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
This commit is contained in:
Zheng, Lei
2019-12-05 10:34:51 +08:00
committed by WandererFan
parent 5d60f3af01
commit 39959f9500
6 changed files with 324 additions and 121 deletions

View File

@@ -29,10 +29,13 @@
#include <boost/bind.hpp>
#include <Base/Tools.h>
#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<const DocumentObject*>(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<App::DocumentObject*>(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<DocumentObjectT&>(*this) = other;
subname = other.subname;
return *this;
}
SubObjectT &SubObjectT::operator=(SubObjectT &&other)
{
if (this == &other)
return *this;
static_cast<DocumentObjectT&>(*this) = std::move(other);
subname = std::move(other.subname);
return *this;
}
bool SubObjectT::operator==(const SubObjectT &other) const {
return static_cast<const DocumentObjectT&>(*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<std::string, std::string> 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<std::string, std::string> 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<App::DocumentObject*> 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

View File

@@ -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<DocumentObject *> 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.

View File

@@ -361,7 +361,7 @@ bool SelectionSingleton::hasSelection() const
}
bool SelectionSingleton::hasPreselection() const {
return !CurrentPreselection.ObjName.empty();
return !CurrentPreselection.Object.getObjectName().empty();
}
std::vector<SelectionSingleton::SelObj> 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<std::string,std::string> 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 "<<Chng.DocName<<'#'<<Chng.ObjName<<'.'<<Chng.SubName
FC_LOG("Add Selection "<<Chng.pDocName<<'#'<<Chng.pObjectName<<'.'<<Chng.pSubName
<< " (" << x << ", " << y << ", " << z << ')');
notify(std::move(Chng));
@@ -1198,7 +1192,7 @@ bool SelectionSingleton::addSelections(const char* pDocName, const char* pObject
SelectionChanges Chng(SelectionChanges::AddSelection,
temp.DocName,temp.FeatName,temp.SubName,temp.TypeName);
FC_LOG("Add Selection "<<Chng.DocName<<'#'<<Chng.ObjName<<'.'<<Chng.SubName);
FC_LOG("Add Selection "<<Chng.pDocName<<'#'<<Chng.pObjectName<<'.'<<Chng.pSubName);
notify(std::move(Chng));
update = true;
@@ -1233,7 +1227,7 @@ bool SelectionSingleton::updateSelection(bool show, const char* pDocName,
SelectionChanges Chng(show?SelectionChanges::ShowSelection:SelectionChanges::HideSelection,
pDocName,pObjectName,pSubName,pObject->getTypeId().getName());
FC_LOG("Update Selection "<<Chng.DocName << '#' << Chng.ObjName << '.' <<Chng.SubName);
FC_LOG("Update Selection "<<Chng.pDocName << '#' << Chng.pObjectName << '.' <<Chng.pSubName);
notify(std::move(Chng));
@@ -1327,7 +1321,7 @@ void SelectionSingleton::rmvSelection(const char* pDocName, const char* pObjectN
// So, the notification is done after the loop, see also #0003469
if(changes.size()) {
for(auto &Chng : changes) {
FC_LOG("Rmv Selection "<<Chng.DocName<<'#'<<Chng.ObjName<<'.'<<Chng.SubName);
FC_LOG("Rmv Selection "<<Chng.pDocName<<'#'<<Chng.pObjectName<<'.'<<Chng.pSubName);
notify(std::move(Chng));
}
getMainWindow()->updateActions();
@@ -1674,7 +1668,7 @@ void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj)
}
if(changes.size()) {
for(auto &Chng : changes) {
FC_LOG("Rmv Selection "<<Chng.DocName<<'#'<<Chng.ObjName<<'.'<<Chng.SubName);
FC_LOG("Rmv Selection "<<Chng.pDocName<<'#'<<Chng.pObjectName<<'.'<<Chng.pSubName);
notify(std::move(Chng));
}
getMainWindow()->updateActions();

View File

@@ -38,7 +38,7 @@
#include <Base/Type.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/DocumentObserver.h>
#include <Gui/SelectionObject.h>
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;
};

View File

@@ -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<ViewProviderPath>(
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);

View File

@@ -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;