Issue #2389: ObjectIdentifiers constructed from a property sometimes do not

resolve correctly, because the resolver may fail if a different document
objects has a Label equal to the property's document object's identifier.
This commit is contained in:
Eivind Kvedalen 2016-01-03 23:49:01 +01:00
parent d53cb8146e
commit 3aa44e6b0c
2 changed files with 56 additions and 24 deletions

View File

@ -117,13 +117,24 @@ ObjectIdentifier::ObjectIdentifier(const App::PropertyContainer * _owner, const
, documentObjectNameSet(false)
, propertyIndex(-1)
{
if (owner) {
const DocumentObject * docObj = freecad_dynamic_cast<const DocumentObject>(owner);
if (!docObj)
throw Base::Exception("Property must be owned by a document object.");
const Document * doc = docObj->getDocument();
documentName = String(doc->getName(), false, true);
documentObjectName = String(docObj->getNameInDocument(), false, true);
}
if (property.size() > 0)
addComponent(Component::SimpleComponent(property));
}
/**
* @brief Construct an ObjectIdentifier object given a property. The property is assumed to be single-valued.
* @param prop Property to construct object idenfier for.
* @param prop Property to construct object identifier for.
*/
ObjectIdentifier::ObjectIdentifier(const Property &prop)
@ -132,6 +143,16 @@ ObjectIdentifier::ObjectIdentifier(const Property &prop)
, documentObjectNameSet(false)
, propertyIndex(-1)
{
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(prop.getContainer());
if (!docObj)
throw Base::Exception("Property must be owned by a document object.");
Document * doc = docObj->getDocument();
documentName = String(doc->getName(), false, true);
documentObjectName = String(docObj->getNameInDocument(), false, true);
addComponent(Component::SimpleComponent(String(owner->getPropertyName(&prop))));
}
@ -508,32 +529,35 @@ std::string ObjectIdentifier::Component::toString() const
* @return Pointer to document object if a unique pointer is found, 0 otherwise.
*/
App::DocumentObject * ObjectIdentifier::getDocumentObject(const App::Document * doc, const std::string & name) const
App::DocumentObject * ObjectIdentifier::getDocumentObject(const App::Document * doc, const String & name) const
{
DocumentObject * o1 = 0;
DocumentObject * o2 = 0;
DocumentObject * objectById = 0;
DocumentObject * objectByLabel = 0;
std::vector<DocumentObject*> docObjects = doc->getObjects();
// No object found with matching label, try using name directly
objectById = doc->getObject(static_cast<const char*>(name));
if (name.isForceIdentifier())
return objectById;
for (std::vector<DocumentObject*>::iterator j = docObjects.begin(); j != docObjects.end(); ++j) {
if (strcmp((*j)->Label.getValue(), name.c_str()) == 0) {
if (strcmp((*j)->Label.getValue(), static_cast<const char*>(name)) == 0) {
// Found object with matching label
if (o1 != 0)
if (objectByLabel != 0)
return 0;
o1 = *j;
objectByLabel = *j;
}
}
// No object found with matching label, try using name directly
o2 = doc->getObject(name.c_str());
if (o1 == 0 && o2 == 0) // Not found at all
if (objectByLabel == 0 && objectById == 0) // Not found at all
return 0;
else if (o1 == 0) // Found by name
return o2;
else if (o2 == 0) // Found by label
return o1;
else if (o1 == o2) // Found by both name and label, same object
return o1;
else if (objectByLabel == 0) // Found by name
return objectById;
else if (objectById == 0) // Found by label
return objectByLabel;
else if (objectByLabel == objectById) // Found by both name and label, same object
return objectByLabel;
else
return 0; // Found by both name and label, two different objects
}
@ -574,11 +598,11 @@ void ObjectIdentifier::resolve() const
}
}
documentName = String(doc->getName());
documentName = String(doc->getName(), false, documentName.isForceIdentifier());
/* Document object name specified? */
if (documentObjectNameSet) {
docObject = getDocumentObject(doc, documentObjectName.getString());
docObject = getDocumentObject(doc, documentObjectName);
if (!docObject)
return;
if (components.size() > 0) {
@ -591,7 +615,7 @@ void ObjectIdentifier::resolve() const
else {
/* Document object name not specified, resolve from path */
if (components.size() == 1) {
documentObjectName = String(static_cast<const DocumentObject*>(owner)->getNameInDocument());
documentObjectName = String(static_cast<const DocumentObject*>(owner)->getNameInDocument(), false, documentObjectName.isForceIdentifier());
propertyName = components[0].name.getString();
propertyIndex = 0;
}
@ -602,12 +626,12 @@ void ObjectIdentifier::resolve() const
docObject = getDocumentObject(doc, components[0].name);
if (docObject) {
documentObjectName = components[0].name;
documentObjectName = String(components[0].name, false, documentObjectName.isForceIdentifier());
propertyName = components[1].name.getString();
propertyIndex = 1;
}
else {
documentObjectName = String(static_cast<const DocumentObject*>(owner)->getNameInDocument());
documentObjectName = String(static_cast<const DocumentObject*>(owner)->getNameInDocument(), false, documentObjectName.isForceIdentifier());
propertyName = components[0].name.getString();
propertyIndex = 0;
}
@ -629,6 +653,10 @@ Document * ObjectIdentifier::getDocument(String name) const
name = getDocumentName();
App::Document * docById = App::GetApplication().getDocument(name);
if (name.isForceIdentifier())
return docById;
App::Document * docByLabel = 0;
const std::vector<App::Document*> docs = App::GetApplication().getDocuments();

View File

@ -47,7 +47,7 @@ public:
public:
// Constructor
String(const std::string & s = "", bool _isRealString = false) : str(s), isString(_isRealString) { }
String(const std::string & s = "", bool _isRealString = false, bool _forceIdentifier = false) : str(s), isString(_isRealString), forceIdentifier(_forceIdentifier) { }
// Accessors
@ -57,6 +57,8 @@ public:
/** Return true is string need to be quoted */
bool isRealString() const { return isString; }
bool isForceIdentifier() const { return forceIdentifier; }
/** Returns a possibly quoted string */
std::string toString() const;
@ -80,6 +82,8 @@ public:
std::string str;
bool isString;
bool forceIdentifier;
};
/**
@ -227,7 +231,7 @@ protected:
void resolve() const;
App::DocumentObject *getDocumentObject(const App::Document *doc, const std::string &name) const;
App::DocumentObject *getDocumentObject(const App::Document *doc, const String &name) const;
const App::PropertyContainer * owner;
bool documentNameSet;