Commit 304ee90f authored by Bob Obara's avatar Bob Obara Committed by Kitware Robot

Merge topic 'AddingAttributeExclusion'

e295de91 ENH: Adding Exclusion and Required Conditions for Attributes
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: David Thompson's avatarDavid Thompson <david.thompson@kitware.com>
Merge-request: !1452
parents aa2e8239 e295de91
Pipeline #129297 running with stage
#Adding Exclusions and Prerequisites
Attribute Definitions can now provide mechanisms for modeling exclusion and prerequisites constraints. An exclusion constraint prevents an attribute from being associated to same persistent object if another attribute is already associated and its definition excludes the attribute's type. For example, consider two attribute definitions A and B as well as two attributes a (of type A) and b (or type B). If we have specified that A and B excludes each other then if we have associated a to an object, we are prevented from associating b to the same object.
In the case of a prerequisite, an attribute is prevent from being associated if there is not an attribute of an appropriate type associated with the object. So continuing the above example lets assume we add a new definition C that has A as it prerequisite and an attribute c (type C). c can be associated to an object only if a is already associated to it.
In addition, these properties are also inherited. So if we derive type A1 from A in the above example, an attribute a1 (from type A1), would excludes b and would be considered a prerequisite of c.
**NOTE - the exclusion property should be symmetric (if A doesn't allow B then B shouldn't allow A) but the prerequisite property can not be symmetric (else neither could be associated - if you need to have both attributes always assigned together then the information should be modeled as a single definition)**
To implement this, the following was added to Definition:
* Set of excluded definitions
* Set of prerequisite definitions
* Added methods to add and remove definitions - when adding an exclusion, it is done symmetrically. So calling A->addExclusion(B) will result in B being added to A's exclusion set and A being added to B's exclusion's set.
* Added methods for checking association rules, exclusions, and prerequisites
* Added canBeAssociated method for testing persistent objects
* I/O classes can read and write these rules in XML and JSON
In addition, the implementation of isUnique has been changed It now used the exclusion mechanism by inserting
itself into the list. Note that this rule is not written out when serialized or when saved
to a file
The qtAssociationWidget has been modified to use these new ruled when determining availability and qtAttributeView has been modified to test for association rules instead of association masks
See attribute/testing/cxx/unitAttributeAssociationConstraints.cxx for an example.
......@@ -277,25 +277,73 @@ const smtk::resource::ResourcePtr Attribute::resource() const
/**\brief Remove all associations of this attribute with model entities.
*
* Note that this actually resets the associations.
* When dealing with prerequisite constrinats it may not be possible to
* remove all associations. If partialRemovalOk is true, then all
* associations that can be removed all. If false, then associations are
* only removed iff all can be removed.
* Note that this may reset the associations.
* If there are any default associations, they will be present
* but typically there are none.
*/
void Attribute::removeAllAssociations()
bool Attribute::removeAllAssociations(bool partialRemovalOk)
{
if (m_associatedObjects)
if (m_associatedObjects == nullptr)
{
for (auto oit = m_associatedObjects->begin(); oit != m_associatedObjects->end(); ++oit)
return true;
}
// Do we need to worry about prerequisites?
if (m_definition->isUsedAsAPrerequisite())
{
std::vector<smtk::resource::PersistentObjectPtr> objs;
objs = this->associatedObjects<std::vector<smtk::resource::PersistentObjectPtr> >();
bool result = true;
// if we are allowed to remove what we can then disassociate where we can
if (partialRemovalOk)
{
for (auto obj : objs)
{
if (!this->disassociate(obj))
{
result = false;
}
}
if (result)
{
// OK - we have been able to remove all associations,
// so we now need to reset the association item in the
// rare case there are default associations
m_associatedObjects->reset();
}
return result;
}
// We need to precheck all of the objects
AttributePtr probAtt;
for (auto obj : objs)
{
auto modelEnt = dynamic_pointer_cast<smtk::model::Entity>(*oit);
if (modelEnt)
if (!this->canBeDisassociated(obj, probAtt))
{
modelEnt->modelResource()->disassociateAttribute(
nullptr, this->id(), modelEnt->id(), false);
result = false;
}
}
m_associatedObjects->reset();
if (!result)
{
// can not remove all of the associations
return false;
}
}
// If we are here then there are no prerequisite issues to deal with
for (auto oit = m_associatedObjects->begin(); oit != m_associatedObjects->end(); ++oit)
{
auto modelEnt = dynamic_pointer_cast<smtk::model::Entity>(*oit);
if (modelEnt)
{
modelEnt->modelResource()->disassociateAttribute(nullptr, this->id(), modelEnt->id(), false);
}
}
m_associatedObjects->reset();
return true;
}
/**\brief Update attribute when entities has been expunged
......@@ -415,6 +463,8 @@ bool Attribute::associate(smtk::resource::PersistentObjectPtr obj)
return res;
}
// Lets see if we have any conflicts
res = m_associatedObjects ? m_associatedObjects->appendObjectValue(obj) : false;
if (!res)
{
......@@ -523,16 +573,7 @@ void Attribute::disassociateEntity(const smtk::common::UUID& entity, bool revers
auto comp = rsrc->find(entity);
if (comp)
{
this->disassociate(comp);
if (reverse)
{
smtk::model::ResourcePtr modelMgr = std::static_pointer_cast<smtk::model::Resource>(rsrc);
if (modelMgr)
{
modelMgr->disassociateAttribute(this->attributeResource(), this->id(), entity, false);
}
}
this->disassociate(comp, reverse);
}
}
}
......@@ -543,44 +584,105 @@ void Attribute::disassociateEntity(const smtk::common::UUID& entity, bool revers
*/
void Attribute::disassociateEntity(const smtk::model::EntityRef& entity, bool reverse)
{
this->disassociate(entity.component(), reverse);
}
bool Attribute::canBeDisassociated(
smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt) const
{
probAtt = nullptr;
if (!m_associatedObjects)
{
return;
return true; // obj is not associated with the attribute
}
std::ptrdiff_t idx = m_associatedObjects->find(entity.entity());
if (idx >= 0)
auto attRes = this->attributeResource();
if (attRes == nullptr)
{
m_associatedObjects->removeValue(idx);
if (reverse)
// This attribute is not part of a resource so there is nothing to remove
return true;
}
// Is this attribute's definition is not used as a prerequisite
// we can safely remove it
if (!m_definition->isUsedAsAPrerequisite())
{
return true;
}
// Ok we found the object - now will removing the association
// invalidate a prerequisite condition? To determine this do the following:
// 1. Get all of the attributes associated with the object
// 2. For each attribute do the following:
// 2a. See if the attribute has this attribute's type as a prerequisite
// Note that hasPrerequisite returns the required prerequisite def
// 2b. If it does then see how many other attributes associated with the object
// match the type - if there is only one then return false
auto atts = attRes->attributes(obj);
for (auto att : atts)
{
// If the attribite is the same type as this, or it has no
// prerequisites, we can skip it
if ((att->m_definition == m_definition) || (!att->m_definition->hasPrerequisites()))
{
// Don't need to check any atts from the original
// definition
continue;
}
auto preDef = att->m_definition->hasPrerequisite(m_definition);
if (preDef == nullptr)
{
smtk::model::EntityRef mutableEntity(entity);
mutableEntity.disassociateAttribute(this->attributeResource(), this->id(), false);
// Not a prerequisite for this attribute so skip it
continue;
}
// Count number of atts that match the preDef
int count = 0;
for (auto att1 : atts)
{
if (att1->m_definition->isA(preDef))
{
count++;
}
}
if (count == 1)
{
// Can't disassociate the attribute
probAtt = att;
return false;
}
}
return true;
}
void Attribute::disassociate(smtk::resource::PersistentObjectPtr obj, bool reverse)
bool Attribute::disassociate(smtk::resource::PersistentObjectPtr obj, bool reverse)
{
if (!m_associatedObjects)
AttributePtr foo;
return this->disassociate(obj, foo, reverse);
}
bool Attribute::disassociate(
smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt, bool reverse)
{
if (!this->canBeDisassociated(obj, probAtt))
{
return;
return false;
}
std::ptrdiff_t idx = m_associatedObjects->find(obj);
if (idx >= 0)
if (idx < 0)
{
// the obj is not associated with the attribute
return true;
}
m_associatedObjects->removeValue(idx);
if (reverse)
{
m_associatedObjects->removeValue(idx);
if (reverse)
auto modelEnt = std::dynamic_pointer_cast<smtk::model::Entity>(obj);
if (modelEnt)
{
auto modelEnt = std::dynamic_pointer_cast<smtk::model::Entity>(obj);
if (modelEnt)
{
modelEnt->modelResource()->disassociateAttribute(
this->attributeResource(), this->id(), modelEnt->id(), false);
}
modelEnt->modelResource()->disassociateAttribute(
this->attributeResource(), this->id(), modelEnt->id(), false);
}
}
return true;
}
/**\brief Return the item with the given \a inName, searching in the given \a style.
......
......@@ -199,6 +199,7 @@ public:
bool isObjectAssociated(const smtk::common::UUID& uid) const;
bool isObjectAssociated(const smtk::resource::PersistentObjectPtr& componentPtr) const;
bool canBeDisassociated(smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt) const;
ConstReferenceItemPtr associations() const { return m_associatedObjects; }
ReferenceItemPtr associations() { return m_associatedObjects; }
......@@ -218,9 +219,14 @@ public:
void disassociateEntity(const smtk::common::UUID& entity, bool reverse = true);
void disassociateEntity(const smtk::model::EntityRef& entity, bool reverse = true);
void disassociate(smtk::resource::PersistentObjectPtr obj, bool reverse = true);
void removeAllAssociations();
/// Disassociate attribute from an object. Returns true if successful, else
/// it will set probAtt to attribute using this as a prerequisite
bool disassociate(
smtk::resource::PersistentObjectPtr obj, AttributePtr& probAtt, bool reverse = true);
/// Disassociate attribute from an object. Returns true if successful.
bool disassociate(smtk::resource::PersistentObjectPtr obj, bool reverse = true);
bool removeAllAssociations(bool partialRemovalOk = false);
/**
* @brief Remove expunged Entities from attribute
......
......@@ -40,9 +40,9 @@ Item::Type ComponentItemDefinition::type() const
return Item::ComponentType;
}
bool ComponentItemDefinition::isValueValid(smtk::resource::PersistentObjectPtr obj) const
bool ComponentItemDefinition::isValueValid(smtk::resource::ConstPersistentObjectPtr obj) const
{
auto comp = std::dynamic_pointer_cast<smtk::resource::Component>(obj);
auto comp = std::dynamic_pointer_cast<const smtk::resource::Component>(obj);
return this->checkComponent(comp);
}
......
......@@ -38,7 +38,7 @@ public:
Item::Type type() const override;
bool isValueValid(smtk::resource::PersistentObjectPtr value) const override;
bool isValueValid(smtk::resource::ConstPersistentObjectPtr value) const override;
/// Construct an item from the definition given its owning attribute and position.
smtk::attribute::ItemPtr buildItem(Attribute* owningAttribute, int itemPosition) const override;
......
This diff is collapsed.
......@@ -49,6 +49,15 @@ class Resource;
class SMTKCORE_EXPORT Definition : public smtk::enable_shared_from_this<Definition>
{
public:
/// Return types for canBeAssociated method
enum class AssociationResultType
{
Valid, //!< Association is allowed.
Illegal, //!< Association with the given component type is disallowed.
Conflict, //!< An association with a mutually exclusive attribute already exists.
Prerequisite //!< A prerequisite association does not yet exist.
};
smtkTypeMacroBase(smtk::attribute::Definition);
struct SMTKCORE_EXPORT WeakDefinitionPtrCompare
{
......@@ -65,6 +74,7 @@ public:
}
};
typedef std::set<WeakDefinitionPtr, WeakDefinitionPtrCompare> WeakDefinitionSet;
virtual ~Definition();
// Description:
......@@ -135,15 +145,13 @@ public:
int advanceLevel() const { return m_advanceLevel; }
void setAdvanceLevel(int level) { m_advanceLevel = level; }
// Indicates if a model entity can have multiple attributes of this
// type associated with it
// Indicates if a persistent object can have multiple attributes of this
// type associated with it (true means it can not)
bool isUnique() const { return m_isUnique; }
// Be careful with setting isUnique to be false
// in order to be consistant all definitions that this is
// a descendant of should also have isUnique set to false!!
// isUnique can be set to true without requiring its parent
// class to also be true.
void setIsUnique(bool isUniqueValue) { m_isUnique = isUniqueValue; }
// Setting isUnique to be true indicates that only one attribute of this
// defintion (or any definition derived from this) can be associated to a
// persistent object.
void setIsUnique(bool isUniqueValue);
// Indicates if the attribute applies to the
// nodes of the analysis mesh
......@@ -216,8 +224,26 @@ public:
bool associatesWithGroup() const;
bool canBeAssociated(smtk::model::BitFlags maskType) const;
bool canBeAssociated(
smtk::model::EntityRef entity, std::vector<smtk::attribute::Attribute*>* conflicts) const;
// Tests to see if attributes based on this definition can be
// associated with a persistent object - see the documentation
// for AssociationResultType for details on return values.
// If a conflict is found, conflictAtt is set to the conflicting attibute
// If a prerequisite is missing, prerequisiteDef is set to the
// missing requirement
// NOTE - testing is completed once a problem has been detected. There maybe be
// other issues preventing association so this method may need be called multiple
// times
AssociationResultType canBeAssociated(smtk::resource::ConstPersistentObjectPtr object,
AttributePtr& conflictAtt, DefinitionPtr& prerequisiteDef) const;
// Check the association rules of the definition (and the definiion it derived from)
// to see if the object can be associated
bool checkAssociationRules(smtk::resource::ConstPersistentObjectPtr object) const;
// Test to see if there is a conflict between this definition and attributes
// already associated to the object. Returns the conflicting attribute if there is a conflict
AttributePtr checkForConflicts(smtk::resource::ConstPersistentObjectPtr object) const;
// Test to see if there is a missing prerequisite attribute that would prevent attributes of
// this type from being associated to the object. Returns the missing prerequisite definition
DefinitionPtr checkForPrerequisites(smtk::resource::ConstPersistentObjectPtr object) const;
// Return all of the attributes associated with object that are derived from this definition
std::set<AttributePtr> attributes(const smtk::resource::ConstPersistentObjectPtr& object) const;
......@@ -302,6 +328,40 @@ public:
std::size_t includeIndex() const { return m_includeIndex; }
// Since Exclusion Constraints are symmetric this method will
// also insert this "definiton" into def
void addExclusion(smtk::attribute::DefinitionPtr def)
{
m_exclusionDefs.insert(def);
def->m_exclusionDefs.insert(this->shared_from_this());
}
// Since Exclusion Constriants are symmetric this method will also remove
// this "definition" from def
void removeExclusion(smtk::attribute::DefinitionPtr def);
const WeakDefinitionSet exclusions() const { return m_exclusionDefs; }
// Return a list of sorted type names that exlude this type of
// attribute
std::vector<std::string> excludedTypeNames() const;
void addPrerequisite(smtk::attribute::DefinitionPtr def);
/// Returns true if the definition is used as a prerequisite
bool isUsedAsAPrerequisite() const;
void removePrerequisite(smtk::attribute::DefinitionPtr def);
const WeakDefinitionSet prerequisites() const { return m_prerequisiteDefs; }
// Return a sort of list of type names that are prerequisite to the type
// of attribute
std::vector<std::string> prerequisiteTypeNames() const;
// Return nullptr if def is not a prerequisite of this Definition else
// return the prerequisite definition that def is derived from
smtk::attribute::ConstDefinitionPtr hasPrerequisite(
smtk::attribute::ConstDefinitionPtr def) const;
/// Returns true if the definition has prerequisites (which can be inherited)
bool hasPrerequisites() const;
protected:
friend class smtk::attribute::Resource;
// AttributeDefinitions can only be created by an attribute resource
......@@ -325,12 +385,15 @@ protected:
bool m_isNodal;
std::set<std::string> m_categories;
int m_advanceLevel;
WeakDefinitionSet m_exclusionDefs;
WeakDefinitionSet m_prerequisiteDefs;
/// Used to keep track of how many definitions are using this one as a prerequisite
size_t m_prerequisiteUsageCount;
std::vector<smtk::attribute::ItemDefinitionPtr> m_itemDefs;
std::map<std::string, int> m_itemDefPositions;
//Is Unique indicates if more than one attribute of this type can be assigned to a
// model entity - NOTE This can be inherited meaning that if the definition's Super definition
// has isUnique = true it will also prevent an attribute from this definition being assigned if the
// targeted model entity has an attribute derived from the Super Definition
// model entity - this constraint is implimented by using adding the definition itself
// into its exclusion list
bool m_isUnique;
bool m_isRequired;
bool m_isNotApplicableColorSet;
......
......@@ -68,7 +68,7 @@ bool ReferenceItemDefinition::setAcceptsEntries(
}
}
bool ReferenceItemDefinition::isValueValid(PersistentObjectPtr entity) const
bool ReferenceItemDefinition::isValueValid(resource::ConstPersistentObjectPtr entity) const
{
bool ok = false;
if (!entity)
......@@ -76,13 +76,13 @@ bool ReferenceItemDefinition::isValueValid(PersistentObjectPtr entity) const
return ok;
}
smtk::resource::ResourcePtr rsrc;
smtk::resource::ComponentPtr comp;
if ((rsrc = std::dynamic_pointer_cast<smtk::resource::Resource>(entity)))
smtk::resource::ConstResourcePtr rsrc;
smtk::resource::ConstComponentPtr comp;
if ((rsrc = std::dynamic_pointer_cast<const smtk::resource::Resource>(entity)))
{
ok = this->checkResource(rsrc);
}
else if ((comp = std::dynamic_pointer_cast<smtk::resource::Component>(entity)))
else if ((comp = std::dynamic_pointer_cast<const smtk::resource::Component>(entity)))
{
ok = this->checkComponent(comp);
}
......@@ -209,7 +209,7 @@ void ReferenceItemDefinition::copyTo(Ptr dest) const
}
}
bool ReferenceItemDefinition::checkResource(smtk::resource::ResourcePtr rsrc) const
bool ReferenceItemDefinition::checkResource(smtk::resource::ConstResourcePtr rsrc) const
{
// If the resource is invalid, then no filtering is needed.
if (!rsrc)
......@@ -244,7 +244,7 @@ bool ReferenceItemDefinition::checkResource(smtk::resource::ResourcePtr rsrc) co
return false;
}
bool ReferenceItemDefinition::checkComponent(smtk::resource::ComponentPtr comp) const
bool ReferenceItemDefinition::checkComponent(smtk::resource::ConstComponentPtr comp) const
{
// If the component is invalid, then no filtering is needed.
if (!comp)
......
......@@ -57,7 +57,7 @@ public:
virtual bool setAcceptsEntries(
const std::string& typeName, const std::string& queryString, bool accept);
virtual bool isValueValid(PersistentObjectPtr entity) const;
virtual bool isValueValid(resource::ConstPersistentObjectPtr entity) const;
/// Return the number of values required by this definition.
std::size_t numberOfRequiredValues() const;
......@@ -109,9 +109,9 @@ protected:
void copyTo(Ptr dst) const;
/// Return whether a resource is accepted by this definition. Used internally by isValueValid().
bool checkResource(smtk::resource::ResourcePtr rsrc) const;
bool checkResource(smtk::resource::ConstResourcePtr rsrc) const;
/// Return whether a component is accepted by this definition. Used internally by isValueValid().
bool checkComponent(smtk::resource::ComponentPtr comp) const;
bool checkComponent(smtk::resource::ConstComponentPtr comp) const;
/// Set the reference's role when generating links between the containing
/// attribute and the reference item. By default, this value is set to
......
......@@ -196,17 +196,31 @@ smtk::attribute::AttributePtr Resource::createAttribute(
return att;
}
void Resource::definitions(std::vector<smtk::attribute::DefinitionPtr>& result) const
void Resource::definitions(std::vector<smtk::attribute::DefinitionPtr>& result, bool sortList) const
{
std::map<std::string, DefinitionPtr>::const_iterator it;
result.resize(m_definitions.size());
int i;
for (it = m_definitions.begin(), i = 0; it != m_definitions.end(); it++, i++)
if (!sortList)
{
result[i] = it->second;
std::map<std::string, DefinitionPtr>::const_iterator it;
for (it = m_definitions.begin(), i = 0; it != m_definitions.end(); it++, i++)
{
result[i] = it->second;
}
return;
}
std::vector<std::string> keys;
for (auto info : m_definitions)
{
keys.push_back(info.first);
}
std::sort(keys.begin(), keys.end());
std::vector<std::string>::const_iterator kit;
for (kit = keys.begin(), i = 0; kit != keys.end(); kit++, i++)
{
result[i] = m_definitions.at(*(kit));
}
}
void Resource::attributes(std::vector<smtk::attribute::AttributePtr>& result) const
{
std::map<std::string, AttributePtr>::const_iterator it;
......@@ -267,6 +281,11 @@ bool Resource::removeAttribute(smtk::attribute::AttributePtr att)
{
return false;
}
if (!att->removeAllAssociations(false))
{
return false;
}
m_attributes.erase(att->name());
m_attributeIdMap.erase(att->id());
m_attributeClusters[att->type()].erase(att);
......@@ -465,7 +484,7 @@ void Resource::derivedDefinitions(
}
smtk::attribute::ConstDefinitionPtr Resource::findIsUniqueBaseClass(
smtk::attribute::DefinitionPtr attDef) const
smtk::attribute::ConstDefinitionPtr attDef) const
{
// If there is no definition or the definition is not
// unique then return an empty shared pointer
......@@ -481,7 +500,7 @@ smtk::attribute::ConstDefinitionPtr Resource::findIsUniqueBaseClass(
}
// Keep traveling up the definition's ancestors until
// we come to the end or we find one that isn't unique
smtk::attribute::DefinitionPtr uDef = attDef, def;
smtk::attribute::ConstDefinitionPtr uDef = attDef, def;
while (1 && uDef.get())
{
def = uDef->baseDefinition();
......@@ -891,12 +910,12 @@ smtk::resource::ComponentPtr Resource::find(const smtk::common::UUID& attId) con
return this->findAttribute(attId);
}
std::function<bool(const smtk::resource::ComponentPtr&)> Resource::queryOperation(
std::function<bool(const smtk::resource::ConstComponentPtr&)> Resource::queryOperation(
const std::string& filter) const
{
if (filter.empty() || filter == "any" || filter == "*")
{
return [](const smtk::resource::ComponentPtr&) { return true; };
return [](const smtk::resource::ConstComponentPtr&) { return true; };
}
const std::string attributeFilter("attribute");
if (!filter.compare(0, attributeFilter.size(), attributeFilter))
......@@ -911,14 +930,14 @@ std::function<bool(const smtk::resource::ComponentPtr&)> Resource::queryOperatio
smtk::attribute::DefinitionPtr defn = this->findDefinition(sdef);
if (defn)
{
return [defn](const smtk::resource::ComponentPtr& comp) {
auto attr = std::dynamic_pointer_cast<Attribute>(comp);
return [defn](const smtk::resource::ConstComponentPtr& comp) {
auto attr = std::dynamic_pointer_cast<const Attribute>(comp);
return (attr && attr->isA(defn));
};
}
}
}
return [](const smtk::resource::ComponentPtr&) { return false; };
return [](const smtk::resource::ConstComponentPtr&) { return false; };
}
// visit all components in the resource.
......
......@@ -112,7 +112,7 @@ public:
* the definition must exist at the time that queryOperation() is called.
* This requirement allows faster repeated evaluation of the query.
*/
std::function<bool(const smtk::resource::ComponentPtr&)> queryOperation(
std::function<bool(const smtk::resource::ConstComponentPtr&)> queryOperation(
const std::string&) const override;
// visit all components in the resource.
......@@ -140,7 +140,7 @@ public:
unsigned long mask, std::vector<smtk::attribute::DefinitionPtr>& result) const;
smtk::attribute::ConstDefinitionPtr findIsUniqueBaseClass(
smtk::attribute::DefinitionPtr attDef) const;
smtk::attribute::ConstDefinitionPtr attDef) const;
bool rename(AttributePtr att, const std::string& newName);
bool defineAnalysis(const std::string& analysisName, const std::set<std::string>& categories);
......@@ -204,7 +204,8 @@ public:
const bool& copyModelAssociations = false, const unsigned int& options = 0);
//Get a list of all definitions in the Resource
void definitions(std::vector<smtk::attribute::DefinitionPtr>& result) const;
void definitions(
std::vector<smtk::attribute::DefinitionPtr>& result, bool sortList = false) const;
//Get a list of all attributes in the Resource
void attributes(std::vector<smtk::attribute::AttributePtr>& result) const;
......
......@@ -35,9 +35,9 @@ Item::Type ResourceItemDefinition::type() const
return Item::ResourceType;
}
bool ResourceItemDefinition::isValueValid(smtk::resource::PersistentObjectPtr obj) const
bool ResourceItemDefinition::isValueValid(smtk::resource::ConstPersistentObjectPtr obj) const
{
auto rsrc = std::dynamic_pointer_cast<smtk::resource::Resource>(obj);
auto rsrc = std::dynamic_pointer_cast<const smtk::resource::Resource>(obj);
return this->checkResource(rsrc);
}
......
......@@ -39,7 +39,7 @@ public:
Item::Type type() const override;
bool isValueValid(smtk::resource::PersistentObjectPtr value) const override;
bool isValueValid(smtk::resource::ConstPersistentObjectPtr value) const override;
/// Construct an item from the definition given its owning attribute and position.
smtk::attribute::ItemPtr buildItem(Attribute* owningAttribute, int itemPosition) const override;
......
......@@ -82,6 +82,9 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
res->findBaseDefinitions(baseDefPtrs);
json defsObj = json::array();
json attsObj = json::array();
json excsObj = json::array();
json presObj = json::array();
std::queue<smtk::attribute::DefinitionPtr, std::deque<smtk::attribute::DefinitionPtr> > defsQueue(
std::deque<smtk::attribute::DefinitionPtr>(baseDefPtrs.begin(), baseDefPtrs.end()));
while (!defsQueue.empty())
......@@ -105,6 +108,54 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
}
}
j["Definitions"] = defsObj;
// Process Exceptions and Prerequistics
std::vector<smtk::attribute::DefinitionPtr> defs;
res->definitions(defs, true);
for (auto def : defs)
{
auto defType = def->type();
// Lets process the constraints of def
auto excludedTypes = def->excludedTypeNames();
if (excludedTypes.size())
{
json types = json::array();
for (auto etype : excludedTypes)
{
if (etype > defType)
{
types.push_back(defType);
types.push_back(etype);
}
}
if (types.size())