/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "GacUICompiler.h" /*********************************************************************** .\GUICPPGEN.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace collections; using namespace stream; using namespace filesystem; using namespace workflow; using namespace workflow::cppcodegen; Ptr PrecompileAndWriteErrors( Ptr resource, IGuiResourcePrecompileCallback* callback, collections::List& errors, const filesystem::FilePath& errorPath) { auto precompiledFolder = resource->Precompile(callback, errors); if (errors.Count() > 0) { List output; GuiResourceError::SortAndLog(errors, output); if (!File(errorPath).WriteAllLines(output, true, BomEncoder::Utf8)) { return nullptr; } } return precompiledFolder; } Ptr WriteWorkflowScript( Ptr precompiledFolder, const filesystem::FilePath& workflowPath) { if (precompiledFolder) { auto compiled = precompiledFolder->GetValueByPath(L"Workflow/InstanceClass").Cast(); WString text; if (compiled->assembly) { auto& codes = compiled->assembly->insAfterCodegen->moduleCodes; FOREACH_INDEXER(WString, code, codeIndex, codes) { text += L"================================(" + itow(codeIndex + 1) + L"/" + itow(codes.Count()) + L")================================\r\n"; text += code + L"\r\n"; } } else { FOREACH_INDEXER(GuiInstanceCompiledWorkflow::ModuleRecord, moduleRecord, codeIndex, compiled->modules) { WString code; { MemoryStream stream; { StreamWriter writer(stream); WfPrint(moduleRecord.module, L"", writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); code = reader.ReadToEnd(); } } text += L"================================(" + itow(codeIndex + 1) + L"/" + itow(compiled->modules.Count()) + L")================================\r\n"; text += code + L"\r\n"; } } if (File(workflowPath).WriteAllText(text)) { return compiled; } } return nullptr; } Ptr WriteCppCodesToFile( Ptr compiled, Ptr cppInput, const filesystem::FilePath& cppFolder) { auto output = GenerateCppFiles(cppInput, compiled->metadata.Obj()); FOREACH_INDEXER(WString, fileName, index, output->cppFiles.Keys()) { WString code = output->cppFiles.Values()[index]; File file(cppFolder / fileName); if (file.Exists()) { WString inputText; BomEncoder::Encoding inputEncoding; bool inputBom; file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom); code = MergeCppFileContent(inputText, code); } if (file.Exists()) { WString inputText; BomEncoder::Encoding inputEncoding; bool inputBom; file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom); if (inputText == code) { continue; } } file.WriteAllText(code, true, BomEncoder::Utf8); } return output; } bool WriteBinaryResource( Ptr resource, bool compress, bool workflow, const filesystem::FilePath& filePath) { auto precompiled = resource->GetFolder(L"Precompiled"); auto folder = precompiled->GetFolder(L"Workflow"); if (!workflow) { precompiled->RemoveFolder(L"Workflow"); } FileStream fileStream(filePath.GetFullPath(), FileStream::WriteOnly); if (fileStream.IsAvailable()) { if (compress) { LzwEncoder encoder; EncoderStream encoderStream(fileStream, encoder); resource->SavePrecompiledBinary(encoderStream); } else { resource->SavePrecompiledBinary(fileStream); } } if (folder && !workflow) { precompiled->AddFolder(L"Workflow", folder); } return fileStream.IsAvailable(); } void WriteEmbeddedBinaryClass(MemoryStream& binaryStream, bool compress, const WString& className, const WString& prefix, StreamWriter& writer) { MemoryStream compressedStream; binaryStream.SeekFromBegin(0); if (compress) { CompressStream(binaryStream, compressedStream); } else { CopyStream(binaryStream, compressedStream); } compressedStream.SeekFromBegin(0); vint lengthBeforeCompressing = (vint)binaryStream.Size(); vint length = (vint)compressedStream.Size(); const vint block = 1024; vint remain = length % block; vint rows = length / block + (remain ? 1 : 0); #define PREFIX writer.WriteString(prefix); PREFIX writer.WriteLine(L"class " + className); PREFIX writer.WriteLine(L"{"); PREFIX writer.WriteLine(L"public:"); PREFIX writer.WriteLine(L"\tstatic const vint parserBufferLength = " + itow(length) + L"; // " + itow(lengthBeforeCompressing) + L" bytes before compressing"); PREFIX writer.WriteLine(L"\tstatic const vint parserBufferBlock = " + itow(block) + L";"); PREFIX writer.WriteLine(L"\tstatic const vint parserBufferRemain = " + itow(remain) + L";"); PREFIX writer.WriteLine(L"\tstatic const vint parserBufferRows = " + itow(rows) + L";"); PREFIX writer.WriteLine(L"\tstatic const char* parserBuffer[" + itow(rows) + L"];"); writer.WriteLine(L""); PREFIX writer.WriteLine(L"\tstatic void ReadToStream(vl::stream::MemoryStream& stream)"); PREFIX writer.WriteLine(L"\t{"); PREFIX writer.WriteLine(L"\t\tDecompressStream(parserBuffer, " + WString(compress ? L"true" : L"false") + L", parserBufferRows, parserBufferBlock, parserBufferRemain, stream);"); PREFIX writer.WriteLine(L"\t}"); PREFIX writer.WriteLine(L"};"); writer.WriteLine(L""); PREFIX writer.WriteLine(L"const char* " + className + L"::parserBuffer[] = {"); char buffer[block]; const wchar_t* hex = L"0123456789ABCDEF"; for (vint i = 0; i < rows; i++) { vint size = i == rows - 1 ? remain : block; compressedStream.Read(buffer, size); PREFIX writer.WriteString(L"\t\""); for (vint j = 0; j < size; j++) { vuint8_t byte = buffer[j]; writer.WriteString(L"\\x"); writer.WriteChar(hex[byte / 16]); writer.WriteChar(hex[byte % 16]); } writer.WriteLine(L"\","); } PREFIX writer.WriteLine(L"\t};"); #undef PREFIX } bool WriteEmbeddedResource(Ptr resource, Ptr cppInput, Ptr cppOutput, bool compress, const filesystem::FilePath& filePath) { WString code; MemoryStream stream; { StreamWriter writer(stream); writer.WriteLine(L"#include \"" + cppOutput->entryFileName + L".h\""); writer.WriteLine(L""); writer.WriteLine(L"namespace vl"); writer.WriteLine(L"{"); writer.WriteLine(L"\tnamespace presentation"); writer.WriteLine(L"\t{"); writer.WriteLine(L"\t\tnamespace user_resource"); writer.WriteLine(L"\t\t{"); writer.WriteLine(L"\t\t\tusing namespace collections;"); writer.WriteLine(L"\t\t\tusing namespace stream;"); writer.WriteLine(L"\t\t\tusing namespace controls;"); writer.WriteLine(L""); { MemoryStream resourceStream; { auto precompiled = resource->GetFolder(L"Precompiled"); auto folder = precompiled->GetFolder(L"Workflow"); precompiled->RemoveFolder(L"Workflow"); resource->SavePrecompiledBinary(resourceStream); precompiled->AddFolder(L"Workflow", folder); } WriteEmbeddedBinaryClass(resourceStream, compress, cppInput->assemblyName + L"ResourceReader", L"\t\t\t", writer); writer.WriteLine(L""); } { writer.WriteLine(L"\t\t\tclass " + cppInput->assemblyName + L"ResourceLoaderPlugin : public Object, public IGuiPlugin"); writer.WriteLine(L"\t\t\t{"); writer.WriteLine(L"\t\t\tpublic:"); writer.WriteLine(L""); writer.WriteLine(L"\t\t\t\tGUI_PLUGIN_NAME(GacGen_" + cppInput->assemblyName + L"ResourceLoader)"); writer.WriteLine(L"\t\t\t\t{"); writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Res_Resource);"); writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Res_TypeResolvers);"); writer.WriteLine(L"#ifndef VCZH_DEBUG_NO_REFLECTION"); writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Instance_Reflection);"); writer.WriteLine(L"\t\t\t\t\tGUI_PLUGIN_DEPEND(GacUI_Compiler_WorkflowTypeResolvers);"); writer.WriteLine(L"#endif"); writer.WriteLine(L"\t\t\t\t}"); writer.WriteLine(L""); writer.WriteLine(L"\t\t\t\tvoid Load()override"); writer.WriteLine(L"\t\t\t\t{"); writer.WriteLine(L"\t\t\t\t\tList errors;"); writer.WriteLine(L"\t\t\t\t\tMemoryStream resourceStream;"); writer.WriteLine(L"\t\t\t\t\t" + cppInput->assemblyName + L"ResourceReader::ReadToStream(resourceStream);"); writer.WriteLine(L"\t\t\t\t\tresourceStream.SeekFromBegin(0);"); writer.WriteLine(L"\t\t\t\t\tauto resource = GuiResource::LoadPrecompiledBinary(resourceStream, errors);"); writer.WriteLine(L"\t\t\t\t\tGetResourceManager()->SetResource(L\"" + cppInput->assemblyName + L"\", resource, GuiResourceUsage::InstanceClass);"); writer.WriteLine(L"\t\t\t\t}"); writer.WriteLine(L""); writer.WriteLine(L"\t\t\t\tvoid Unload()override"); writer.WriteLine(L"\t\t\t\t{"); writer.WriteLine(L"\t\t\t\t}"); writer.WriteLine(L"\t\t\t};"); writer.WriteLine(L"\t\t\tGUI_REGISTER_PLUGIN(" + cppInput->assemblyName + L"ResourceLoaderPlugin)"); } writer.WriteLine(L"\t\t}"); writer.WriteLine(L"\t}"); writer.WriteLine(L"}"); } stream.SeekFromBegin(0); { StreamReader reader(stream); code = reader.ReadToEnd(); } File file(filePath); if (file.Exists()) { WString inputText; BomEncoder::Encoding inputEncoding; bool inputBom; file.ReadAllTextWithEncodingTesting(inputText, inputEncoding, inputBom); if (inputText == code) { return true; } } return file.WriteAllText(code, true, BomEncoder::Utf8); } } } /*********************************************************************** .\GUIINSTANCEHELPERTYPES.CPP ***********************************************************************/ namespace vl { namespace presentation { namespace helper_types { } } #ifndef VCZH_DEBUG_NO_REFLECTION namespace reflection { namespace description { using namespace presentation::helper_types; /*********************************************************************** Type Declaration ***********************************************************************/ GUIREFLECTIONHELPERTYPES_TYPELIST(IMPL_VL_TYPE_INFO) #define _ , BEGIN_STRUCT_MEMBER(SiteValue) STRUCT_MEMBER(row) STRUCT_MEMBER(column) STRUCT_MEMBER(rowSpan) STRUCT_MEMBER(columnSpan) END_STRUCT_MEMBER(SiteValue) #undef _ } } namespace presentation { using namespace reflection::description; using namespace controls; /*********************************************************************** Type Loader ***********************************************************************/ class GuiHelperTypesLoader : public Object, public ITypeLoader { public: void Load(ITypeManager* manager) { GUIREFLECTIONHELPERTYPES_TYPELIST(ADD_TYPE_INFO) } void Unload(ITypeManager* manager) { } }; /*********************************************************************** GuiHelperTypesLoaderPlugin ***********************************************************************/ class GuiHelperTypesLoaderPlugin : public Object, public IGuiPlugin { public: GUI_PLUGIN_NAME(GacUI_Instance_ReflectionHelper) { GUI_PLUGIN_DEPEND(GacUI_Instance_Reflection); } void Load()override { ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new GuiHelperTypesLoader; manager->AddTypeLoader(loader); } } void Unload()override { } }; GUI_REGISTER_PLUGIN(GuiHelperTypesLoaderPlugin) } #endif } /*********************************************************************** .\GUIINSTANCESHAREDSCRIPT.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace parsing::xml; /*********************************************************************** GuiInstanceSharedScript ***********************************************************************/ Ptr GuiInstanceSharedScript::LoadFromXml(Ptr resource, Ptr xml, GuiResourceError::List& errors) { if (xml->rootElement->subNodes.Count() == 1) { if (auto cdata = xml->rootElement->subNodes[0].Cast()) { auto script = MakePtr(); script->language = xml->rootElement->name.value; script->code = cdata->content.value; script->codePosition = { {resource},cdata->codeRange.start }; script->codePosition.column += 9; // rootElement->codeRange.start }, L"Script should be contained in a CDATA section.")); return nullptr; } Ptr GuiInstanceSharedScript::SaveToXml() { auto cdata = MakePtr(); cdata->content.value = code; auto xml = MakePtr(); xml->name.value = language; xml->subNodes.Add(cdata); return xml; } } } /*********************************************************************** .\GUIINSTANCEREPRESENTATION.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace collections; using namespace parsing; using namespace parsing::xml; using namespace templates; using namespace stream; /*********************************************************************** GuiValueRepr ***********************************************************************/ void GuiValueRepr::CloneBody(Ptr repr) { repr->fromStyle = fromStyle; repr->tagPosition = tagPosition; } /*********************************************************************** GuiTextRepr ***********************************************************************/ Ptr GuiTextRepr::Clone() { auto repr = MakePtr(); GuiValueRepr::CloneBody(repr); repr->text = text; return repr; } void GuiTextRepr::FillXml(Ptr xml) { if (!fromStyle) { auto xmlText = MakePtr(); xmlText->content.value = text; xml->subNodes.Add(xmlText); } } /*********************************************************************** GuiAttSetterRepr ***********************************************************************/ void GuiAttSetterRepr::CloneBody(Ptr repr) { GuiValueRepr::CloneBody(repr); FOREACH_INDEXER(GlobalStringKey, name, index, setters.Keys()) { auto src = setters.Values()[index]; auto dst = MakePtr(); dst->binding = src->binding; dst->attPosition = src->attPosition; FOREACH(Ptr, value, src->values) { dst->values.Add(value->Clone()); } repr->setters.Add(name, dst); } FOREACH_INDEXER(GlobalStringKey, name, index, eventHandlers.Keys()) { auto src = eventHandlers.Values()[index]; auto dst = MakePtr(); dst->binding = src->binding; dst->value = src->value; dst->fromStyle = src->fromStyle; dst->attPosition = src->attPosition; dst->valuePosition = src->valuePosition; repr->eventHandlers.Add(name, dst); } FOREACH_INDEXER(GlobalStringKey, name, index, environmentVariables.Keys()) { auto src = environmentVariables.Values()[index]; auto dst = MakePtr(); dst->value = src->value; dst->fromStyle = src->fromStyle; dst->attPosition = src->attPosition; dst->valuePosition = src->valuePosition; repr->environmentVariables.Add(name, dst); } repr->instanceName = instanceName; } Ptr GuiAttSetterRepr::Clone() { auto repr = MakePtr(); GuiAttSetterRepr::CloneBody(repr); repr->fromStyle = fromStyle; return repr; } void GuiAttSetterRepr::FillXml(Ptr xml) { if (!fromStyle) { if (instanceName != GlobalStringKey::Empty) { auto attName = MakePtr(); attName->name.value = L"ref.Name"; attName->value.value = instanceName.ToString(); xml->attributes.Add(attName); } for (vint i = 0; i < setters.Count(); i++) { auto key = setters.Keys()[i]; auto value = setters.Values()[i]; if (key == GlobalStringKey::Empty) { FOREACH(Ptr, repr, value->values) { repr->FillXml(xml); } } else if (From(value->values).Any([](Ptr value) {return !value->fromStyle; })) { bool containsElement = From(value->values) .Any([](Ptr value) { return !value->fromStyle && !value.Cast(); }); if (containsElement) { auto xmlProp = MakePtr(); xmlProp->name.value = L"att." + key.ToString(); if (value->binding != GlobalStringKey::Empty) { xmlProp->name.value += L"-" + value->binding.ToString(); } FOREACH(Ptr, repr, value->values) { if (!repr.Cast()) { repr->FillXml(xmlProp); } } xml->subNodes.Add(xmlProp); } else { FOREACH(Ptr, repr, value->values) { if (auto textRepr = repr.Cast()) { if (!textRepr->fromStyle) { auto att = MakePtr(); att->name.value = key.ToString(); if (value->binding != GlobalStringKey::Empty) { att->name.value += L"-" + value->binding.ToString(); } att->value.value = textRepr->text; xml->attributes.Add(att); break; } } } } } } for (vint i = 0; i < eventHandlers.Count(); i++) { auto key = eventHandlers.Keys()[i]; auto value = eventHandlers.Values()[i]; if (!value->fromStyle) { auto xmlEvent = MakePtr(); xmlEvent->name.value = L"ev." + key.ToString(); if (value->binding != GlobalStringKey::Empty) { xmlEvent->name.value += L"-" + value->binding.ToString(); } xml->subNodes.Add(xmlEvent); auto xmlText = MakePtr(); xmlText->content.value = value->value; xmlEvent->subNodes.Add(xmlText); } } for (vint i = 0; i < environmentVariables.Count(); i++) { auto key = environmentVariables.Keys()[i]; auto value = environmentVariables.Values()[i]; if (!value->fromStyle) { auto xmlEnvVar = MakePtr(); xmlEnvVar->name.value = L"env." + key.ToString(); xml->subNodes.Add(xmlEnvVar); auto xmlText = MakePtr(); xmlText->content.value = value->value; xmlEnvVar->subNodes.Add(xmlText); } } } } /*********************************************************************** GuiConstructorRepr ***********************************************************************/ Ptr GuiConstructorRepr::Clone() { auto repr = MakePtr(); GuiAttSetterRepr::CloneBody(repr); repr->fromStyle = fromStyle; repr->typeNamespace = typeNamespace; repr->typeName = typeName; repr->styleName = styleName; return repr; } void GuiConstructorRepr::FillXml(Ptr xml) { if (!fromStyle) { auto xmlCtor = MakePtr(); if (typeNamespace == GlobalStringKey::Empty) { xmlCtor->name.value = typeName.ToString(); } else { xmlCtor->name.value = typeNamespace.ToString() + L":" + typeName.ToString(); } if (styleName) { auto attStyle = MakePtr(); attStyle->name.value = L"ref.Style"; attStyle->value.value = styleName.Value(); xml->attributes.Add(attStyle); } GuiAttSetterRepr::FillXml(xmlCtor); xml->subNodes.Add(xmlCtor); } } /*********************************************************************** GuiInstanceContext ***********************************************************************/ void GuiInstanceContext::CollectDefaultAttributes(Ptr resource, GuiAttSetterRepr::ValueList& values, Ptr xml, GuiResourceError::List& errors) { if (auto parser = GetParserManager()->GetParser(L"INSTANCE-ELEMENT-NAME")) { // test if there is only one text value in the xml if (xml->subNodes.Count() == 1) { if (Ptr text = xml->subNodes[0].Cast()) { Ptr value = new GuiTextRepr; value->text = text->content.value; value->tagPosition = { {resource},text->content.codeRange.start }; values.Add(value); } else if (Ptr text = xml->subNodes[0].Cast()) { Ptr value = new GuiTextRepr; value->text = text->content.value; value->tagPosition = { {resource},text->content.codeRange.start }; value->tagPosition.column += 9; // , element, XmlGetElements(xml)) { if(auto name = parser->Parse({ resource }, element->name.value, element->codeRange.start, errors)) { if (name->IsCtorName()) { // collect constructor values in the default attribute setter auto ctor = LoadCtor(resource, element, errors); if (ctor) { values.Add(ctor); } } else if (!name->IsPropertyElementName() && !name->IsEventElementName()) { errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Unknown element name: \"" + element->name.value + L"\".")); } } } } } void GuiInstanceContext::CollectAttributes(Ptr resource, GuiAttSetterRepr::SetteValuerMap& setters, Ptr xml, GuiResourceError::List& errors) { if (auto parser = GetParserManager()->GetParser(L"INSTANCE-ELEMENT-NAME")) { Ptr defaultValue = new GuiAttSetterRepr::SetterValue; // collect default attributes CollectDefaultAttributes(resource, defaultValue->values, xml, errors); if (defaultValue->values.Count() > 0) { setters.Add(GlobalStringKey::Empty, defaultValue); } // collect values FOREACH(Ptr, element, XmlGetElements(xml)) { if(auto name = parser->Parse({ resource }, element->name.value, element->name.codeRange.start, errors)) { if (name->IsPropertyElementName()) { // collect a value as a new attribute setter if (setters.Keys().Contains(GlobalStringKey::Get(name->name))) { errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Duplicated property \"" + name->name + L"\".")); } else { Ptr sv = new GuiAttSetterRepr::SetterValue; sv->binding = GlobalStringKey::Get(name->binding); sv->attPosition = { {resource},element->codeRange.start }; if (name->binding == L"set") { // if the binding is "set", it means that this element is a complete setter element Ptr setter = new GuiAttSetterRepr; FillAttSetter(resource, setter, element, errors); sv->values.Add(setter); } else { // if the binding is not "set", then this is a single-value attribute or a colection attribute // fill all data into this attribute CollectDefaultAttributes(resource, sv->values, element, errors); } if (sv->values.Count() > 0) { setters.Add(GlobalStringKey::Get(name->name), sv); } } } } } } } void GuiInstanceContext::CollectEvents(Ptr resource, GuiAttSetterRepr::EventHandlerMap& eventHandlers, Ptr xml, GuiResourceError::List& errors) { if (auto parser = GetParserManager()->GetParser(L"INSTANCE-ELEMENT-NAME")) { // collect values FOREACH(Ptr, element, XmlGetElements(xml)) { if(auto name = parser->Parse({ resource }, element->name.value, element->name.codeRange.start, errors)) { if (name->IsEventElementName()) { // collect a value as an event setter if (eventHandlers.Keys().Contains(GlobalStringKey::Get(name->name))) { errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Duplicated event \"" + name->name + L"\".")); } else { // test if there is only one text value in the xml if (element->subNodes.Count() == 1) { if (Ptr text = element->subNodes[0].Cast()) { auto value = MakePtr(); value->binding = GlobalStringKey::Get(name->binding); value->value = text->content.value; value->attPosition = { {resource},element->codeRange.start }; value->valuePosition = { {resource},text->content.codeRange.start }; eventHandlers.Add(GlobalStringKey::Get(name->name), value); if (text->content.codeRange.start.row != text->content.codeRange.end.row) { errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Multiple lines script should be contained in a CDATA section.")); } goto EVENT_SUCCESS; } else if (Ptr text = element->subNodes[0].Cast()) { auto value = MakePtr(); value->binding = GlobalStringKey::Get(name->binding); value->value = text->content.value; value->attPosition = { {resource},element->codeRange.start }; value->valuePosition = { {resource},text->content.codeRange.start }; value->valuePosition.column += 9; // name), value); } goto EVENT_SUCCESS; } errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"Event script should be contained in a text or CDATA section.")); EVENT_SUCCESS:; } } } } } } void GuiInstanceContext::FillAttSetter(Ptr resource, Ptr setter, Ptr xml, GuiResourceError::List& errors) { if (auto parser = GetParserManager()->GetParser(L"INSTANCE-ELEMENT-NAME")) { setter->tagPosition = { {resource},xml->codeRange.start }; // collect attributes as setters FOREACH(Ptr, att, xml->attributes) { if(auto name = parser->Parse({ resource }, att->name.value, att->name.codeRange.start, errors)) { if (name->IsReferenceAttributeName()) { // collect reference attributes if (name->name == L"Name") { setter->instanceName = GlobalStringKey::Get(att->value.value); } } else if (name->IsEnvironmentAttributeName()) { // collect environment variables if (setter->environmentVariables.Keys().Contains(GlobalStringKey::Get(name->name))) { errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated environment variable \"" + name->name + L"\".")); } else { auto value = MakePtr(); value->value = att->value.value; value->attPosition = { {resource},att->codeRange.start }; value->valuePosition = { {resource},att->value.codeRange.start }; value->valuePosition.column += 1; setter->environmentVariables.Add(GlobalStringKey::Get(name->name), value); } } else if (name->IsPropertyAttributeName()) { // collect attributes setters if (setter->setters.Keys().Contains(GlobalStringKey::Get(name->name))) { errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated property \"" + name->name + L"\".")); } else { auto sv = MakePtr(); sv->binding = GlobalStringKey::Get(name->binding); sv->attPosition = { {resource},att->codeRange.start }; setter->setters.Add(GlobalStringKey::Get(name->name), sv); Ptr value = new GuiTextRepr; value->text = att->value.value; value->tagPosition = { {resource},att->value.codeRange.start }; value->tagPosition.column += 1; sv->values.Add(value); } } else if (name->IsEventAttributeName()) { // collect event setters if (setter->eventHandlers.Keys().Contains(GlobalStringKey::Get(name->name))) { errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Duplicated event \"" + name->name + L"\".")); } else { auto value = MakePtr(); value->binding = GlobalStringKey::Get(name->binding); value->value = att->value.value; value->attPosition = { {resource},att->codeRange.start }; value->valuePosition = { {resource},att->value.codeRange.start }; value->valuePosition.column += 1; setter->eventHandlers.Add(GlobalStringKey::Get(name->name), value); } } else { errors.Add(GuiResourceError({ {resource},att->name.codeRange.start }, L"Unknown attribute name: \"" + att->name.value + L"\".")); } } } // collect attributes and events CollectAttributes(resource, setter->setters, xml, errors); CollectEvents(resource, setter->eventHandlers, xml, errors); } } Ptr GuiInstanceContext::LoadCtor(Ptr resource, Ptr xml, GuiResourceError::List& errors) { if (auto parser = GetParserManager()->GetParser(L"INSTANCE-ELEMENT-NAME")) { if(auto ctorName = parser->Parse({ resource }, xml->name.value, xml->name.codeRange.start, errors)) { if (ctorName->IsCtorName()) { Ptr ctor = new GuiConstructorRepr; ctor->typeNamespace = GlobalStringKey::Get(ctorName->namespaceName); ctor->typeName = GlobalStringKey::Get(ctorName->name); // collect attributes as setters FOREACH(Ptr, att, xml->attributes) { if(auto attName = parser->Parse({ resource }, att->name.value, att->name.codeRange.start, errors)) { if (attName->IsReferenceAttributeName()) { if (attName->name == L"Style") { ctor->styleName = att->value.value; } } } } FillAttSetter(resource, ctor, xml, errors); return ctor; } else { errors.Add(GuiResourceError({ {resource},xml->codeRange.start }, L"Wrong constructor name \"" + xml->name.value + L"\".")); } } } return 0; } Ptr GuiInstanceContext::LoadFromXml(Ptr resource, Ptr xml, GuiResourceError::List& errors) { Ptr context = new GuiInstanceContext; context->tagPosition = { {resource},xml->rootElement->codeRange.start }; if (xml->rootElement->name.value == L"Instance") { if (auto codeBehindAttr = XmlGetAttribute(xml->rootElement, L"ref.CodeBehind")) { context->codeBehind = codeBehindAttr->value.value == L"true"; } // load type name if (auto classAttr = XmlGetAttribute(xml->rootElement, L"ref.Class")) { context->className = classAttr->value.value; context->classPosition = { {resource},classAttr->codeRange.start }; } // load style names if (auto styleAttr = XmlGetAttribute(xml->rootElement, L"ref.Styles")) { SplitBySemicolon(styleAttr->value.value, context->stylePaths); context->stylePosition = { {resource},styleAttr->codeRange.start }; } // load namespaces List> namespaceAttributes; CopyFrom(namespaceAttributes, xml->rootElement->attributes); if (!XmlGetAttribute(xml->rootElement, L"xmlns")) { Ptr att = new XmlAttribute; att->name.value = L"xmlns"; att->value.value = L"presentation::controls::Gui*;" L"presentation::elements::Gui*Element;" L"presentation::compositions::Gui*Composition;" L"presentation::compositions::Gui*;" L"presentation::templates::Gui*;" L"system::*;" L"system::reflection::*;" L"presentation::*;" L"presentation::Gui*;" L"presentation::controls::*;" L"presentation::controls::list::*;" L"presentation::controls::tree::*;" L"presentation::elements::*;" L"presentation::elements::Gui*;" L"presentation::elements::text::*;" L"presentation::compositions::*;" L"presentation::templates::*;" L"presentation::theme::*"; namespaceAttributes.Add(att); } FOREACH(Ptr, att, namespaceAttributes) { // check if the attribute defines a namespace WString attName = att->name.value; if (attName.Length() >= 5 && attName.Left(5) == L"xmlns") { GlobalStringKey ns; if (attName.Length() > 6) { if (attName.Left(6) == L"xmlns:") { ns = GlobalStringKey::Get(attName.Sub(6, attName.Length() - 6)); } else { continue; } } // create a data structure for the namespace Ptr info; vint index = context->namespaces.Keys().IndexOf(ns); if (index == -1) { info = new NamespaceInfo; info->name = ns; info->attPosition = { {resource},att->codeRange.start }; context->namespaces.Add(ns, info); } else { info = context->namespaces.Values()[index]; } // extract all patterns in the namespace, split the value by ';' List patterns; SplitBySemicolon(att->value.value, patterns); FOREACH(WString, pattern, patterns) { // add the pattern to the namespace Ptr ns = new GuiInstanceNamespace; Pair star = INVLOC.FindFirst(pattern, L"*", Locale::None); if (star.key == -1) { ns->prefix = pattern; } else { ns->prefix = pattern.Sub(0, star.key); ns->postfix = pattern.Sub(star.key + star.value, pattern.Length() - star.key - star.value); } info->namespaces.Add(ns); } } } // load instance FOREACH(Ptr, element, XmlGetElements(xml->rootElement)) { if (element->name.value == L"ref.Parameter") { auto attName = XmlGetAttribute(element, L"Name"); auto attClass = XmlGetAttribute(element, L"Class"); if (attName && attClass) { auto parameter = MakePtr(); parameter->name = GlobalStringKey::Get(attName->value.value); parameter->className = GlobalStringKey::Get(attClass->value.value); parameter->tagPosition = { {resource},element->codeRange.start }; parameter->classPosition = { {resource},attClass->value.codeRange.start }; parameter->classPosition.column += 1; context->parameters.Add(parameter); } else { errors.Add(GuiResourceError({ {resource},element->codeRange.start }, L"ref.Parameter requires the following attributes existing at the same time: Name, Class.")); } } #define COLLECT_SCRIPT(NAME, SCRIPT, POSITION)\ (element->name.value == L"ref." #NAME)\ {\ if (element->subNodes.Count() == 1)\ {\ if (auto cdata = element->subNodes[0].Cast())\ {\ context->SCRIPT = cdata->content.value;\ context->POSITION = { {resource},cdata->codeRange.start };\ context->POSITION.column += 9; /* codeRange.start }, L"Script should be contained in a CDATA section."));\ NAME##_SCRIPT_SUCCESS:;\ }\ else if COLLECT_SCRIPT(Members, memberScript, memberPosition) else if COLLECT_SCRIPT(Ctor, ctorScript, ctorPosition) else if COLLECT_SCRIPT(Dtor, dtorScript, dtorPosition) #undef COLLECT_SCRIPT else if (!context->instance) { context->instance = LoadCtor(resource, element, errors); } } } else { errors.Add(GuiResourceError({ {resource},xml->rootElement->codeRange.start }, L"The root element of instance should be \"Instance\".")); } return context->instance ? context : nullptr; } Ptr GuiInstanceContext::SaveToXml() { auto xmlInstance = MakePtr(); xmlInstance->name.value = L"Instance"; { auto attCodeBehind = MakePtr(); attCodeBehind->name.value = L"ref.CodeBehind"; attCodeBehind->value.value = codeBehind ? L"true" : L"false"; xmlInstance->attributes.Add(attCodeBehind); } auto attClass = MakePtr(); attClass->name.value = L"ref.Class"; attClass->value.value = className; xmlInstance->attributes.Add(attClass); for (vint i = 0; i < namespaces.Count(); i++) { auto key = namespaces.Keys()[i]; auto value = namespaces.Values()[i]; auto xmlns = MakePtr(); xmlns->name.value = L"xmlns"; if (key != GlobalStringKey::Empty) { xmlns->name.value += L":" + key.ToString(); } xmlInstance->attributes.Add(xmlns); for (vint j = 0; j < value->namespaces.Count(); j++) { auto ns = value->namespaces[j]; if (j != 0) { xmlns->value.value += L";"; } xmlns->value.value += ns->prefix + L"*" + ns->postfix; } } FOREACH(Ptr, parameter, parameters) { auto xmlParameter = MakePtr(); xmlParameter->name.value = L"ref.Parameter"; xmlInstance->subNodes.Add(xmlParameter); auto attName = MakePtr(); attName->name.value = L"Name"; attName->value.value = parameter->name.ToString(); xmlParameter->attributes.Add(attName); auto attClass = MakePtr(); attClass->name.value = L"Class"; attClass->value.value = parameter->className.ToString(); xmlParameter->attributes.Add(attClass); } #define SERIALIZE_SCRIPT(NAME, SCRIPT)\ if (SCRIPT != L"")\ {\ auto xmlScript = MakePtr();\ xmlScript->name.value = L"ref." #NAME;\ xmlInstance->subNodes.Add(xmlScript);\ auto text = MakePtr();\ text->content.value = SCRIPT;\ xmlScript->subNodes.Add(text);\ }\ SERIALIZE_SCRIPT(Members, memberScript) SERIALIZE_SCRIPT(Ctpr, ctorScript) SERIALIZE_SCRIPT(Dtor, dtorScript) #undef SERIALIZE_SCRIPT if (stylePaths.Count() > 0) { auto attStyles = MakePtr(); attStyles->name.value = L"ref.Styles"; xmlInstance->attributes.Add(attStyles); for (vint j = 0; j < stylePaths.Count(); j++) { if (j != 0) { attStyles->value.value += L";"; } attStyles->value.value += stylePaths[j]; } } instance->FillXml(xmlInstance); auto doc = MakePtr(); doc->rootElement = xmlInstance; return doc; } bool GuiInstanceContext::ApplyStyles(Ptr resource, Ptr resolver, GuiResourceError::List& errors) { if (!appliedStyles) { appliedStyles = true; List> styles; FOREACH(WString, uri, stylePaths) { WString protocol, path; if (IsResourceUrl(uri, protocol, path)) { if (auto styleContext = resolver->ResolveResource(protocol, path).Cast()) { CopyFrom(styles, styleContext->styles, true); } else { errors.Add(GuiResourceError({ resource }, stylePosition, L"Failed to find the style referred in attribute \"ref.Styles\": \"" + uri + L"\".")); } } else { errors.Add(GuiResourceError({ resource }, stylePosition, L"Invalid path in attribute \"ref.Styles\": \"" + uri + L"\".")); } } FOREACH(Ptr, style, styles) { List> output; ExecuteQuery(style->query, this, output); FOREACH(Ptr, ctor, output) { ApplyStyle(style, ctor); } } return true; } else { return false; } } /*********************************************************************** GuiInstanceStyle ***********************************************************************/ namespace visitors { class SetStyleMarkVisitor : public Object, public GuiValueRepr::IVisitor { public: void Visit(GuiTextRepr* repr)override { repr->fromStyle = true; } void Visit(GuiAttSetterRepr* repr)override { repr->fromStyle = true; FOREACH(Ptr, value, repr->setters.Values()) { FOREACH(Ptr, subValue, value->values) { subValue->Accept(this); } } FOREACH(Ptr, value, repr->eventHandlers.Values()) { value->fromStyle = true; } FOREACH(Ptr, value, repr->environmentVariables.Values()) { value->fromStyle = true; } } void Visit(GuiConstructorRepr* repr)override { Visit((GuiAttSetterRepr*)repr); } }; } using namespace visitors; Ptr GuiInstanceStyle::LoadFromXml(Ptr resource, Ptr xml, GuiResourceError::List& errors) { auto style = MakePtr(); if (auto pathAttr = XmlGetAttribute(xml, L"ref.Path")) { auto position = pathAttr->value.codeRange.start; position.column += 1; auto parser = GetParserManager()->GetParser(L"INSTANCE-QUERY"); auto query = parser->Parse({ resource }, pathAttr->value.value, position, errors); if (!query) return nullptr; style->query = query; } else { errors.Add(GuiResourceError({ {resource},xml->codeRange.start }, L"Missing attribute \"ref.Path\" in