mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-07 20:21:24 -06:00
292 lines
11 KiB
C++
292 lines
11 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2015 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
#include <openspace/properties/propertyowner.h>
|
|
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
|
|
namespace openspace {
|
|
namespace properties {
|
|
|
|
namespace {
|
|
const std::string _loggerCat = "PropertyOwner";
|
|
|
|
bool propertyLess(Property* lhs, Property* rhs)
|
|
{
|
|
return lhs->identifier() < rhs->identifier();
|
|
}
|
|
|
|
bool subOwnerLess(PropertyOwner* lhs, PropertyOwner* rhs) {
|
|
return lhs->name() < rhs->name();
|
|
}
|
|
|
|
}
|
|
|
|
PropertyOwner::PropertyOwner()
|
|
: _name("")
|
|
, _owner(nullptr)
|
|
{
|
|
}
|
|
|
|
PropertyOwner::~PropertyOwner() {
|
|
_properties.clear();
|
|
_subOwners.clear();
|
|
}
|
|
|
|
const std::vector<Property*>& PropertyOwner::properties() const {
|
|
return _properties;
|
|
}
|
|
|
|
std::vector<Property*> PropertyOwner::propertiesRecursive() const {
|
|
std::vector<Property*> props = properties();
|
|
|
|
for (const PropertyOwner* owner : _subOwners) {
|
|
std::vector<Property*> p = owner->propertiesRecursive();
|
|
props.insert(props.end(), p.begin(), p.end());
|
|
}
|
|
|
|
return props;
|
|
}
|
|
|
|
Property* PropertyOwner::property(const std::string& id) const {
|
|
assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess));
|
|
|
|
// As the _properties list is sorted, just finding the lower bound is sufficient
|
|
std::vector<Property*>::const_iterator it
|
|
= std::lower_bound(_properties.begin(), _properties.end(), id,
|
|
[](Property* prop, const std::string& str) {
|
|
return prop->identifier() < str;
|
|
});
|
|
|
|
if (it == _properties.end() || (*it)->identifier() != id) {
|
|
// if we do not own the searched property, it must consist of a concatenated
|
|
// name and we can delegate it to a subowner
|
|
const size_t ownerSeparator = id.find(URISeparator);
|
|
if (ownerSeparator == std::string::npos) {
|
|
// if we do not own the property and there is no separator, it does not exist
|
|
return nullptr;
|
|
}
|
|
else {
|
|
const std::string ownerName = id.substr(0, ownerSeparator);
|
|
const std::string propertyName = id.substr(ownerSeparator + 1);
|
|
|
|
PropertyOwner* owner = propertySubOwner(ownerName);
|
|
if (owner == nullptr) {
|
|
return nullptr;
|
|
}
|
|
else {
|
|
// Recurse into the subOwner
|
|
return owner->property(propertyName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return *it;
|
|
}
|
|
|
|
bool PropertyOwner::hasProperty(const std::string& id) const {
|
|
return property(id) != nullptr;
|
|
}
|
|
|
|
const std::vector<PropertyOwner*>& PropertyOwner::propertySubOwners() const {
|
|
return _subOwners;
|
|
}
|
|
|
|
PropertyOwner* PropertyOwner::propertySubOwner(const std::string& name) const {
|
|
assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess));
|
|
|
|
// As the _subOwners list is sorted, getting the lower bound is sufficient
|
|
std::vector<PropertyOwner*>::const_iterator it
|
|
= std::lower_bound(_subOwners.begin(), _subOwners.end(), name,
|
|
[](PropertyOwner* owner, const std::string& str) {
|
|
return owner->name() < str;
|
|
});
|
|
|
|
if (it == _subOwners.end() || (*it)->name() != name)
|
|
return nullptr;
|
|
else
|
|
return *it;
|
|
}
|
|
|
|
bool PropertyOwner::hasPropertySubOwner(const std::string& name) const {
|
|
return propertySubOwner(name) != nullptr;
|
|
}
|
|
|
|
void PropertyOwner::setPropertyGroupName(std::string groupID, std::string name) {
|
|
_groupNames[std::move(groupID)] = std::move(name);
|
|
}
|
|
|
|
const std::string& PropertyOwner::propertyGroupName(const std::string& groupID) const {
|
|
auto it = _groupNames.find(groupID);
|
|
if (it == _groupNames.end())
|
|
return groupID;
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
void PropertyOwner::addProperty(Property* prop)
|
|
{
|
|
assert(prop != nullptr);
|
|
assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess));
|
|
assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess));
|
|
|
|
if (prop->identifier().empty()) {
|
|
LERROR("No property identifier specified");
|
|
return;
|
|
}
|
|
|
|
// See if we can find the identifier of the property to add in the properties list
|
|
// The _properties list is sorted, so getting the lower bound is sufficient
|
|
std::vector<Property*>::iterator it
|
|
= std::lower_bound(_properties.begin(), _properties.end(), prop->identifier(),
|
|
[](Property* prop, const std::string& str) {
|
|
return prop->identifier() < str;
|
|
});
|
|
|
|
// If we found the property identifier, we need to bail out
|
|
if (it != _properties.end() && (*it)->identifier() == prop->identifier()) {
|
|
LERROR("Property identifier '" << prop->identifier()
|
|
<< "' already present in PropertyOwner '"
|
|
<< name() << "'");
|
|
return;
|
|
} else {
|
|
// Otherwise we still have to look if there is a PropertyOwner with the same name
|
|
const bool hasOwner = hasPropertySubOwner(prop->identifier());
|
|
if (hasOwner) {
|
|
LERROR("Property identifier '" << prop->identifier() << "' already names a"
|
|
<< "registed PropertyOwner");
|
|
return;
|
|
}
|
|
else {
|
|
// now have found the correct position to add it in
|
|
_properties.insert(it, prop);
|
|
prop->setPropertyOwner(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PropertyOwner::addProperty(Property& prop) {
|
|
addProperty(&prop);
|
|
}
|
|
|
|
void PropertyOwner::addPropertySubOwner(openspace::properties::PropertyOwner* owner) {
|
|
assert(owner != nullptr);
|
|
assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess));
|
|
assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess));
|
|
|
|
if (owner->name().empty()) {
|
|
LERROR("PropertyOwner did not have a name");
|
|
return;
|
|
}
|
|
|
|
// See if we can find the name of the propertyowner to add using the lower bound
|
|
std::vector<PropertyOwner*>::iterator it
|
|
= std::lower_bound(_subOwners.begin(), _subOwners.end(), owner->name(),
|
|
[](PropertyOwner* owner, const std::string& str) {
|
|
return owner->name() < str;
|
|
});
|
|
|
|
// If we found the propertyowner's name, we need to bail out
|
|
if (it != _subOwners.end() && (*it)->name() == owner->name()) {
|
|
LERROR("PropertyOwner '" << owner->name()
|
|
<< "' already present in PropertyOwner '" << name() << "'");
|
|
return;
|
|
} else {
|
|
// We still need to check if the PropertyOwners name is used in a Property
|
|
const bool hasProp = hasProperty(owner->name());
|
|
if (hasProp) {
|
|
LERROR("PropertyOwner '" << owner->name() << "'s name already names a "
|
|
<< "Property");
|
|
return;
|
|
}
|
|
else {
|
|
// Otherwise we have found the correct position to add it in
|
|
_subOwners.insert(it, owner);
|
|
owner->setPropertyOwner(this);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void PropertyOwner::addPropertySubOwner(openspace::properties::PropertyOwner& owner) {
|
|
addPropertySubOwner(&owner);
|
|
}
|
|
|
|
void PropertyOwner::removeProperty(Property* prop) {
|
|
assert(prop != nullptr);
|
|
|
|
// See if we can find the identifier of the property to add in the properties list
|
|
std::vector<Property*>::iterator it
|
|
= std::lower_bound(_properties.begin(), _properties.end(), prop->identifier(),
|
|
[](Property* prop, const std::string& str) {
|
|
return prop->identifier() < str;
|
|
});
|
|
|
|
// If we found the property identifier, we can delete it
|
|
if (it != _properties.end() && (*it)->identifier() == prop->identifier()) {
|
|
(*it)->setPropertyOwner(nullptr);
|
|
_properties.erase(it);
|
|
} else
|
|
LERROR("Property with identifier '" << prop->identifier()
|
|
<< "' not found for removal.");
|
|
}
|
|
|
|
void PropertyOwner::removeProperty(Property& prop) {
|
|
removeProperty(&prop);
|
|
}
|
|
|
|
void PropertyOwner::removePropertySubOwner(openspace::properties::PropertyOwner* owner) {
|
|
assert(owner != nullptr);
|
|
|
|
// See if we can find the name of the propertyowner to add
|
|
std::vector<PropertyOwner*>::iterator it
|
|
= std::lower_bound(_subOwners.begin(), _subOwners.end(), owner->name(),
|
|
[](PropertyOwner* owner, const std::string& str) {
|
|
return owner->name() < str;
|
|
});
|
|
|
|
// If we found the propertyowner, we can delete it
|
|
if (it != _subOwners.end() && (*it)->name() == owner->name()) {
|
|
_subOwners.erase(it);
|
|
} else
|
|
LERROR("PropertyOwner with name '" << owner->name()
|
|
<< "' not found for removal.");
|
|
}
|
|
|
|
void PropertyOwner::removePropertySubOwner(openspace::properties::PropertyOwner& owner) {
|
|
removePropertySubOwner(&owner);
|
|
}
|
|
|
|
void PropertyOwner::setName(std::string name) {
|
|
_name = std::move(name);
|
|
}
|
|
|
|
const std::string& PropertyOwner::name() const {
|
|
return _name;
|
|
}
|
|
|
|
} // namespace properties
|
|
} // namespace openspace
|