/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "GacUICompiler.h" /*********************************************************************** 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: void Load()override { ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new GuiHelperTypesLoader; manager->AddTypeLoader(loader); } } void AfterLoad()override { } void Unload()override { } }; GUI_REGISTER_PLUGIN(GuiHelperTypesLoaderPlugin) } #endif } /*********************************************************************** GUIINSTANCELOADER.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace collections; using namespace parsing; using namespace parsing::xml; using namespace parsing::tabling; using namespace controls; using namespace regex; using namespace reflection::description; using namespace stream; using namespace workflow; using namespace workflow::analyzer; using namespace workflow::typeimpl; /*********************************************************************** GuiInstancePropertyInfo ***********************************************************************/ Ptr GuiInstancePropertyInfo::Unsupported() { return new GuiInstancePropertyInfo; } Ptr GuiInstancePropertyInfo::Assign(Ptr typeInfo) { auto info = MakePtr(); info->support = SupportAssign; if (typeInfo) info->acceptableTypes.Add(typeInfo); return info; } Ptr GuiInstancePropertyInfo::AssignWithParent(Ptr typeInfo) { auto info = Assign(typeInfo); info->mergability = MergeWithParent; return info; } Ptr GuiInstancePropertyInfo::Collection(Ptr typeInfo) { auto info = Assign(typeInfo); info->support = SupportCollection; return info; } Ptr GuiInstancePropertyInfo::CollectionWithParent(Ptr typeInfo) { auto info = Collection(typeInfo); info->mergability = MergeWithParent; return info; } Ptr GuiInstancePropertyInfo::Set(Ptr typeInfo) { auto info = MakePtr(); info->support = SupportSet; if (typeInfo) info->acceptableTypes.Add(typeInfo); return info; } Ptr GuiInstancePropertyInfo::Array(Ptr typeInfo) { auto info = MakePtr(); info->support = SupportArray; if (typeInfo) info->acceptableTypes.Add(typeInfo); return info; } /*********************************************************************** IGuiInstanceLoader ***********************************************************************/ void IGuiInstanceLoader::ClearReflectionCache() { } void IGuiInstanceLoader::GetRequiredPropertyNames(const TypeInfo& typeInfo, collections::List& propertyNames) { } void IGuiInstanceLoader::GetPropertyNames(const TypeInfo& typeInfo, collections::List& propertyNames) { } void IGuiInstanceLoader::GetPairedProperties(const PropertyInfo& propertyInfo, collections::List& propertyNames) { } Ptr IGuiInstanceLoader::GetPropertyType(const PropertyInfo& propertyInfo) { return nullptr; } bool IGuiInstanceLoader::CanCreate(const TypeInfo& typeInfo) { return false; } Ptr IGuiInstanceLoader::CreateRootInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, ArgumentMap& arguments, GuiResourceError::List& errors) { CHECK_FAIL(L"IGuiInstanceLoader::CreateControlTemplateArgument(types::ResolvingResult&, const TypeInfo&, Ptr, collections::List&)#This function is not implemented."); } Ptr IGuiInstanceLoader::InitializeRootInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceError::List& errors) { return nullptr; } Ptr IGuiInstanceLoader::CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors) { CHECK_FAIL(L"IGuiInstanceLoader::CreateInstance(types::ResolvingResult&, const TypeInfo&, GlobalStringKey, ArgumentMap&, collections::List&)#This function is not implemented."); } Ptr IGuiInstanceLoader::AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors) { CHECK_FAIL(L"IGuiInstanceLoader::AssignParameters(types::ResolvingResult&, const TypeInfo&, GlobalStringKey, ArgumentMap&, collections::List&)#This function is not implemented."); } Ptr IGuiInstanceLoader::GetParameter(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const PropertyInfo& propertyInfo, GlobalStringKey variableName, GuiResourceTextPos attPosition, GuiResourceError::List& errors) { CHECK_FAIL(L"IGuiInstanceLoader::GetParameter(types::ResolvingResult&, const PropertyInfo&, GlobalStringKey, collections::List&)#This function is not implemented."); } /*********************************************************************** GuiInstanceContext::ElementName Parser ***********************************************************************/ class GuiInstanceContextElementNameParser : public Object, public IGuiParser { typedef GuiInstanceContext::ElementName ElementName; public: Regex regexElementName; GuiInstanceContextElementNameParser() :regexElementName(L"(([a-zA-Z_]/w*):)?(([a-zA-Z_]/w*).)?([a-zA-Z_]/w*)(-([a-zA-Z_]/w*))?") { } Ptr ParseInternal(const WString& text, collections::List>& errors)override { Ptr match = regexElementName.MatchHead(text); if (!match || match->Result().Length() != text.Length()) { errors.Add(MakePtr(L"Failed to parse an element name \"" + text + L"\".")); return nullptr; } Ptr elementName = new ElementName; if (match->Groups().Keys().Contains(L"namespaceName")) { elementName->namespaceName = match->Groups()[L"namespaceName"][0].Value(); } if (match->Groups().Keys().Contains(L"category")) { elementName->category = match->Groups()[L"category"][0].Value(); } if (match->Groups().Keys().Contains(L"name")) { elementName->name = match->Groups()[L"name"][0].Value(); } if (match->Groups().Keys().Contains(L"binding")) { elementName->binding = match->Groups()[L"binding"][0].Value(); } return elementName; } }; /*********************************************************************** GuiDefaultInstanceLoader ***********************************************************************/ #define CTOR_PARAM_PREFIX\ static const wchar_t Prefix[] = L"";\ static const vint PrefixLength = (vint)sizeof(Prefix) / sizeof(*Prefix) - 1;\ #define CTOR_PARAM_NAME(NAME) (NAME).Right((NAME).Length() - PrefixLength) class GuiDefaultInstanceLoader : public Object, public IGuiInstanceLoader { protected: typedef Tuple FieldKey; typedef Tuple, IPropertyInfo*> PropertyType; Dictionary propertyTypes; Dictionary defaultConstructors; Dictionary instanceConstructors; public: IMethodInfo* GetDefaultConstructor(ITypeDescriptor* typeDescriptor) { IMethodInfo* ctor = nullptr; vint index = defaultConstructors.Keys().IndexOf(typeDescriptor); if (index == -1) { if (auto ctors = typeDescriptor->GetConstructorGroup()) { vint count = ctors->GetMethodCount(); for (vint i = 0; i < count; i++) { IMethodInfo* method = ctors->GetMethod(i); if (method->GetParameterCount() == 0) { ctor = method; break; } } } defaultConstructors.Add(typeDescriptor, ctor); } else { ctor = defaultConstructors.Values()[index]; } return ctor; } IMethodInfo* GetInstanceConstructor(ITypeDescriptor* typeDescriptor) { CTOR_PARAM_PREFIX IMethodInfo* ctor = nullptr; vint index = instanceConstructors.Keys().IndexOf(typeDescriptor); if (index == -1) { if (dynamic_cast(typeDescriptor)) { if (auto group = typeDescriptor->GetConstructorGroup()) { if (group->GetMethodCount() == 1) { auto method = group->GetMethod(0); vint count = method->GetParameterCount(); for (vint i = 0; i < count; i++) { const auto& name = method->GetParameter(i)->GetName(); if (name.Length() <= PrefixLength || name.Left(PrefixLength) != Prefix) { goto FINISHED; } if (!typeDescriptor->GetPropertyByName(CTOR_PARAM_NAME(name), false)) { goto FINISHED; } } ctor = method; } } } FINISHED: instanceConstructors.Add(typeDescriptor, ctor); } else { ctor = instanceConstructors.Values()[index]; } return ctor; } GlobalStringKey GetTypeName()override { return GlobalStringKey::Empty; } void ClearReflectionCache()override { propertyTypes.Clear(); defaultConstructors.Clear(); instanceConstructors.Clear(); } //*********************************************************************************** ITypeInfo* ProcessGenericType(ITypeInfo* propType, bool& readableList, bool& writableList, bool& collectionType) { readableList = false; writableList = false; collectionType = false; if (propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetElementType()->GetDecorator() == ITypeInfo::Generic) { auto genericType = propType->GetElementType(); if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { readableList = true; writableList = true; collectionType = true; return genericType->GetGenericArgument(0); } else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { collectionType = true; return genericType->GetGenericArgument(0); } else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { readableList = true; collectionType = true; return genericType->GetGenericArgument(0); } else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { readableList = true; collectionType = true; return genericType->GetGenericArgument(0); } else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { collectionType = true; return nullptr; } else if (genericType->GetTypeDescriptor() == description::GetTypeDescriptor()) { collectionType = true; return nullptr; } } return propType; } ITypeInfo* GetPropertyReflectionTypeInfo(const PropertyInfo& propertyInfo, GuiInstancePropertyInfo::Support& support) { support = GuiInstancePropertyInfo::NotSupport; IPropertyInfo* prop = propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(propertyInfo.propertyName.ToString(), true); if (prop) { ITypeInfo* propType = prop->GetReturn(); bool readableList = false; bool writableList = false; bool collectionType = false; auto propValueType = ProcessGenericType(propType, readableList, writableList, collectionType); if (prop->IsWritable()) { if (collectionType) { if (readableList) { support = GuiInstancePropertyInfo::SupportArray; return propValueType; } } else { support = GuiInstancePropertyInfo::SupportAssign; return propValueType; } } else if (prop->IsReadable()) { if (collectionType) { if (writableList) { support = GuiInstancePropertyInfo::SupportCollection; return propValueType; } } else { if (propType->GetDecorator() == ITypeInfo::SharedPtr || propType->GetDecorator() == ITypeInfo::RawPtr) { if (propType->GetElementType()->GetDecorator() != ITypeInfo::Generic) { support = GuiInstancePropertyInfo::SupportSet; return propValueType; } } } } } return nullptr; } void CollectPropertyNames(const TypeInfo& typeInfo, ITypeDescriptor* typeDescriptor, collections::List& propertyNames) { vint propertyCount = typeDescriptor->GetPropertyCount(); for (vint i = 0; i < propertyCount; i++) { GlobalStringKey propertyName = GlobalStringKey::Get(typeDescriptor->GetProperty(i)->GetName()); if (!propertyNames.Contains(propertyName)) { auto info = GetPropertyType(PropertyInfo(typeInfo, propertyName)); if (info && info->support != GuiInstancePropertyInfo::NotSupport) { propertyNames.Add(propertyName); } } } vint parentCount = typeDescriptor->GetBaseTypeDescriptorCount(); for (vint i = 0; i < parentCount; i++) { CollectPropertyNames(typeInfo, typeDescriptor->GetBaseTypeDescriptor(i), propertyNames); } } //*********************************************************************************** void GetRequiredPropertyNames(const TypeInfo& typeInfo, collections::List& propertyNames)override { if (CanCreate(typeInfo)) { CTOR_PARAM_PREFIX if (auto ctor = GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor())) { vint count = ctor->GetParameterCount(); for (vint i = 0; i < count; i++) { const auto& name = ctor->GetParameter(i)->GetName(); propertyNames.Add(GlobalStringKey::Get(CTOR_PARAM_NAME(name))); } } } } void GetPropertyNames(const TypeInfo& typeInfo, collections::List& propertyNames)override { GetRequiredPropertyNames(typeInfo, propertyNames); CollectPropertyNames(typeInfo, typeInfo.typeInfo->GetTypeDescriptor(), propertyNames); } PropertyType GetPropertyTypeCached(const PropertyInfo& propertyInfo) { CTOR_PARAM_PREFIX FieldKey key(propertyInfo.typeInfo.typeInfo->GetTypeDescriptor(), propertyInfo.propertyName); vint index = propertyTypes.Keys().IndexOf(key); if (index == -1) { GuiInstancePropertyInfo::Support support = GuiInstancePropertyInfo::NotSupport; if (ITypeInfo* propType = GetPropertyReflectionTypeInfo(propertyInfo, support)) { Ptr result = new GuiInstancePropertyInfo; result->support = support; result->acceptableTypes.Add(CopyTypeInfo(propType)); if (auto ctor = GetInstanceConstructor(propertyInfo.typeInfo.typeInfo->GetTypeDescriptor())) { vint count = ctor->GetParameterCount(); for (vint i = 0; i < count; i++) { const auto& name = ctor->GetParameter(i)->GetName(); if (CTOR_PARAM_NAME(name) == propertyInfo.propertyName.ToString()) { result->usage = GuiInstancePropertyInfo::ConstructorArgument; result->bindability = GuiInstancePropertyInfo::Bindable; } } } IPropertyInfo* prop = propertyInfo.typeInfo.typeInfo->GetTypeDescriptor()->GetPropertyByName(propertyInfo.propertyName.ToString(), true); PropertyType value(result, prop); propertyTypes.Add(key, value); return value; } else { PropertyType value(GuiInstancePropertyInfo::Unsupported(), 0); propertyTypes.Add(key, value); return value; } } else { return propertyTypes.Values()[index]; } } Ptr GetPropertyType(const PropertyInfo& propertyInfo)override { return GetPropertyTypeCached(propertyInfo).f0; } //*********************************************************************************** bool CanCreate(const TypeInfo& typeInfo)override { return GetDefaultConstructor(typeInfo.typeInfo->GetTypeDescriptor()) != nullptr || GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor()) != nullptr; } Ptr CreateInstance(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override { CTOR_PARAM_PREFIX auto defaultCtor = GetDefaultConstructor(typeInfo.typeInfo->GetTypeDescriptor()); auto instanceCtor = GetInstanceConstructor(typeInfo.typeInfo->GetTypeDescriptor()); auto create = MakePtr(); if (defaultCtor) { create->type = GetTypeFromTypeInfo(defaultCtor->GetReturn()); } else { create->type = GetTypeFromTypeInfo(instanceCtor->GetReturn()); vint count = instanceCtor->GetParameterCount(); for (vint i = 0; i < count; i++) { const auto& name = instanceCtor->GetParameter(i)->GetName(); auto key = GlobalStringKey::Get(CTOR_PARAM_NAME(name)); vint index = arguments.Keys().IndexOf(key); if (index == -1) { return nullptr; } else { create->arguments.Add(arguments.GetByIndex(index)[0].expression); } } } auto refValue = MakePtr(); refValue->name.value = variableName.ToString(); auto assign = MakePtr(); assign->op = WfBinaryOperator::Assign; assign->first = refValue; assign->second = create; auto stat = MakePtr(); stat->expression = assign; return stat; } Ptr AssignParameters(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const TypeInfo& typeInfo, GlobalStringKey variableName, ArgumentMap& arguments, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override { auto block = MakePtr(); FOREACH_INDEXER(GlobalStringKey, prop, index, arguments.Keys()) { PropertyType propertyType = GetPropertyTypeCached(PropertyInfo(typeInfo, prop)); if (propertyType.f1) { switch (propertyType.f0->support) { case GuiInstancePropertyInfo::SupportCollection: { const auto& values = arguments.GetByIndex(index); if (values.Count() > 0) { { auto refValue = MakePtr(); refValue->name.value = variableName.ToString(); auto refProp = MakePtr(); refProp->parent = refValue; refProp->name.value = prop.ToString(); auto varDesc = MakePtr(); varDesc->name.value = L""; varDesc->expression = refProp; auto stat = MakePtr(); stat->variable = varDesc; block->statements.Add(stat); } for (vint i = 0; i < values.Count(); i++) { auto refCollection = MakePtr(); refCollection->name.value = L""; auto refAdd = MakePtr(); refAdd->parent = refCollection; refAdd->name.value = L"Add"; auto call = MakePtr(); call->function = refAdd; call->arguments.Add(values[i].expression); auto stat = MakePtr(); stat->expression = call; block->statements.Add(stat); } } } break; case GuiInstancePropertyInfo::SupportArray: { auto refArray = MakePtr(); FOREACH(ArgumentInfo, item, arguments.GetByIndex(index)) { auto argument = MakePtr(); argument->key = item.expression; refArray->arguments.Add(argument); } auto refValue = MakePtr(); refValue->name.value = variableName.ToString(); auto refProp = MakePtr(); refProp->parent = refValue; refProp->name.value = prop.ToString(); auto assign = MakePtr(); assign->op = WfBinaryOperator::Assign; assign->first = refProp; assign->second = refArray; auto stat = MakePtr(); stat->expression = assign; block->statements.Add(stat); } break; case GuiInstancePropertyInfo::SupportAssign: { auto& propertyValue = arguments.GetByIndex(index)[0]; if (propertyValue.expression) { auto refValue = MakePtr(); refValue->name.value = variableName.ToString(); auto refProp = MakePtr(); refProp->parent = refValue; refProp->name.value = prop.ToString(); auto assign = MakePtr(); assign->op = WfBinaryOperator::Assign; assign->first = refProp; assign->second = propertyValue.expression; auto stat = MakePtr(); stat->expression = assign; block->statements.Add(stat); } } break; default: errors.Add(GuiResourceError({ resolvingResult.resource }, attPosition, L"Precompile: Property \"" + prop.ToString() + L"\" of type \"" + typeInfo.typeName.ToString() + L"\" is not assignable.")); } } } if (block->statements.Count() > 0) { return block; } return nullptr; } Ptr GetParameter(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, const PropertyInfo& propertyInfo, GlobalStringKey variableName, GuiResourceTextPos attPosition, GuiResourceError::List& errors)override { auto refValue = MakePtr(); refValue->name.value = variableName.ToString(); auto refProp = MakePtr(); refProp->parent = refValue; refProp->name.value = propertyInfo.propertyName.ToString(); return refProp; } }; #undef CTOR_PARAM_NAME #undef CTOR_PARAM_PREFIX /*********************************************************************** GuiInstanceLoaderManager ***********************************************************************/ IGuiInstanceLoaderManager* instanceLoaderManager = 0; IGuiInstanceLoaderManager* GetInstanceLoaderManager() { return instanceLoaderManager; } class GuiInstanceLoaderManager : public Object, public IGuiInstanceLoaderManager, public IGuiPlugin { protected: typedef Dictionary> BinderMap; typedef Dictionary> EventBinderMap; typedef List> DeserializerList; struct VirtualTypeInfo { GlobalStringKey typeName; ITypeDescriptor* typeDescriptor = nullptr; GlobalStringKey parentTypeName; // for virtual type only Ptr loader; List parentTypes; // all direct or indirect base types that does not has a type info List parentTypeInfos; // type infos for all registered direct or indirect base types }; typedef Dictionary> VirtualTypeInfoMap; Ptr rootLoader; BinderMap binders; EventBinderMap eventBinders; DeserializerList deserializers; VirtualTypeInfoMap typeInfos; bool IsTypeExists(GlobalStringKey name) { return GetGlobalTypeManager()->GetTypeDescriptor(name.ToString()) != 0 || typeInfos.Keys().Contains(name); } void FindParentTypeInfos(Ptr typeInfo, ITypeDescriptor* searchType) { if (searchType != typeInfo->typeDescriptor) { vint index = typeInfos.Keys().IndexOf(GlobalStringKey::Get(searchType->GetTypeName())); if (index == -1) { typeInfo->parentTypes.Add(searchType); } else { typeInfo->parentTypeInfos.Add(typeInfos.Values()[index].Obj()); return; } } vint count = searchType->GetBaseTypeDescriptorCount(); for (vint i = 0; i < count; i++) { ITypeDescriptor* baseType = searchType->GetBaseTypeDescriptor(i); FindParentTypeInfos(typeInfo, baseType); } } void FillParentTypeInfos(Ptr typeInfo) { if (typeInfo->parentTypeName != GlobalStringKey::Empty) { typeInfo->typeDescriptor = nullptr; } typeInfo->parentTypes.Clear(); typeInfo->parentTypeInfos.Clear(); ITypeDescriptor* searchType = typeInfo->typeDescriptor; if (!searchType) { vint index = typeInfos.Keys().IndexOf(typeInfo->parentTypeName); if (index == -1) { searchType = GetGlobalTypeManager()->GetTypeDescriptor(typeInfo->parentTypeName.ToString()); typeInfo->typeDescriptor = searchType; typeInfo->parentTypes.Add(searchType); } else { VirtualTypeInfo* parentTypeInfo = typeInfos.Values()[index].Obj(); typeInfo->typeDescriptor = parentTypeInfo->typeDescriptor; typeInfo->parentTypeInfos.Add(parentTypeInfo); return; } } if (searchType) { FindParentTypeInfos(typeInfo, searchType); } } IGuiInstanceLoader* GetLoaderFromType(ITypeDescriptor* typeDescriptor) { vint index = typeInfos.Keys().IndexOf(GlobalStringKey::Get(typeDescriptor->GetTypeName())); if (index == -1) { vint count = typeDescriptor->GetBaseTypeDescriptorCount(); for (vint i = 0; i < count; i++) { ITypeDescriptor* baseType = typeDescriptor->GetBaseTypeDescriptor(i); IGuiInstanceLoader* loader = GetLoaderFromType(baseType); if (loader) return loader; } return 0; } else { return typeInfos.Values()[index]->loader.Obj(); } } public: GuiInstanceLoaderManager() { rootLoader = new GuiDefaultInstanceLoader; } void Load()override { instanceLoaderManager = this; } void AfterLoad()override { IGuiParserManager* manager = GetParserManager(); manager->SetParser(L"INSTANCE-ELEMENT-NAME", new GuiInstanceContextElementNameParser); } void Unload()override { instanceLoaderManager = nullptr; } bool AddInstanceBinder(Ptr binder)override { if (binders.Keys().Contains(binder->GetBindingName())) return false; binders.Add(binder->GetBindingName(), binder); return true; } IGuiInstanceBinder* GetInstanceBinder(GlobalStringKey bindingName)override { vint index = binders.Keys().IndexOf(bindingName); return index == -1 ? nullptr : binders.Values()[index].Obj(); } bool AddInstanceEventBinder(Ptr binder)override { if (eventBinders.Keys().Contains(binder->GetBindingName())) return false; eventBinders.Add(binder->GetBindingName(), binder); return true; } IGuiInstanceEventBinder* GetInstanceEventBinder(GlobalStringKey bindingName)override { vint index = eventBinders.Keys().IndexOf(bindingName); return index == -1 ? nullptr : eventBinders.Values()[index].Obj(); } bool AddInstanceDeserializer(Ptr deserializer)override { if (deserializers.Contains(deserializer.Obj())) return false; deserializers.Add(deserializer); return true; } IGuiInstanceDeserializer* GetInstanceDeserializer(description::ITypeInfo* typeInfo)override { FOREACH(Ptr, deserializer, deserializers) { if (deserializer->CanDeserialize(typeInfo)) { return deserializer.Obj(); } } return nullptr; } bool CreateVirtualType(GlobalStringKey parentType, Ptr loader)override { if (IsTypeExists(loader->GetTypeName()) || !IsTypeExists(parentType)) return false; Ptr typeInfo = new VirtualTypeInfo; typeInfo->typeName = loader->GetTypeName(); typeInfo->parentTypeName = parentType; typeInfo->loader = loader; typeInfos.Add(loader->GetTypeName(), typeInfo); FillParentTypeInfos(typeInfo); return true; } bool SetLoader(Ptr loader)override { vint index = typeInfos.Keys().IndexOf(loader->GetTypeName()); if (index != -1) return false; ITypeDescriptor* typeDescriptor = GetGlobalTypeManager()->GetTypeDescriptor(loader->GetTypeName().ToString()); if (typeDescriptor == 0) return false; Ptr typeInfo = new VirtualTypeInfo; typeInfo->typeName = loader->GetTypeName(); typeInfo->typeDescriptor = typeDescriptor; typeInfo->loader = loader; typeInfos.Add(typeInfo->typeName, typeInfo); FillParentTypeInfos(typeInfo); FOREACH(Ptr, derived, typeInfos.Values()) { if (derived->parentTypes.Contains(typeInfo->typeDescriptor)) { FillParentTypeInfos(derived); } } return true; } IGuiInstanceLoader* GetLoader(GlobalStringKey typeName)override { vint index = typeInfos.Keys().IndexOf(typeName); if (index != -1) { return typeInfos.Values()[index]->loader.Obj(); } ITypeDescriptor* typeDescriptor = GetGlobalTypeManager()->GetTypeDescriptor(typeName.ToString()); if (typeDescriptor) { IGuiInstanceLoader* loader = GetLoaderFromType(typeDescriptor); return loader ? loader : rootLoader.Obj(); } return 0; } IGuiInstanceLoader* GetParentLoader(IGuiInstanceLoader* loader)override { vint index = typeInfos.Keys().IndexOf(loader->GetTypeName()); if (index != -1) { Ptr typeInfo = typeInfos.Values()[index]; if (typeInfo->parentTypeInfos.Count() > 0) { return typeInfo->parentTypeInfos[0]->loader.Obj(); } return rootLoader.Obj(); } return 0; } Ptr GetTypeInfoForType(GlobalStringKey typeName)override { vint index = typeInfos.Keys().IndexOf(typeName); auto td = index == -1 ? GetGlobalTypeManager()->GetTypeDescriptor(typeName.ToString()) : typeInfos.Values()[index]->typeDescriptor; if (!td) return nullptr; if (auto ctor = td->GetConstructorGroup()) { return CopyTypeInfo(ctor->GetMethod(0)->GetReturn()); } else { return MakePtr(MakePtr(td, TypeInfoHint::Normal)); } } void GetVirtualTypes(collections::List& typeNames)override { for (vint i = 0; i < typeInfos.Count(); i++) { if (typeInfos.Values()[i]->parentTypeName != GlobalStringKey::Empty) { typeNames.Add(typeInfos.Keys()[i]); } } } GlobalStringKey GetParentTypeForVirtualType(GlobalStringKey virtualType)override { vint index = typeInfos.Keys().IndexOf(virtualType); if (index != -1) { auto typeInfo = typeInfos.Values()[index]; return typeInfo->parentTypeName; } return GlobalStringKey::Empty; } void ClearReflectionCache()override { rootLoader->ClearReflectionCache(); FOREACH(Ptr, info, typeInfos.Values()) { info->loader->ClearReflectionCache(); } } }; GUI_REGISTER_PLUGIN(GuiInstanceLoaderManager) } } /*********************************************************************** GUIINSTANCELOADER_PREDEFINEDINSTANCEBINDERS.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace collections; using namespace reflection::description; using namespace parsing; using namespace workflow; using namespace workflow::analyzer; using namespace workflow::runtime; using namespace controls; using namespace stream; /*********************************************************************** GuiResourceInstanceBinder (uri) ***********************************************************************/ class GuiResourceInstanceBinder : public Object, public IGuiInstanceBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Uri; } bool ApplicableToConstructorArgument()override { return true; } bool RequirePropertyExist()override { return false; } Ptr GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { WString protocol, path; if (!IsResourceUrl(code, protocol, path)) { errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: \"" + code + L"\" is not a valid resource uri.")); return nullptr; } else { return Workflow_GetUriProperty(precompileContext, resolvingResult, loader, prop, propInfo, protocol, path, position, errors); } } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { WString protocol, path; if (!IsResourceUrl(code, protocol, path)) { errors.Add(GuiResourceError({ resolvingResult.resource }, position, L"Precompile: \"" + code + L"\" is not a valid resource uri.")); return nullptr; } else { return Workflow_InstallUriProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, protocol, path, position, errors); } } }; /*********************************************************************** GuiReferenceInstanceBinder (ref) ***********************************************************************/ class GuiReferenceInstanceBinder : public Object, public IGuiInstanceBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Ref; } bool ApplicableToConstructorArgument()override { return false; } bool RequirePropertyExist()override { return false; } Ptr GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { CHECK_FAIL(L"GuiReferenceInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function."); } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { auto expression = MakePtr(); expression->name.value = code; return Workflow_InstallEvalProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, expression, position, errors); } }; /*********************************************************************** GuiEvalInstanceBinder (eval) ***********************************************************************/ class GuiEvalInstanceBinder : public Object, public IGuiInstanceBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Eval; } bool ApplicableToConstructorArgument()override { return true; } bool RequirePropertyExist()override { return false; } Ptr GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { return Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors); } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { if(auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors)) { return Workflow_InstallEvalProperty(precompileContext, resolvingResult, variableName, loader, prop, propInfo, expression, position, errors); } return nullptr; } }; /*********************************************************************** GuiBindInstanceBinder (bind) ***********************************************************************/ class GuiBindInstanceBinder : public Object, public IGuiInstanceBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Bind; } bool ApplicableToConstructorArgument()override { return false; } bool RequirePropertyExist()override { return true; } Ptr GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { CHECK_FAIL(L"GuiBindInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function."); } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { if(auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, code, position, errors)) { auto inferExpr = MakePtr(); inferExpr->expression = expression; inferExpr->type = GetTypeFromTypeInfo(propertyInfo->GetReturn()); auto bindExpr = MakePtr(); bindExpr->expression = inferExpr; return Workflow_InstallBindProperty(precompileContext, resolvingResult, variableName, propertyInfo, bindExpr); } return nullptr; } }; /*********************************************************************** GuiFormatInstanceBinder (format) ***********************************************************************/ class GuiFormatInstanceBinder : public Object, public IGuiInstanceBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Format; } bool ApplicableToConstructorArgument()override { return false; } bool RequirePropertyExist()override { return true; } Ptr GenerateConstructorArgument(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { CHECK_FAIL(L"GuiFormatInstanceBinder::GenerateConstructorArgument()#This binder does not support binding to constructor arguments. Please call ApplicableToConstructorArgument() to determine before calling this function."); } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IPropertyInfo* propertyInfo, IGuiInstanceLoader* loader, const IGuiInstanceLoader::PropertyInfo& prop, Ptr propInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { if (auto expression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, L"bind($\"" + code + L"\")", position, errors, { 0,7 })) // bind($" { return Workflow_InstallBindProperty(precompileContext, resolvingResult, variableName, propertyInfo, expression); } return nullptr; } }; /*********************************************************************** GuiEvalInstanceEventBinder (eval) ***********************************************************************/ class GuiEvalInstanceEventBinder : public Object, public IGuiInstanceEventBinder { public: GlobalStringKey GetBindingName()override { return GlobalStringKey::_Eval; } Ptr GenerateInstallStatement(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, GlobalStringKey variableName, description::IEventInfo* eventInfo, const WString& code, GuiResourceTextPos position, GuiResourceError::List& errors)override { bool coroutine = false; { auto reading = code.Buffer(); while (true) { switch (*reading) { case ' ': case '\t': case '\r': case '\n': reading++; break; default: goto BEGIN_TESTING; } } BEGIN_TESTING: coroutine = *reading == '$'; } auto parseFunction = coroutine ? &Workflow_ParseCoProviderStatement : &Workflow_ParseStatement; if (auto statement = parseFunction(precompileContext, { resolvingResult.resource }, code, position, errors, { 0,0 })) { return Workflow_InstallEvalEvent(precompileContext, resolvingResult, variableName, eventInfo, statement); } return nullptr; } }; /*********************************************************************** GuiPredefinedInstanceBindersPlugin ***********************************************************************/ class GuiPredefinedInstanceBindersPlugin : public Object, public IGuiPlugin { public: GuiPredefinedInstanceBindersPlugin() { } void Load()override { WfLoadTypes(); GuiIqLoadTypes(); } void AfterLoad()override { { IGuiParserManager* manager = GetParserManager(); manager->SetParsingTable(L"WORKFLOW", &WfLoadTable); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-TYPE", &WfParseType); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-EXPRESSION", &WfParseExpression); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-STATEMENT", &WfParseStatement); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-COPROVIDER-STATEMENT", &WfParseCoProviderStatement); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-DECLARATION", &WfParseDeclaration); manager->SetTableParser(L"WORKFLOW", L"WORKFLOW-MODULE", &WfParseModule); manager->SetParsingTable(L"INSTANCE-QUERY", &GuiIqLoadTable); manager->SetTableParser(L"INSTANCE-QUERY", L"INSTANCE-QUERY", &GuiIqParse); } { IGuiInstanceLoaderManager* manager=GetInstanceLoaderManager(); manager->AddInstanceBinder(new GuiResourceInstanceBinder); manager->AddInstanceBinder(new GuiReferenceInstanceBinder); manager->AddInstanceBinder(new GuiEvalInstanceBinder); manager->AddInstanceEventBinder(new GuiEvalInstanceEventBinder); manager->AddInstanceBinder(new GuiBindInstanceBinder); manager->AddInstanceBinder(new GuiFormatInstanceBinder); } } void Unload()override { } }; GUI_REGISTER_PLUGIN(GuiPredefinedInstanceBindersPlugin) } } /*********************************************************************** GUIINSTANCELOADER_PREDEFINEDINSTANCEDESERIALIZERS.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace collections; using namespace reflection::description; using namespace workflow; using namespace workflow::analyzer; using namespace controls; using namespace controls::list; using namespace templates; /*********************************************************************** GuiTemplatePropertyDeserializer ***********************************************************************/ class GuiTemplatePropertyDeserializer : public Object, public IGuiInstanceDeserializer { protected: Ptr stringType; bool IsTemplatePropertyType(ITypeInfo* propType) { if (propType->GetDecorator() == ITypeInfo::SharedPtr) { auto genericType = propType->GetElementType(); if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 2) { if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor()) { if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor()) { auto returnType = genericType->GetGenericArgument(0); if (returnType->GetDecorator() == ITypeInfo::RawPtr) { if (returnType->GetElementType()->GetTypeDescriptor()->CanConvertTo(description::GetTypeDescriptor())) { return true; } } } } } } return false; } bool IsDataVisualizerFactoryType(ITypeInfo* propType) { return propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetTypeDescriptor() == description::GetTypeDescriptor(); } bool IsDataEditorFactoryType(ITypeInfo* propType) { return propType->GetDecorator() == ITypeInfo::SharedPtr && propType->GetTypeDescriptor() == description::GetTypeDescriptor(); } public: GuiTemplatePropertyDeserializer() { stringType = TypeInfoRetriver::CreateTypeInfo(); } bool CanDeserialize(description::ITypeInfo* typeInfo)override { return IsTemplatePropertyType(typeInfo) || IsDataVisualizerFactoryType(typeInfo) || IsDataEditorFactoryType(typeInfo); } description::ITypeInfo* DeserializeAs(description::ITypeInfo* typeInfo)override { return stringType.Obj(); } static void GetItemTemplateType( types::ResolvingResult& resolvingResult, WString typeNamesString, List& tds, GuiResourceTextPos tagPosition, GuiResourceError::List& errors ) { List typeNames; SplitBySemicolon(typeNamesString, typeNames); if (typeNames.Count() == 0) { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: Template list \"" + typeNamesString + L"\" cannot be empty.")); } FOREACH(WString, controlTemplateName, typeNames) { auto controlTemplateTd = description::GetTypeDescriptor(controlTemplateName); if (!controlTemplateTd) { auto index = INVLOC.FindFirst(controlTemplateName, L":", Locale::None); GlobalStringKey namespaceName; auto typeName = controlTemplateName; if (index.key != -1) { namespaceName = GlobalStringKey::Get(controlTemplateName.Left(index.key)); typeName = controlTemplateName.Right(controlTemplateName.Length() - index.key - index.value); } auto source = FindInstanceLoadingSource(resolvingResult.context, namespaceName, typeName); if (auto typeInfo = GetInstanceLoaderManager()->GetTypeInfoForType(source.typeName)) { controlTemplateTd = typeInfo->GetTypeDescriptor(); } } if (controlTemplateTd) { tds.Add(controlTemplateTd); } else { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: Type \"" + controlTemplateName + L"\" does not exist.")); continue; } } } static Ptr CreateTemplateFactory( types::ResolvingResult& resolvingResult, List& controlTemplateTds, ITypeInfo* templateType, GuiResourceTextPos tagPosition, GuiResourceError::List& errors ) { auto funcCreateTemplate = MakePtr(); funcCreateTemplate->anonymity = WfFunctionAnonymity::Anonymous; funcCreateTemplate->returnType = GetTypeFromTypeInfo(templateType); auto argViewModel = MakePtr(); argViewModel->type = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); argViewModel->name.value = L""; funcCreateTemplate->arguments.Add(argViewModel); auto block = MakePtr(); funcCreateTemplate->statement = block; ITypeDescriptor* stopControlTemplateTd = nullptr; FOREACH(ITypeDescriptor*, controlTemplateTd, controlTemplateTds) { if (!controlTemplateTd->CanConvertTo(templateType->GetTypeDescriptor())) { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: Type \"" + controlTemplateTd->GetTypeName() + L"\" cannot be used here because it requires \"" + templateType->GetTypeDescriptor()->GetTypeName() + L"\" or its derived classes.")); } if (stopControlTemplateTd) { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: Type \"" + controlTemplateTd->GetTypeName() + L"\" will never be tried, because \"" + stopControlTemplateTd->GetTypeName() + L"\", which is listed before, has a default constructor. So whatever the view model is, it will be the last choice.")); continue; } ITypeInfo* viewModelType = nullptr; { auto ctors = controlTemplateTd->GetConstructorGroup(); if (!ctors || ctors->GetMethodCount() != 1) { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: To use type \"" + controlTemplateTd->GetTypeName() + L"\" as a control template or item template, it should have exactly one constructor.")); continue; } auto ctor = ctors->GetMethod(0); if (ctor->GetParameterCount() > 1) { errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, L"Precompile: To use type \"" + controlTemplateTd->GetTypeName() + L"\" as a control template or item template, its constructor cannot have more than one parameter.")); continue; } if (ctor->GetParameterCount() != 0) { viewModelType = ctor->GetParameter(0)->GetType(); } } if (!viewModelType) { stopControlTemplateTd = controlTemplateTd; } auto subBlock = MakePtr(); block->statements.Add(subBlock); Ptr controlTemplateType; { auto elementType = MakePtr(controlTemplateTd, TypeInfoHint::Normal); auto pointerType = MakePtr(elementType); controlTemplateType = pointerType; } Ptr returnStatBlock; if (viewModelType) { auto refViewModel = MakePtr(); refViewModel->name.value = L""; auto condition = MakePtr(); condition->test = WfTypeTesting::IsType; condition->expression = refViewModel; condition->type = GetTypeFromTypeInfo(viewModelType); auto ifStat = MakePtr(); subBlock->statements.Add(ifStat); ifStat->expression = condition; returnStatBlock = MakePtr(); ifStat->trueBranch = returnStatBlock; } else { returnStatBlock = subBlock; } { auto createControlTemplate = MakePtr(); createControlTemplate->type = GetTypeFromTypeInfo(controlTemplateType.Obj()); if (viewModelType) { auto refViewModel = MakePtr(); refViewModel->name.value = L""; auto cast = MakePtr(); cast->strategy = WfTypeCastingStrategy::Strong; cast->expression = refViewModel; cast->type = GetTypeFromTypeInfo(viewModelType); createControlTemplate->arguments.Add(cast); } auto returnStat = MakePtr(); returnStat->expression = createControlTemplate; returnStatBlock->statements.Add(returnStat); } } if (!stopControlTemplateTd) { auto value = MakePtr(); value->value.value = L"Cannot find a matched control template to create."; auto raiseStat = MakePtr(); raiseStat->expression = value; block->statements.Add(raiseStat); } auto expr = MakePtr(); expr->function = funcCreateTemplate; return expr; } static Ptr CreateDataVisualizerFactory( types::ResolvingResult& resolvingResult, List& controlTemplateTds, GuiResourceTextPos tagPosition, GuiResourceError::List& errors ) { auto templateType = TypeInfoRetriver::CreateTypeInfo(); Ptr previousFactory; FOREACH_INDEXER(ITypeDescriptor*, controlTemplateTd, index, controlTemplateTds) { List tds; tds.Add(controlTemplateTd); auto refFactory = CreateTemplateFactory(resolvingResult, tds, templateType.Obj(), tagPosition, errors); auto createStyle = MakePtr(); createStyle->type = GetTypeFromTypeInfo(TypeInfoRetriver>::CreateTypeInfo().Obj()); createStyle->arguments.Add(refFactory); if (index > 0) { createStyle->arguments.Add(previousFactory); } else { auto nullExpr = MakePtr(); nullExpr->value = WfLiteralValue::Null; createStyle->arguments.Add(nullExpr); } previousFactory = createStyle; } return previousFactory; } static Ptr CreateDataEditorFactory( types::ResolvingResult& resolvingResult, List& controlTemplateTds, GuiResourceTextPos tagPosition, GuiResourceError::List& errors ) { auto templateType = TypeInfoRetriver::CreateTypeInfo(); auto refFactory = CreateTemplateFactory(resolvingResult, controlTemplateTds, templateType.Obj(), tagPosition, errors); auto createStyle = MakePtr(); createStyle->type = GetTypeFromTypeInfo(TypeInfoRetriver>::CreateTypeInfo().Obj()); createStyle->arguments.Add(refFactory); return createStyle; } Ptr Deserialize(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, description::ITypeInfo* typeInfo, Ptr valueExpression, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override { auto stringExpr = valueExpression.Cast(); List tds; GetItemTemplateType(resolvingResult, stringExpr->value.value, tds, tagPosition, errors); if (IsDataVisualizerFactoryType(typeInfo)) { return CreateDataVisualizerFactory(resolvingResult, tds, tagPosition, errors); } else if (IsDataEditorFactoryType(typeInfo)) { return CreateDataEditorFactory(resolvingResult, tds, tagPosition, errors); } else { auto templateType = typeInfo->GetElementType()->GetGenericArgument(0); return CreateTemplateFactory(resolvingResult, tds, templateType, tagPosition, errors); } } }; /*********************************************************************** GuiItemPropertyDeserializer ***********************************************************************/ class GuiItemPropertyDeserializer : public Object, public IGuiInstanceDeserializer { protected: Ptr stringType; bool IsItemPropertyType(ITypeInfo* propType) { if (propType->GetDecorator() == ITypeInfo::SharedPtr) { auto genericType = propType->GetElementType(); if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 2) { if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor()) { if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor()) { return true; } } } } return false; } bool IsWritableItemPropertyType(ITypeInfo* propType) { if (propType->GetDecorator() == ITypeInfo::SharedPtr) { auto genericType = propType->GetElementType(); if (genericType->GetDecorator() == ITypeInfo::Generic && genericType->GetGenericArgumentCount() == 4) { if (genericType->GetElementType()->GetTypeDescriptor() == description::GetTypeDescriptor()) { if (genericType->GetGenericArgument(1)->GetTypeDescriptor() == description::GetTypeDescriptor() && genericType->GetGenericArgument(3)->GetTypeDescriptor() == description::GetTypeDescriptor()) { if (IsSameType(genericType->GetGenericArgument(0), genericType->GetGenericArgument(2))) { return true; } } } } } return false; } public: GuiItemPropertyDeserializer() { stringType = TypeInfoRetriver::CreateTypeInfo(); } bool CanDeserialize(description::ITypeInfo* typeInfo)override { return IsItemPropertyType(typeInfo) || IsWritableItemPropertyType(typeInfo); } description::ITypeInfo* DeserializeAs(description::ITypeInfo* typeInfo)override { return stringType.Obj(); } Ptr Deserialize(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, description::ITypeInfo* typeInfo, Ptr valueExpression, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override { auto stringExpr = valueExpression.Cast(); Ptr propertyExpression; { propertyExpression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, stringExpr->value.value, tagPosition, errors); if (!propertyExpression) { return nullptr; } }; vint indexItemType = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemType")); if (indexItemType == -1) { auto error = L"Precompile: env.ItemType must be specified before deserializing \"" + stringExpr->value.value + L"\" to value of type \"" + typeInfo->GetTypeFriendlyName() + L"\"."; errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, error)); return nullptr; } Ptr itemType; { const auto& values = resolvingResult.envVars.GetByIndex(indexItemType); auto itemTypeValue = values[values.Count() - 1]; itemType = Workflow_ParseType(precompileContext, { resolvingResult.resource }, itemTypeValue->value, itemTypeValue->valuePosition, errors); if (!itemType) { return nullptr; } }; vint indexItemName = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemName")); WString itemName(L"item", false); if (indexItemName != -1) { const auto& values = resolvingResult.envVars.GetByIndex(indexItemName); itemName = values[values.Count() - 1]->value; } if (auto refExpr = propertyExpression.Cast()) { if (refExpr->name.value != itemName) { auto refItem = MakePtr(); refItem->name.value = itemName; auto member = MakePtr(); member->parent = refItem; member->name.value = refExpr->name.value; propertyExpression = member; } } bool isWritableItemProperty = IsWritableItemPropertyType(typeInfo); auto funcDecl = MakePtr(); ITypeInfo* acceptValueType = nullptr; funcDecl->anonymity = WfFunctionAnonymity::Anonymous; { auto genericType = typeInfo->GetElementType(); funcDecl->returnType = GetTypeFromTypeInfo(genericType->GetGenericArgument(0)); { auto argument = MakePtr(); argument->name.value = L""; argument->type = GetTypeFromTypeInfo(genericType->GetGenericArgument(1)); funcDecl->arguments.Add(argument); } if (isWritableItemProperty) { { auto argument = MakePtr(); argument->name.value = L""; argument->type = GetTypeFromTypeInfo((acceptValueType = genericType->GetGenericArgument(2))); funcDecl->arguments.Add(argument); } { auto argument = MakePtr(); argument->name.value = L""; argument->type = GetTypeFromTypeInfo(genericType->GetGenericArgument(3)); funcDecl->arguments.Add(argument); } } } auto funcBlock = MakePtr(); funcDecl->statement = funcBlock; { auto refItem = MakePtr(); refItem->name.value = L""; auto refCast = MakePtr(); refCast->strategy = WfTypeCastingStrategy::Strong; refCast->type = itemType; refCast->expression = refItem; auto varDecl = MakePtr(); varDecl->name.value = itemName; varDecl->expression = refCast; auto varStat = MakePtr(); varStat->variable = varDecl; funcBlock->statements.Add(varStat); } Ptr returnStat; { returnStat = MakePtr(); returnStat->expression = propertyExpression; } if (isWritableItemProperty) { auto ifStat = MakePtr(); funcBlock->statements.Add(ifStat); { auto refUpdate = MakePtr(); refUpdate->name.value = L""; ifStat->expression = refUpdate; } { auto block = MakePtr(); ifStat->trueBranch = block; { auto refValue = MakePtr(); refValue->name.value = L""; auto assignExpr = MakePtr(); assignExpr->op = WfBinaryOperator::Assign; assignExpr->first = CopyExpression(propertyExpression); if (acceptValueType->GetTypeDescriptor()->GetTypeDescriptorFlags() == TypeDescriptorFlags::Object) { auto castExpr = MakePtr(); castExpr->strategy = WfTypeCastingStrategy::Strong; castExpr->expression = refValue; assignExpr->second = castExpr; } else { assignExpr->second = refValue; } auto stat = MakePtr(); stat->expression = assignExpr; block->statements.Add(stat); } { auto returnStat = MakePtr(); block->statements.Add(returnStat); auto returnType = typeInfo->GetElementType()->GetGenericArgument(0); returnStat->expression = CreateDefaultValue(returnType); } } { auto block = MakePtr(); ifStat->falseBranch = block; block->statements.Add(returnStat); } } else { funcBlock->statements.Add(returnStat); } auto funcExpr = MakePtr(); funcExpr->function = funcDecl; return funcExpr; } }; /*********************************************************************** GuiDataProcessorDeserializer ***********************************************************************/ class GuiDataProcessorDeserializer : public Object, public IGuiInstanceDeserializer { protected: Ptr stringType; public: GuiDataProcessorDeserializer() { stringType = TypeInfoRetriver::CreateTypeInfo(); } bool CanDeserialize(description::ITypeInfo* typeInfo)override { return typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor() || typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor(); } description::ITypeInfo* DeserializeAs(description::ITypeInfo* typeInfo)override { return stringType.Obj(); } Ptr Deserialize(GuiResourcePrecompileContext& precompileContext, types::ResolvingResult& resolvingResult, description::ITypeInfo* typeInfo, Ptr valueExpression, GuiResourceTextPos tagPosition, GuiResourceError::List& errors)override { auto stringExpr = valueExpression.Cast(); Ptr propertyExpression; { propertyExpression = Workflow_ParseExpression(precompileContext, { resolvingResult.resource }, stringExpr->value.value, tagPosition, errors); if (!propertyExpression) { return nullptr; } }; vint indexItemType = resolvingResult.envVars.Keys().IndexOf(GlobalStringKey::Get(L"ItemType")); if (indexItemType == -1) { auto error = L"Precompile: env.ItemType must be specified before deserializing \"" + stringExpr->value.value + L"\" to value of type \"" + typeInfo->GetTypeFriendlyName() + L"\"."; errors.Add(GuiResourceError({ resolvingResult.resource }, tagPosition, error)); return nullptr; } Ptr itemType; { const auto& values = resolvingResult.envVars.GetByIndex(indexItemType); auto itemTypeValue = values[values.Count() - 1]; itemType = Workflow_ParseType(precompileContext, { resolvingResult.resource }, itemTypeValue->value, itemTypeValue->valuePosition, errors); if (!itemType) { return nullptr; } }; auto newExpr = MakePtr(); newExpr->type = GetTypeFromTypeInfo(typeInfo); { auto decl = MakePtr(); newExpr->declarations.Add(decl); decl->classMember = MakePtr(); decl->classMember->kind = WfClassMemberKind::Override; decl->name.value = L"SetCallback"; decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); { auto argument = MakePtr(); argument->type = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); argument->name.value = L"value"; decl->arguments.Add(argument); } auto block = MakePtr(); decl->statement = block; } { auto decl = MakePtr(); newExpr->declarations.Add(decl); decl->classMember = MakePtr(); decl->classMember->kind = WfClassMemberKind::Override; List argumentNames; if (typeInfo->GetTypeDescriptor() == description::GetTypeDescriptor()) { decl->name.value = L"Filter"; decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); argumentNames.Add(L""); } else { decl->name.value = L"Compare"; decl->returnType = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); argumentNames.Add(L""); argumentNames.Add(L""); } FOREACH(WString, name, argumentNames) { auto argument = MakePtr(); argument->type = GetTypeFromTypeInfo(TypeInfoRetriver::CreateTypeInfo().Obj()); argument->name.value = name; decl->arguments.Add(argument); } auto block = MakePtr(); decl->statement = block; auto inferExpr = MakePtr(); inferExpr->expression = propertyExpression; { auto funcType = MakePtr(); inferExpr->type = funcType; funcType->result = CopyType(decl->returnType); for (vint i = 0; i < decl->arguments.Count(); i++) { funcType->arguments.Add(CopyType(itemType)); } } auto callExpr = MakePtr(); callExpr->function = inferExpr; FOREACH_INDEXER(WString, name, index, argumentNames) { auto refExpr = MakePtr(); refExpr->name.value = name; auto castExpr = MakePtr(); castExpr->strategy = WfTypeCastingStrategy::Strong; castExpr->type = (index == 0 ? itemType : CopyType(itemType)); castExpr->expression = refExpr; callExpr->arguments.Add(castExpr); } auto stat = MakePtr(); stat->expression = callExpr; block->statements.Add(stat); } return newExpr; } }; /*********************************************************************** GuiPredefinedInstanceDeserializersPlugin ***********************************************************************/ class GuiPredefinedInstanceDeserializersPlugin : public Object, public IGuiPlugin { public: GuiPredefinedInstanceDeserializersPlugin() { } void Load()override { } void AfterLoad()override { IGuiInstanceLoaderManager* manager = GetInstanceLoaderManager(); manager->AddInstanceDeserializer(new GuiTemplatePropertyDeserializer); manager->AddInstanceDeserializer(new GuiItemPropertyDeserializer); manager->AddInstanceDeserializer(new GuiDataProcessorDeserializer); } void Unload()override { } }; GUI_REGISTER_PLUGIN(GuiPredefinedInstanceDeserializersPlugin) } } /*********************************************************************** GUIINSTANCELOADER_PREDEFINEDTYPERESOLVERS.CPP ***********************************************************************/ namespace vl { namespace presentation { using namespace parsing; using namespace parsing::xml; using namespace workflow; using namespace workflow::analyzer; using namespace workflow::emitter; using namespace workflow::runtime; using namespace reflection::description; using namespace collections; using namespace stream; using namespace controls; class WorkflowVirtualScriptPositionVisitor : public traverse_visitor::ModuleVisitor { public: GuiResourcePrecompileContext& context; Ptr sp; WorkflowVirtualScriptPositionVisitor(GuiResourcePrecompileContext& _context) :context(_context) { sp = Workflow_GetScriptPosition(context); } void Visit(WfVirtualExpression* node)override { traverse_visitor::ExpressionVisitor::Visit(node); vint index = sp->nodePositions.Keys().IndexOf(node); if (index != -1) { auto record = sp->nodePositions.Values()[index]; Workflow_RecordScriptPosition(context, record.position, node->expandedExpression, record.availableAfter); } } void Visit(WfVirtualStatement* node)override { traverse_visitor::StatementVisitor::Visit(node); vint index = sp->nodePositions.Keys().IndexOf(node); if (index != -1) { auto record = sp->nodePositions.Values()[index]; Workflow_RecordScriptPosition(context, record.position, node->expandedStatement, record.availableAfter); } } void Visit(WfVirtualDeclaration* node)override { traverse_visitor::DeclarationVisitor::Visit(node); vint index = sp->nodePositions.Keys().IndexOf(node); if (index != -1) { auto record = sp->nodePositions.Values()[index]; FOREACH(Ptr, decl, node->expandedDeclarations) { Workflow_RecordScriptPosition(context, record.position, decl, record.availableAfter); } } } }; Ptr Workflow_GetModule(GuiResourcePrecompileContext& context, const WString& path) { return context.targetFolder->GetValueByPath(path).Cast(); } void Workflow_AddModule(GuiResourcePrecompileContext& context, const WString& path, Ptr module, GuiInstanceCompiledWorkflow::AssemblyType assemblyType, GuiResourceTextPos tagPosition) { auto compiled = Workflow_GetModule(context, path); if (!compiled) { compiled = new GuiInstanceCompiledWorkflow; compiled->type = assemblyType; context.targetFolder->CreateValueByPath(path, L"Workflow", compiled); } else { CHECK_ERROR(compiled->type == assemblyType, L"Workflow_AddModule(GuiResourcePrecompiledContext&, const WString&, GuiInstanceCompiledWorkflow::AssemblyType)#Unexpected assembly type."); } if (compiled) { GuiInstanceCompiledWorkflow::ModuleRecord record; record.module = module; record.position = tagPosition; record.shared = assemblyType == GuiInstanceCompiledWorkflow::Shared; compiled->modules.Add(record); } } void Workflow_GenerateAssembly(GuiResourcePrecompileContext& context, const WString& path, GuiResourceError::List& errors, bool keepMetadata) { auto compiled = Workflow_GetModule(context, path); if (!compiled) { return; } if (!compiled->assembly) { List codes; auto manager = Workflow_GetSharedManager(); manager->Clear(false, true); auto addCode = [&codes](TextReader& reader) { vint row = 0; WString code; while (!reader.IsEnd()) { auto rowHeader = itow(++row); while (rowHeader.Length() < 6) { rowHeader = L" " + rowHeader; } code += rowHeader + L" : " + reader.ReadLine() + L"\r\n"; } codes.Add(code); }; for (vint i = 0; i < compiled->modules.Count(); i++) { manager->AddModule(compiled->modules[i].module); } if (manager->errors.Count() == 0) { manager->Rebuild(true); } if (manager->errors.Count() == 0) { compiled->assembly = GenerateAssembly(manager); compiled->Initialize(true); } else { WorkflowVirtualScriptPositionVisitor visitor(context); for (vint i = 0; i < compiled->modules.Count(); i++) { auto module = compiled->modules[i]; visitor.VisitField(module.module.Obj()); Workflow_RecordScriptPosition(context, module.position, module.module); } auto sp = Workflow_GetScriptPosition(context); for (vint i = 0; i < manager->errors.Count(); i++) { auto error = manager->errors[i]; errors.Add({ sp->nodePositions[error->parsingTree].computedPosition, error->errorMessage }); } } if (keepMetadata) { compiled->metadata = Workflow_TransferSharedManager(); } else { manager->Clear(false, true); } } } /*********************************************************************** Shared Script Type Resolver (Script) ***********************************************************************/ #define Path_Shared L"Workflow/Shared" #define Path_TemporaryClass L"Workflow/TemporaryClass" #define Path_InstanceClass L"Workflow/InstanceClass" class GuiResourceSharedScriptTypeResolver : public Object , public IGuiResourceTypeResolver , private IGuiResourceTypeResolver_Precompile , private IGuiResourceTypeResolver_IndirectLoad { public: WString GetType()override { return L"Script"; } bool XmlSerializable()override { return true; } bool StreamSerializable()override { return false; } WString GetPreloadType()override { return L"Xml"; } bool IsDelayLoad()override { return false; } vint GetMaxPassIndex()override { return Workflow_Max; } PassSupport GetPassSupport(vint passIndex)override { switch (passIndex) { case Workflow_Collect: return PerResource; case Workflow_Compile: return PerPass; default: return NotSupported; } } void PerResourcePrecompile(Ptr resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override { switch (context.passIndex) { case Workflow_Collect: { if (auto obj = resource->GetContent().Cast()) { if (obj->language == L"Workflow") { if (auto module = Workflow_ParseModule(context, obj->codePosition.originalLocation, obj->code, obj->codePosition, errors)) { Workflow_AddModule(context, Path_Shared, module, GuiInstanceCompiledWorkflow::Shared, obj->codePosition); } } } } break; } } void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override { switch (context.passIndex) { case Workflow_Compile: Workflow_GenerateAssembly(context, Path_Shared, errors, false); break; } } IGuiResourceTypeResolver_Precompile* Precompile()override { return this; } IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override { return this; } Ptr Serialize(Ptr resource, Ptr content)override { if (auto obj = content.Cast()) { return obj->SaveToXml(); } return nullptr; } Ptr ResolveResource(Ptr resource, Ptr resolver, GuiResourceError::List& errors)override { Ptr xml = resource->GetContent().Cast(); if (xml) { auto schema = GuiInstanceSharedScript::LoadFromXml(resource, xml, errors); return schema; } return 0; } }; /*********************************************************************** Instance Type Resolver (Instance) ***********************************************************************/ class GuiResourceInstanceTypeResolver : public Object , public IGuiResourceTypeResolver , private IGuiResourceTypeResolver_Precompile , private IGuiResourceTypeResolver_IndirectLoad { public: WString GetType()override { return L"Instance"; } bool XmlSerializable()override { return true; } bool StreamSerializable()override { return false; } WString GetPreloadType()override { return L"Xml"; } bool IsDelayLoad()override { return false; } vint GetMaxPassIndex()override { return Instance_Max; } PassSupport GetPassSupport(vint passIndex)override { switch (passIndex) { case Instance_CollectInstanceTypes: case Instance_CollectEventHandlers: case Instance_GenerateInstanceClass: return PerResource; case Instance_CompileInstanceTypes: case Instance_CompileEventHandlers: case Instance_CompileInstanceClass: return PerPass; default: return NotSupported; } } #define ENSURE_ASSEMBLY_EXISTS(PATH)\ if (auto compiled = Workflow_GetModule(context, PATH))\ {\ if (!compiled->assembly)\ {\ break;\ }\ }\ else\ {\ break;\ }\ #define UNLOAD_ASSEMBLY(PATH)\ if (auto compiled = Workflow_GetModule(context, PATH))\ {\ compiled->context = nullptr;\ }\ #define DELETE_ASSEMBLY(PATH)\ if (auto compiled = Workflow_GetModule(context, PATH))\ {\ compiled->context = nullptr;\ compiled->assembly = nullptr;\ }\ void PerResourcePrecompile(Ptr resource, GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override { switch (context.passIndex) { case Instance_CollectEventHandlers: ENSURE_ASSEMBLY_EXISTS(Path_TemporaryClass) case Instance_CollectInstanceTypes: { if (auto obj = resource->GetContent().Cast()) { if (obj->className == L"") { errors.Add(GuiResourceError({ resource }, obj->tagPosition, L"Precompile: Instance \"" + (obj->instance->typeNamespace == GlobalStringKey::Empty ? obj->instance->typeName.ToString() : obj->instance->typeNamespace.ToString() + L":" + obj->instance->typeName.ToString() ) + L"\" should have the class name specified in the ref.Class attribute.")); } obj->ApplyStyles(resource, context.resolver, errors); types::ResolvingResult resolvingResult; resolvingResult.resource = resource; resolvingResult.context = obj; if (auto module = Workflow_GenerateInstanceClass(context, resolvingResult, errors, context.passIndex)) { Workflow_AddModule(context, Path_TemporaryClass, module, GuiInstanceCompiledWorkflow::TemporaryClass, obj->tagPosition); } if (context.passIndex == Instance_CollectInstanceTypes) { auto record = context.targetFolder->GetValueByPath(L"ClassNameRecord").Cast(); if (!record) { record = MakePtr(); context.targetFolder->CreateValueByPath(L"ClassNameRecord", L"ClassNameRecord", record); } record->classNames.Add(obj->className); } } } break; case Instance_GenerateInstanceClass: { ENSURE_ASSEMBLY_EXISTS(Path_TemporaryClass) if (auto obj = resource->GetContent().Cast()) { vint previousErrorCount = errors.Count(); types::ResolvingResult resolvingResult; resolvingResult.resource = resource; resolvingResult.context = obj; resolvingResult.rootTypeInfo = Workflow_CollectReferences(context, resolvingResult, errors); if (errors.Count() == previousErrorCount) { if (auto ctorModule = Workflow_PrecompileInstanceContext(context, resolvingResult, errors)) { if (auto instanceModule = Workflow_GenerateInstanceClass(context, resolvingResult, errors, context.passIndex)) { Workflow_AddModule(context, Path_InstanceClass, ctorModule, GuiInstanceCompiledWorkflow::InstanceClass, obj->tagPosition); Workflow_AddModule(context, Path_InstanceClass, instanceModule, GuiInstanceCompiledWorkflow::InstanceClass, obj->tagPosition); } } } } } break; } } void PerPassPrecompile(GuiResourcePrecompileContext& context, GuiResourceError::List& errors)override { WString path; switch (context.passIndex) { case Instance_CompileInstanceTypes: DELETE_ASSEMBLY(Path_Shared) path = Path_TemporaryClass; break; case Instance_CompileEventHandlers: DELETE_ASSEMBLY(Path_TemporaryClass) path = Path_TemporaryClass; break; case Instance_CompileInstanceClass: UNLOAD_ASSEMBLY(Path_TemporaryClass) path = Path_InstanceClass; break; default: return; } auto sharedCompiled = Workflow_GetModule(context, Path_Shared); auto compiled = Workflow_GetModule(context, path); if (sharedCompiled && compiled) { CopyFrom( compiled->modules, From(sharedCompiled->modules) .Where([](const GuiInstanceCompiledWorkflow::ModuleRecord& module) { return module.shared; }), true ); } switch (context.passIndex) { case Instance_CompileInstanceTypes: Workflow_GenerateAssembly(context, path, errors, false); compiled->modules.Clear(); break; case Instance_CompileEventHandlers: Workflow_GenerateAssembly(context, path, errors, false); break; case Instance_CompileInstanceClass: Workflow_GenerateAssembly(context, path, errors, true); break; default:; } Workflow_ClearScriptPosition(context); GetInstanceLoaderManager()->ClearReflectionCache(); } #undef DELETE_ASSEMBLY #undef UNLOAD_ASSEMBLY #undef ENSURE_ASSEMBLY_EXISTS IGuiResourceTypeResolver_Precompile* Precompile()override { return this; } IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override { return this; } Ptr Serialize(Ptr resource, Ptr content)override { if (auto obj = content.Cast()) { return obj->SaveToXml(); } return 0; } Ptr ResolveResource(Ptr resource, Ptr resolver, GuiResourceError::List& errors)override { Ptr xml = resource->GetContent().Cast(); if (xml) { Ptr context = GuiInstanceContext::LoadFromXml(resource, xml, errors); return context; } return 0; } }; #undef Path_Shared #undef Path_TemporaryClass #undef Path_InstanceClass /*********************************************************************** Instance Style Type Resolver (InstanceStyle) ***********************************************************************/ class GuiResourceInstanceStyleResolver : public Object , public IGuiResourceTypeResolver , private IGuiResourceTypeResolver_IndirectLoad { public: WString GetType()override { return L"InstanceStyle"; } bool XmlSerializable()override { return true; } bool StreamSerializable()override { return false; } WString GetPreloadType()override { return L"Xml"; } bool IsDelayLoad()override { return false; } IGuiResourceTypeResolver_IndirectLoad* IndirectLoad()override { return this; } Ptr Serialize(Ptr resource, Ptr content)override { if (auto obj = content.Cast()) { return obj->SaveToXml(); } return 0; } Ptr ResolveResource(Ptr resource, Ptr resolver, GuiResourceError::List& errors)override { Ptr xml = resource->GetContent().Cast(); if (xml) { auto context = GuiInstanceStyleContext::LoadFromXml(resource, xml, errors); return context; } return 0; } }; /*********************************************************************** Plugin ***********************************************************************/ class GuiCompilerTypeResolversPlugin : public Object, public IGuiPlugin { public: GuiCompilerTypeResolversPlugin() { } void Load()override { } void AfterLoad()override { IGuiResourceResolverManager* manager = GetResourceResolverManager(); manager->SetTypeResolver(new GuiResourceInstanceTypeResolver); manager->SetTypeResolver(new GuiResourceInstanceStyleResolver); manager->SetTypeResolver(new GuiResourceSharedScriptTypeResolver); } void Unload()override { } }; GUI_REGISTER_PLUGIN(GuiCompilerTypeResolversPlugin) } } /*********************************************************************** 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::*"; 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