diff --git a/data/scene/mercury/mercury.mod b/data/scene/mercury/mercury.mod index aa4be9675d..7902252625 100644 --- a/data/scene/mercury/mercury.mod +++ b/data/scene/mercury/mercury.mod @@ -62,7 +62,8 @@ return { }, Color = {0.6, 0.5, 0.5 }, Period = 87.968, - Resolution = 100 + Resolution = 100, + Tag = "defaultTrails" } } } diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 8cca565ef7..1db90523fe 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -328,20 +328,6 @@ public: */ const ghoul::Dictionary& metaData() const; - /** - * Returns a list of all tags that have been assigned to the Property. Useful for - * trying to find a match for a desired batch operation on Properties. - * \return Pointer to vector of string tags that were assigned to the Property - */ - const std::vector* getTags(void) const; - - /** - * Adds a tag to the Property's list of assigned tags. Tags are useful for creating - * groups of Properties that can be used in batch operations. - * \param tag The string that is to be assigned to the Property - */ - void addTag(std::string tag); - protected: static const char* IdentifierKey; static const char* NameKey; @@ -398,8 +384,6 @@ protected: /// The callback function that will be invoked whenever the encapsulated value changes std::function _onChangeCallback; - /// Collection of string tag(s) assigned to this property - std::vector _tags; }; } // namespace properties diff --git a/include/openspace/properties/propertyowner.h b/include/openspace/properties/propertyowner.h index e26af2db6f..aa5f138faf 100644 --- a/include/openspace/properties/propertyowner.h +++ b/include/openspace/properties/propertyowner.h @@ -207,6 +207,20 @@ public: /// \see PropertyOwner::removePropertySubOwner(PropertyOwner*) void removePropertySubOwner(PropertyOwner& owner); + /** + * Returns a list of all tags that have been assigned to the Property. Useful for + * trying to find a match for a desired batch operation on Properties. + * \return Pointer to vector of string tags that were assigned to the Property + */ + const std::vector* getTags(void) const; + + /** + * Adds a tag to the Property's list of assigned tags. Tags are useful for creating + * groups of Properties that can be used in batch operations. + * \param tag The string that is to be assigned to the Property + */ + void addTag(std::string tag); + private: /// The name of this PropertyOwner std::string _name; @@ -218,6 +232,8 @@ private: std::vector _subOwners; /// The associations between group identifiers of Property's and human-readable names std::map _groupNames; + /// Collection of string tag(s) assigned to this property + std::vector _tags; }; } // namespace properties diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 1acce2442e..dd1310625d 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -59,6 +59,7 @@ public: static const std::string KeyName; static const std::string KeyParentName; static const std::string KeyDependencies; + static const std::string KeyTag; SceneGraphNode(); ~SceneGraphNode(); diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 06bf067281..c7cb5ddd44 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -211,14 +211,5 @@ std::string Property::generateAdditionalDescription() const { return ""; } -const std::vector* Property::getTags(void) const { - return &_tags; -} - -void Property::addTag(std::string tag) { - _tags.push_back(tag); -} - - } // namespace properties } // namespace openspace diff --git a/src/properties/propertyowner.cpp b/src/properties/propertyowner.cpp index e45cd9279f..373e2a8da4 100644 --- a/src/properties/propertyowner.cpp +++ b/src/properties/propertyowner.cpp @@ -324,5 +324,13 @@ const std::string& PropertyOwner::name() const { return _name; } +const std::vector* PropertyOwner::getTags(void) const { + return &_tags; +} + +void PropertyOwner::addTag(std::string tag) { + _tags.push_back(tag); +} + } // namespace properties } // namespace openspace diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index aed03d9479..44fbd504d6 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -675,29 +675,30 @@ scripting::LuaLibrary Scene::luaLibrary() { { "setPropertyGroup", &luascriptfunctions::property_setGroup, - "string, string, *", + "string, *", "Sets all properties that belong to a tagged group AND match the " - "URI (with optional wildcards) in the first argument. Second argument is " - "the tag name to match. The third argument can be any type, but it has to " - "match tye type that the property expects.", + "URI (with optional wildcards) in the first argument (group tag name is " + "given in place of property owner name). The second argument can be any " + "type, but it has to match the type that the property expects.", }, { "setPropertyGroupSingle", &luascriptfunctions::property_setGroupSingle, - "string, string, *", + "string, *", "Sets all properties that belong to a tagged group AND match the " - "URI (requires exact match) in the first argument. Second argument is " - "the tag name to match. The third argument can be any type, but it has to " - "match tye type that the property expects.", + "URI (requires exact match) in the first argument (group tag name is " + "given in place of property owner name). The second argument can be any " + "type, but it has to match the type that the property expects.", }, { "setPropertyGroupRegex", &luascriptfunctions::property_setGroupRegex, - "string, string, *", + "string, *", "Sets all properties that belong to a tagged group AND match the " - "URI regex in the first argument. Second argument is the tag name to" - "match. The third argument can be any type, but it has to match the " - "type that the property expects.", + "URI (allows regular expression syntax) in the first argument " + "(group tag name is given in place of property owner name). The second " + "argument can be any type, but it has to match the type that the " + "property expects.", }, { "getPropertyValue", diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index e0f97421d9..023001dc4a 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -73,6 +73,38 @@ void applyRegularExpression(lua_State* L, std::regex regex, } } } + +std::string extractGroupNameFromUri(std::string command) { + return command.substr(0, command.find_first_of(".")); +} + +template +PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop, + const std::string tagToMatch) { + PropertyOwner* tagMatchOwner = nullptr; + PropertyOwner* owner = prop->owner(); + + if (owner != nullptr) { + std::vector* tags = owner->getTags(); + for (currTag : tags) { + if (currTag == tagToMatch) { + tagMatchOwner = owner; + break; + } + } + + //Call recursively until we find an owner with matching tag or the top of the + // ownership list + if (tagMatchOwner == nullptr) + tagMatchOwner = findPropertyOwnerWithMatchingGroupTag(owner, tagToMatch); + } + return tagMatchOwner; +} + +std::string replaceUriGroupNameWith(std::string uri, std::string ownerName) { + size_t pos = uri.find_first_of("."); + return ownerName + "." + uri.substr(pos); +} } @@ -190,10 +222,11 @@ int property_setValue(lua_State* L) { /** * \ingroup LuaScripts - * setPropertyGroupSingle(string, string, *): - * Sets all properties identified by the URI (requires exact match) in the first - * argument, AND contain a tag that matches that given in the second argument. The third - * argument can be any type, but it has to match the type that the property(s) expect. + * setPropertyGroupSingle(string, *): + * Sets all properties that belong to a tagged group AND match the URI (requires exact + * match) in the first argument (group tag name is given in place of property owner + * name). The second argument can be any type, but it has to match the type that the + * property expects. */ int property_setGroupSingle(lua_State* L) { using ghoul::lua::errorLocation; @@ -202,19 +235,16 @@ int property_setGroupSingle(lua_State* L) { int nArguments = lua_gettop(L); SCRIPT_CHECK_ARGUMENTS("property_setGroupSingle", L, 2, nArguments); - std::string uri = luaL_checkstring(L, -3); - std::string tagToMatch = luaL_checkstring(L, -2); + std::string uri = luaL_checkstring(L, -2); const int type = lua_type(L, -1); - - properties::Property* prop = property(uri); - if (!prop) { - LERRORC("property_setValue", errorLocation(L) << "Property with URI '" - << uri << "' was not found"); - return 0; - } - - for (std::string tagEvaluate : *prop->getTags()) { - if (tagEvaluate.compare(tagToMatch) == 0) { + std::string tagToMatch = extractGroupNameFromUri(uri); + + for (properties::Property* prop : allProperties()) { + //std::string id = prop->fullyQualifiedIdentifier(); + PropertyOwner* matchingTaggedOwner = findPropertyOwnerWithMatchingGroupTag(prop, + tagToMatch); + if (matchingTaggedOwner != nullptr) { + uri = replaceUriGroupNameWith(uri, matchingTaggedOwner.name()); if (type != prop->typeLua()) { LERRORC("property_setValue", errorLocation(L) << "Property '" << prop->guiName() << "' does not accept input of type '" @@ -239,10 +269,11 @@ int property_setGroupSingle(lua_State* L) { /** * \ingroup LuaScripts - * setPropertyGroup(string, string, *): - * Sets all properties identified by the URI (with potential wildcards) in the first - * argument, AND contain a tag that matches that given in the second argument. The third - * argument can be any type, but it has to match the type that the property(s) expect. + * setPropertyGroup(string, *): + * Sets all properties that belong to a tagged group AND match the URI (with optional + * wildcards) in the first argument (group tag name is given in place of property owner + * name). The second argument can be any type, but it has to match the type that the + * property expects. */ int property_setGroup(lua_State* L) { @@ -250,10 +281,9 @@ int property_setGroup(lua_State* L) { using ghoul::lua::luaTypeToString; int nArguments = lua_gettop(L); - SCRIPT_CHECK_ARGUMENTS("property_setGroup", L, 3, nArguments); + SCRIPT_CHECK_ARGUMENTS("property_setGroup", L, 2, nArguments); - std::string tag = luaL_checkstring(L, -2); - std::string regex = luaL_checkstring(L, -3); + std::string regex = luaL_checkstring(L, -2); // Replace all wildcards * with the correct regex (.*) size_t startPos = regex.find("*"); @@ -277,9 +307,10 @@ int property_setGroup(lua_State* L) { /** * \ingroup LuaScripts * setPropertyGroupRegex(string, *): - * Sets all properties that pass the regular expression in the first argument. The second - * argument can be any type, but it has to match the type of the properties that matched - * the regular expression. The regular expression has to be of the ECMAScript grammar. + * Sets all properties that belong to a tagged group AND match the URI (allows regular + * expression syntax) in the first argument (group tag name is given in place of property + * owner name). The second argument can be any type, but it has to match the type that + * the property expects. */ int property_setGroupRegex(lua_State* L) { using ghoul::lua::errorLocation; @@ -288,8 +319,7 @@ int property_setGroupRegex(lua_State* L) { int nArguments = lua_gettop(L); SCRIPT_CHECK_ARGUMENTS("property_setGroupRegex<", L, 2, nArguments); - std::string regex = luaL_checkstring(L, -3); - std::string tag = luaL_checkstring(L, -2); + std::string regex = luaL_checkstring(L, -2); try { applyRegularExpression( L, diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index d19effd97b..a039c20a07 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -64,6 +64,7 @@ const std::string SceneGraphNode::RootNodeName = "Root"; const std::string SceneGraphNode::KeyName = "Name"; const std::string SceneGraphNode::KeyParentName = "Parent"; const std::string SceneGraphNode::KeyDependencies = "Dependencies"; +const std::string SceneGraphNode::KeyTag = "Tag"; SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){ openspace::documentation::testSpecificationAndThrow( @@ -139,6 +140,13 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di LDEBUG("Successfully created scale for '" << result->name() << "'"); } + if (dictionary.hasKey(KeyTag)) { + std::string tagString; + dictionary.getValue(KeyTag, tagString); + result->addTag(tagString); + LDEBUG("Successfully added tag for '" << result->name() << "'"); + } + LDEBUG("Successfully created SceneGraphNode '" << result->name() << "'"); return result;