From e4978be7a43b9f8c436f1f6e61a57fd9abfb072b Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 5 Dec 2019 10:34:51 +0800 Subject: [PATCH] App: add new convenient class SubObjectT Derived from App::DocumentObjectT to add support of sub object Also some minor changes to App::DocumentObjectT Changed Gui::SelectionChanges to make use of SubObjectT --- src/App/DocumentObserver.cpp | 254 ++++++++++++++++---- src/App/DocumentObserver.h | 83 ++++++- src/Gui/Selection.cpp | 32 +-- src/Gui/Selection.h | 58 ++--- src/Mod/Path/Gui/ViewProviderPath.cpp | 16 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 2 +- 6 files changed, 324 insertions(+), 121 deletions(-) diff --git a/src/App/DocumentObserver.cpp b/src/App/DocumentObserver.cpp index 18122c157a..c88043d628 100644 --- a/src/App/DocumentObserver.cpp +++ b/src/App/DocumentObserver.cpp @@ -29,10 +29,13 @@ #include +#include #include "Application.h" #include "Document.h" #include "DocumentObject.h" #include "DocumentObserver.h" +#include "ComplexGeoData.h" +#include "GeoFeature.h" using namespace App; @@ -77,7 +80,7 @@ Document* DocumentT::getDocument() const return GetApplication().getDocument(document.c_str()); } -std::string DocumentT::getDocumentName() const +const std::string &DocumentT::getDocumentName() const { return document; } @@ -85,15 +88,7 @@ std::string DocumentT::getDocumentName() const std::string DocumentT::getDocumentPython() const { std::stringstream str; - Document* doc = GetApplication().getActiveDocument(); - if (doc && document == doc->getName()) { - str << "App.ActiveDocument"; - } - else { - str << "App.getDocument(\"" - << document - << "\")"; - } + str << "App.getDocument(\"" << document << "\")"; return str.str(); } @@ -103,11 +98,19 @@ DocumentObjectT::DocumentObjectT() { } +DocumentObjectT::DocumentObjectT(const DocumentObjectT &other) +{ + *this = other; +} + +DocumentObjectT::DocumentObjectT(DocumentObjectT &&other) +{ + *this = std::move(other); +} + DocumentObjectT::DocumentObjectT(const DocumentObject* obj) { - object = obj->getNameInDocument(); - label = obj->Label.getValue(); - document = obj->getDocument()->getName(); + *this = obj; } DocumentObjectT::DocumentObjectT(const Property* prop) @@ -115,35 +118,78 @@ DocumentObjectT::DocumentObjectT(const Property* prop) *this = prop; } +DocumentObjectT::DocumentObjectT(const char *docName, const char *objName) +{ + if(docName) + document = docName; + if(objName) + object = objName; +} + DocumentObjectT::~DocumentObjectT() { } -void DocumentObjectT::operator=(const DocumentObjectT& obj) +DocumentObjectT &DocumentObjectT::operator=(const DocumentObjectT& obj) { if (this == &obj) - return; + return *this; object = obj.object; label = obj.label; document = obj.document; property = obj.property; + return *this; +} + +DocumentObjectT &DocumentObjectT::operator=(DocumentObjectT&& obj) +{ + if (this == &obj) + return *this; + object = std::move(obj.object); + label = std::move(obj.label); + document = std::move(obj.document); + property = std::move(obj.property); + return *this; } void DocumentObjectT::operator=(const DocumentObject* obj) { - object = obj->getNameInDocument(); - label = obj->Label.getValue(); - document = obj->getDocument()->getName(); - property.clear(); + if(!obj || !obj->getNameInDocument()) { + object.clear(); + label.clear(); + document.clear(); + property.clear(); + } else { + object = obj->getNameInDocument(); + label = obj->Label.getValue(); + document = obj->getDocument()->getName(); + property.clear(); + } } void DocumentObjectT::operator=(const Property *prop) { - auto obj = dynamic_cast(prop->getContainer()); - assert(obj); - object = obj->getNameInDocument(); - label = obj->Label.getValue(); - document = obj->getDocument()->getName(); - property = prop->getName(); + if(!prop || !prop->getName() + || !prop->getContainer() + || !prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId())) + { + object.clear(); + label.clear(); + document.clear(); + property.clear(); + } else { + auto obj = static_cast(prop->getContainer()); + object = obj->getNameInDocument(); + label = obj->Label.getValue(); + document = obj->getDocument()->getName(); + property = prop->getName(); + } +} + +bool DocumentObjectT::operator==(const DocumentObjectT &other) const { + return document == other.document + && object == other.object + && label == other.label + && property == other.property; } Document* DocumentObjectT::getDocument() const @@ -151,7 +197,7 @@ Document* DocumentObjectT::getDocument() const return GetApplication().getDocument(document.c_str()); } -std::string DocumentObjectT::getDocumentName() const +const std::string& DocumentObjectT::getDocumentName() const { return document; } @@ -159,15 +205,7 @@ std::string DocumentObjectT::getDocumentName() const std::string DocumentObjectT::getDocumentPython() const { std::stringstream str; - Document* doc = GetApplication().getActiveDocument(); - if (doc && document == doc->getName()) { - str << "App.ActiveDocument"; - } - else { - str << "App.getDocument(\"" - << document - << "\")"; - } + str << "FreeCAD.getDocument(\"" << document << "\")"; return str.str(); } @@ -181,12 +219,12 @@ DocumentObject* DocumentObjectT::getObject() const return obj; } -std::string DocumentObjectT::getObjectName() const +const std::string &DocumentObjectT::getObjectName() const { return object; } -std::string DocumentObjectT::getObjectLabel() const +const std::string &DocumentObjectT::getObjectLabel() const { return label; } @@ -194,21 +232,11 @@ std::string DocumentObjectT::getObjectLabel() const std::string DocumentObjectT::getObjectPython() const { std::stringstream str; - Document* doc = GetApplication().getActiveDocument(); - if (doc && document == doc->getName()) { - str << "App.ActiveDocument."; - } - else { - str << "App.getDocument(\"" - << document - << "\")."; - } - - str << object; + str << "FreeCAD.getDocument('" << document << "').getObject('" << object << "')"; return str.str(); } -std::string DocumentObjectT::getPropertyName() const { +const std::string &DocumentObjectT::getPropertyName() const { return property; } @@ -231,6 +259,134 @@ Property *DocumentObjectT::getProperty() const { } // ----------------------------------------------------------------------------- +SubObjectT::SubObjectT() +{} + +SubObjectT::SubObjectT(const SubObjectT &other) + :DocumentObjectT(other), subname(other.subname) +{ +} + +SubObjectT::SubObjectT(SubObjectT &&other) + :DocumentObjectT(std::move(other)), subname(std::move(other.subname)) +{ +} + +SubObjectT::SubObjectT(const DocumentObject *obj, const char *s) + :DocumentObjectT(obj),subname(s?s:"") +{} + +SubObjectT::SubObjectT(const char *docName, const char *objName, const char *s) + :DocumentObjectT(docName,objName), subname(s?s:"") +{ +} + +bool SubObjectT::operator<(const SubObjectT &other) const { + if(getDocumentName() < other.getDocumentName()) + return true; + if(getDocumentName() > other.getDocumentName()) + return false; + if(getObjectName() < other.getObjectName()) + return true; + if(getObjectName() > other.getObjectName()) + return false; + if(getSubName() < other.getSubName()) + return true; + if(getSubName() > other.getSubName()) + return false; + return getPropertyName() < other.getPropertyName(); +} + +SubObjectT &SubObjectT::operator=(const SubObjectT& other) +{ + if (this == &other) + return *this; + static_cast(*this) = other; + subname = other.subname; + return *this; +} + +SubObjectT &SubObjectT::operator=(SubObjectT &&other) +{ + if (this == &other) + return *this; + static_cast(*this) = std::move(other); + subname = std::move(other.subname); + return *this; +} + +bool SubObjectT::operator==(const SubObjectT &other) const { + return static_cast(*this) == other + && subname == other.subname; +} + +void SubObjectT::setSubName(const char *s) { + subname = s?s:""; +} + +const std::string &SubObjectT::getSubName() const { + return subname; +} + +std::string SubObjectT::getSubNameNoElement() const { + return Data::ComplexGeoData::noElementName(subname.c_str()); +} + +const char *SubObjectT::getElementName() const { + return Data::ComplexGeoData::findElementName(subname.c_str()); +} + +std::string SubObjectT::getNewElementName() const { + std::pair element; + auto obj = getObject(); + if(!obj) + return std::string(); + GeoFeature::resolveElement(obj,subname.c_str(),element); + return std::move(element.first); +} + +std::string SubObjectT::getOldElementName(int *index) const { + std::pair element; + auto obj = getObject(); + if(!obj) + return std::string(); + GeoFeature::resolveElement(obj,subname.c_str(),element); + if(!index) + return std::move(element.second); + std::size_t pos = element.second.find_first_of("0123456789"); + if(pos == std::string::npos) + *index = -1; + else { + *index = std::atoi(element.second.c_str()+pos); + element.second.resize(pos); + } + return std::move(element.second); +} + +App::DocumentObject *SubObjectT::getSubObject() const { + auto obj = getObject(); + if(obj) + return obj->getSubObject(subname.c_str()); + return 0; +} + +std::string SubObjectT::getSubObjectPython(bool force) const { + if(!force && subname.empty()) + return getObjectPython(); + std::stringstream str; + str << "(" << getObjectPython() << ",u'" + << Base::Tools::escapedUnicodeFromUtf8(subname.c_str()) << "')"; + return str.str(); +} + +std::vector SubObjectT::getSubObjectList() const { + auto obj = getObject(); + if(obj) + return obj->getSubObjectList(subname.c_str()); + return {}; +} + +// ----------------------------------------------------------------------------- DocumentObserver::DocumentObserver() : _document(0) { this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(boost::bind diff --git a/src/App/DocumentObserver.h b/src/App/DocumentObserver.h index abb38423bc..dcf7936304 100644 --- a/src/App/DocumentObserver.h +++ b/src/App/DocumentObserver.h @@ -62,7 +62,7 @@ public: /*! Get a pointer to the document or 0 if it doesn't exist any more. */ Document* getDocument() const; /*! Get the name of the document. */ - std::string getDocumentName() const; + const std::string &getDocumentName() const; /*! Get the document as Python command. */ std::string getDocumentPython() const; @@ -83,22 +83,32 @@ public: /*! Constructor */ DocumentObjectT(); /*! Constructor */ + DocumentObjectT(const DocumentObjectT &); + /*! Constructor */ + DocumentObjectT(DocumentObjectT &&); + /*! Constructor */ DocumentObjectT(const DocumentObject*); /*! Constructor */ + DocumentObjectT(const char *docName, const char *objName); + /*! Constructor */ DocumentObjectT(const Property*); /*! Destructor */ ~DocumentObjectT(); /*! Assignment operator */ - void operator=(const DocumentObjectT&); + DocumentObjectT &operator=(const DocumentObjectT&); + /*! Assignment operator */ + DocumentObjectT &operator=(DocumentObjectT &&); /*! Assignment operator */ void operator=(const DocumentObject*); /*! Assignment operator */ void operator=(const Property*); + /*! Equality operator */ + bool operator==(const DocumentObjectT&) const; /*! Get a pointer to the document or 0 if it doesn't exist any more. */ Document* getDocument() const; /*! Get the name of the document. */ - std::string getDocumentName() const; + const std::string &getDocumentName() const; /*! Get the document as Python command. */ std::string getDocumentPython() const; /*! Get a pointer to the document object or 0 if it doesn't exist any more. */ @@ -106,11 +116,11 @@ public: /*! Get a pointer to the property or 0 if it doesn't exist any more. */ Property* getProperty() const; /*! Get the name of the document object. */ - std::string getObjectName() const; + const std::string &getObjectName() const; /*! Get the label of the document object. */ - std::string getObjectLabel() const; + const std::string &getObjectLabel() const; /*! Get the name of the property. */ - std::string getPropertyName() const; + const std::string &getPropertyName() const; /*! Get the document object as Python command. */ std::string getObjectPython() const; /*! Get the property as Python command. */ @@ -134,6 +144,67 @@ private: std::string property; }; +class AppExport SubObjectT: public DocumentObjectT +{ +public: + /*! Constructor */ + SubObjectT(); + + /*! Constructor */ + SubObjectT(const SubObjectT &); + + /*! Constructor */ + SubObjectT(SubObjectT &&); + + /*! Constructor */ + SubObjectT(const DocumentObject*, const char *subname); + + /*! Constructor */ + SubObjectT(const char *docName, const char *objName, const char *subname); + + /*! Assignment operator */ + SubObjectT &operator=(const SubObjectT&); + + /*! Assignment operator */ + SubObjectT &operator=(SubObjectT &&); + + /*! Equality operator */ + bool operator==(const SubObjectT&) const; + + /// Set the subname path to the sub-object + void setSubName(const char *subname); + + /// Return the subname path + const std::string &getSubName() const; + + /// Return the subname path without sub-element + std::string getSubNameNoElement() const; + + /// Return the sub-element (Face, Edge, etc) of the subname path + const char *getElementName() const; + + /// Return the new style sub-element name + std::string getNewElementName() const; + + /** Return the old style sub-element name + * @param index: if given, then return the element type, and extract the index + */ + std::string getOldElementName(int *index=0) const; + + /// Return the sub-object + DocumentObject *getSubObject() const; + + /// Return all objects along the subname path + std::vector getSubObjectList() const; + + bool operator<(const SubObjectT &other) const; + + std::string getSubObjectPython(bool force=true) const; + +private: + std::string subname; +}; + /** * The DocumentObserver class simplfies the step to write classes that listen * to what happens inside a document. diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp index 70ed8f3f49..469944a634 100644 --- a/src/Gui/Selection.cpp +++ b/src/Gui/Selection.cpp @@ -361,7 +361,7 @@ bool SelectionSingleton::hasSelection() const } bool SelectionSingleton::hasPreselection() const { - return !CurrentPreselection.ObjName.empty(); + return !CurrentPreselection.Object.getObjectName().empty(); } std::vector SelectionSingleton::getCompleteSelection(int resolve) const @@ -584,9 +584,7 @@ void SelectionSingleton::notify(SelectionChanges &&Chng) { break; case SelectionChanges::SetPreselect: notify = CurrentPreselection.Type==SelectionChanges::SetPreselect - && CurrentPreselection.DocName == msg.DocName - && CurrentPreselection.ObjName == msg.ObjName - && CurrentPreselection.SubName == msg.SubName; + && CurrentPreselection.Object == msg.Object; break; case SelectionChanges::RmvPreselect: notify = CurrentPreselection.Type==SelectionChanges::ClrSelection; @@ -719,14 +717,12 @@ void SelectionSingleton::slotSelectionChanged(const SelectionChanges& msg) { msg.Type == SelectionChanges::HideSelection) return; - if(msg.DocName.size() && msg.ObjName.size() && msg.SubName.size()) { - App::Document* pDoc = getDocument(msg.pDocName); - if(!pDoc) return; + if(msg.Object.getSubName().size()) { + auto pParent = msg.Object.getObject(); + if(!pParent) return; std::pair elementName; auto &newElementName = elementName.first; auto &oldElementName = elementName.second; - auto pParent = pDoc->getObject(msg.pObjectName); - if(!pParent) return; auto pObject = App::GeoFeature::resolveElement(pParent,msg.pSubName,elementName); if (!pObject) return; SelectionChanges msg2(msg.Type,pObject->getDocument()->getName(), @@ -735,12 +731,10 @@ void SelectionSingleton::slotSelectionChanged(const SelectionChanges& msg) { pObject->getTypeId().getName(), msg.x,msg.y,msg.z); msg2.pOriginalMsg = &msg; - msg2.pParentObject = pParent; - msg2.pSubObject = pObject; signalSelectionChanged3(msg2); - msg2.SubName = oldElementName; - msg2.pSubName = msg2.SubName.c_str(); + msg2.Object.setSubName(oldElementName.c_str()); + msg2.pSubName = msg2.Object.getSubName().c_str(); signalSelectionChanged2(msg2); }else { @@ -854,7 +848,7 @@ void SelectionSingleton::setPreselectCoord( float x, float y, float z) static char buf[513]; // if nothing is in preselect ignore - if(!CurrentPreselection.pObjectName || CurrentPreselection.ObjName.empty()) return; + if(CurrentPreselection.Object.getObjectName().empty()) return; CurrentPreselection.x = x; CurrentPreselection.y = y; @@ -1053,7 +1047,7 @@ bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectN SelectionChanges Chng(SelectionChanges::AddSelection, temp.DocName,temp.FeatName,temp.SubName,temp.TypeName, x,y,z); - FC_LOG("Add Selection "<getTypeId().getName()); - FC_LOG("Update Selection "<updateActions(); @@ -1674,7 +1668,7 @@ void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj) } if(changes.size()) { for(auto &Chng : changes) { - FC_LOG("Rmv Selection "<updateActions(); diff --git a/src/Gui/Selection.h b/src/Gui/Selection.h index 4add9f4c0e..b982d4cf5e 100644 --- a/src/Gui/Selection.h +++ b/src/Gui/Selection.h @@ -38,7 +38,7 @@ #include #include #include - +#include #include namespace App @@ -85,13 +85,11 @@ public: float x=0, float y=0, float z=0, int subtype=0) : Type(type),SubType(subtype) , x(x),y(y),z(z) + , Object(docName,objName,subName) { - if(docName) DocName=docName; - pDocName = DocName.c_str(); - if(objName) ObjName = objName; - pObjectName = ObjName.c_str(); - if(subName) SubName = subName; - pSubName = SubName.c_str(); + pDocName = Object.getDocumentName().c_str(); + pObjectName = Object.getObjectName().c_str(); + pSubName = Object.getSubName().c_str(); if(typeName) TypeName = typeName; pTypeName = TypeName.c_str(); } @@ -104,14 +102,12 @@ public: float x=0,float y=0,float z=0, int subtype=0) : Type(type), SubType(subtype) , x(x),y(y),z(z) - , DocName(docName) - , ObjName(objName) - , SubName(subName) + , Object(docName.c_str(), objName.c_str(), subName.c_str()) , TypeName(typeName) { - pDocName = DocName.c_str(); - pObjectName = ObjName.c_str(); - pSubName = SubName.c_str(); + pDocName = Object.getDocumentName().c_str(); + pObjectName = Object.getObjectName().c_str(); + pSubName = Object.getSubName().c_str(); pTypeName = TypeName.c_str(); } @@ -125,17 +121,13 @@ public: x = other.x; y = other.y; z = other.z; - DocName = other.DocName; - ObjName = other.ObjName; - SubName = other.SubName; + Object = other.Object; TypeName = other.TypeName; - pDocName = DocName.c_str(); - pObjectName = ObjName.c_str(); - pSubName = SubName.c_str(); + pDocName = Object.getDocumentName().c_str(); + pObjectName = Object.getObjectName().c_str(); + pSubName = Object.getSubName().c_str(); pTypeName = TypeName.c_str(); pOriginalMsg = other.pOriginalMsg; - pSubObject = other.pSubObject; - pParentObject = other.pParentObject; return *this; } @@ -149,17 +141,13 @@ public: x = other.x; y = other.y; z = other.z; - DocName = std::move(other.DocName); - ObjName = std::move(other.ObjName); - SubName = std::move(other.SubName); + Object = std::move(other.Object); TypeName = std::move(other.TypeName); - pDocName = DocName.c_str(); - pObjectName = ObjName.c_str(); - pSubName = SubName.c_str(); + pDocName = Object.getDocumentName().c_str(); + pObjectName = Object.getObjectName().c_str(); + pSubName = Object.getSubName().c_str(); pTypeName = TypeName.c_str(); pOriginalMsg = other.pOriginalMsg; - pSubObject = other.pSubObject; - pParentObject = other.pParentObject; return *this; } @@ -174,19 +162,9 @@ public: float y; float z; - // For more robust selection notification (e.g. in case user make selection - // change inside selection notification handler), the notification message - // shall make a copy of all the strings here. - std::string DocName; - std::string ObjName; - std::string SubName; + App::SubObjectT Object; std::string TypeName; - // Resolved sub object in case resolve!=0, otherwise this is null - App::DocumentObject *pSubObject = 0; - // Resolved parent object in case resolve!=0, otherwise this is null - App::DocumentObject *pParentObject = 0; - // Original selection message in case resolve!=0 const SelectionChanges *pOriginalMsg = 0; }; diff --git a/src/Mod/Path/Gui/ViewProviderPath.cpp b/src/Mod/Path/Gui/ViewProviderPath.cpp index abcb92a99a..1b36e7f2f3 100644 --- a/src/Mod/Path/Gui/ViewProviderPath.cpp +++ b/src/Mod/Path/Gui/ViewProviderPath.cpp @@ -97,22 +97,26 @@ public: setArrow(); return; } - if((msg.Type!=Gui::SelectionChanges::SetPreselect + if(msg.Type!=Gui::SelectionChanges::SetPreselect && msg.Type!=Gui::SelectionChanges::MovePreselect) - || !msg.pOriginalMsg || !msg.pSubObject || !msg.pParentObject) + return; + auto obj = msg.Object.getObject(); + if(!obj) + return; + Base::Matrix4D mat; + auto sobj = obj->getSubObject(msg.pSubName,0,&mat); + if(!sobj) return; Base::Matrix4D linkMat; - auto sobj = msg.pSubObject->getLinkedObject(true,&linkMat,false); + auto linked = sobj->getLinkedObject(true,&linkMat,false); auto vp = Base::freecad_dynamic_cast( - Application::Instance->getViewProvider(sobj)); + Application::Instance->getViewProvider(linked)); if(!vp) { setArrow(); return; } if(vp->pt0Index >= 0) { - Base::Matrix4D mat; - msg.pParentObject->getSubObject(msg.pSubName,0,&mat); mat *= linkMat; mat.inverse(); Base::Vector3d pt = mat*Base::Vector3d(msg.x,msg.y,msg.z); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 7f6c17c0ac..9baa570458 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -1485,7 +1485,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg) // are we in edit? if (edit) { // ignore external object - if(msg.ObjName.size() && msg.DocName.size() && msg.DocName!=getObject()->getDocument()->getName()) + if(msg.Object.getObjectName().size() && msg.Object.getDocument()!=getObject()->getDocument()) return; bool handled=false;