diff --git a/src/Gui/ActiveObjectList.cpp b/src/Gui/ActiveObjectList.cpp
index 6f65de40e9..d2f85a2e62 100644
--- a/src/Gui/ActiveObjectList.cpp
+++ b/src/Gui/ActiveObjectList.cpp
@@ -28,44 +28,116 @@
#endif
+#include
#include "ActiveObjectList.h"
#include
#include
+#include
#include
+#include "Tree.h"
-
+FC_LOG_LEVEL_INIT("MDIView",true,true);
using namespace Gui;
-
-void Gui::ActiveObjectList::setObject(App::DocumentObject* obj, const char* name, const Gui::HighlightMode& mode)
+App::DocumentObject *ActiveObjectList::getObject(const ObjectInfo &info, bool resolve,
+ App::DocumentObject **parent, std::string *subname) const
{
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView");
- bool autoExpand = hGrp->GetBool("TreeActiveAutoExpand", true);
+ if(parent) *parent = info.obj;
+ if(subname) *subname = info.subname;
+ auto obj = info.obj;
+ if(!obj || !obj->getNameInDocument())
+ return 0;
+ if(info.subname.size()) {
+ obj = obj->getSubObject(info.subname.c_str());
+ if(!obj)
+ return 0;
+ }
+ return resolve?obj->getLinkedObject(true):obj;
+}
- if (hasObject(name)) {
- App::DocumentObject* act = getObject(name);
- Gui::Document* doc = Application::Instance->getDocument(act->getDocument());
- Gui::ViewProviderDocumentObject* viewProvider = static_cast
- (doc->getViewProvider(act));
- doc->signalHighlightObject(*viewProvider, mode, false);
- if (autoExpand)
- doc->signalExpandObject(*viewProvider, Gui::CollapseItem);
+void ActiveObjectList::setHighlight(const ObjectInfo &info, HighlightMode mode, bool enable) {
+ auto obj = getObject(info,false);
+ if(!obj) return;
+ auto vp = dynamic_cast(Application::Instance->getViewProvider(obj));
+ if(!vp) return;
+
+ if(FC_TREEPARAM(TreeActiveAutoExpand))
+ vp->getDocument()->signalExpandObject(*vp,
+ enable?Gui::ExpandPath:Gui::CollapseItem, info.obj, info.subname.c_str());
+
+ vp->getDocument()->signalHighlightObject(*vp, mode,enable,info.obj,info.subname.c_str());
+}
+
+Gui::ActiveObjectList::ObjectInfo Gui::ActiveObjectList::getObjectInfo(
+ App::DocumentObject *obj, const char *subname) const
+{
+ ObjectInfo info;
+ info.obj = 0;
+ if(!obj || !obj->getNameInDocument())
+ return info;
+ if(subname) {
+ info.obj = obj;
+ if(subname) info.subname = subname;
+ }else{
+ // If the input object is not from this document, it must be brought in
+ // by some link type object of this document. We only accept the object
+ // if we can find such object in the current selection.
+ auto sels = Gui::Selection().getSelection(_Doc->getDocument()->getName(),false);
+ for(auto &sel : sels) {
+ if(sel.pObject == obj || sel.pObject->getLinkedObject(true)==obj) {
+ info.obj = sel.pObject;
+ break;
+ }
+ for(auto dot=strchr(sel.SubName,'.');dot;dot=strchr(dot+1,'.')) {
+ std::string subname(sel.SubName,dot-sel.SubName+1);
+ auto sobj = sel.pObject->getSubObject(subname.c_str());
+ if(!sobj) break;
+ if(sobj == obj || sobj->getLinkedObject(true) == obj) {
+ info.obj = sel.pObject;
+ info.subname = subname;
+ break;
+ }
+ }
+ if(info.obj) break;
+ }
+ if(!info.obj && obj->getDocument()==_Doc->getDocument())
+ info.obj = obj;
+ }
+ return info;
+}
+
+bool Gui::ActiveObjectList::hasObject(App::DocumentObject *obj,
+ const char *name, const char *subname) const
+{
+ auto it = _ObjectMap.find(name);
+ if(it==_ObjectMap.end())
+ return false;
+ auto info = getObjectInfo(obj,subname);
+ return info.obj==it->second.obj && info.subname==it->second.subname;
+}
+
+void Gui::ActiveObjectList::setObject(App::DocumentObject* obj, const char* name,
+ const char *subname, const Gui::HighlightMode& mode)
+{
+ auto it = _ObjectMap.find(name);
+ if(it!=_ObjectMap.end()) {
+ setHighlight(it->second,mode,false);
+ _ObjectMap.erase(it);
+ }
+ if(!obj) return;
+
+ auto info = getObjectInfo(obj,subname);
+ if(!info.obj) {
+ FC_ERR("Cannot set active object "
+ << obj->getFullName() << '.' << (subname?subname:"")
+ << " in document '" << _Doc->getDocument()->getName()
+ << "'. Not found in current selection");
+ return;
}
- if (obj) {
- Gui::Document* doc = Application::Instance->getDocument(obj->getDocument());
- Gui::ViewProviderDocumentObject* viewProvider = static_cast
- (doc->getViewProvider(obj));
- doc->signalHighlightObject(*viewProvider, mode, true);
- if (autoExpand)
- doc->signalExpandObject(*viewProvider, Gui::ExpandPath);
- _ObjectMap[name] = obj;
- }
- else {
- if (hasObject(name))
- _ObjectMap.erase(name);
- }
+ _ObjectMap[name] = info;
+ setHighlight(info,mode,true);
}
bool Gui::ActiveObjectList::hasObject(const char*name)const
@@ -73,14 +145,12 @@ bool Gui::ActiveObjectList::hasObject(const char*name)const
return _ObjectMap.find(name) != _ObjectMap.end();
}
-void ActiveObjectList::objectDeleted(const ViewProviderDocumentObject& viewProviderIn)
+void ActiveObjectList::objectDeleted(const ViewProviderDocumentObject &vp)
{
- App::DocumentObject* object = viewProviderIn.getObject();
//maybe boost::bimap or boost::multi_index
- std::map::iterator it;
- for (it = _ObjectMap.begin(); it != _ObjectMap.end(); ++it)
+ for (auto it = _ObjectMap.begin(); it != _ObjectMap.end(); ++it)
{
- if (it->second == object)
+ if (it->second.obj == vp.getObject())
{
_ObjectMap.erase(it);
return;
diff --git a/src/Gui/ActiveObjectList.h b/src/Gui/ActiveObjectList.h
index fd0f5d4915..416530ce67 100644
--- a/src/Gui/ActiveObjectList.h
+++ b/src/Gui/ActiveObjectList.h
@@ -34,32 +34,50 @@ namespace App {
namespace Gui
{
-
class Document;
class ViewProviderDocumentObject;
- /** List of active or special objects
- * This class holds a list of objects with a special name.
- * Its mainly used to points to something like the active Body or Part in a edit session.
- * The class is used the viewer (editor) of a document.
- * @see Gui::MDIViewer
- * @author Jürgen Riegel
- */
- class GuiExport ActiveObjectList
+ /** List of active or special objects
+ * This class holds a list of objects with a special name.
+ * Its mainly used to points to something like the active Body or Part in a edit session.
+ * The class is used the viewer (editor) of a document.
+ * @see Gui::MDIViewer
+ * @author Jürgen Riegel
+ */
+ class GuiExport ActiveObjectList
{
-
public:
+ ActiveObjectList(Document *doc)
+ :_Doc(doc)
+ {}
+
template
- inline _T getObject(const char* name) const
- {
- std::map::const_iterator pos = _ObjectMap.find(name);
- return pos == _ObjectMap.end() ? 0 : dynamic_cast<_T>(pos->second);
+ inline _T getObject(const char* name, App::DocumentObject **parent=0, std::string *subname=0) const {
+ auto it = _ObjectMap.find(name);
+ if(it==_ObjectMap.end())
+ return 0;
+ return dynamic_cast<_T>(getObject(it->second,true,parent,subname));
}
- void setObject(App::DocumentObject*, const char*, const Gui::HighlightMode& m = Gui::UserDefined);
+ void setObject(App::DocumentObject*, const char*, const char *subname=0,
+ const Gui::HighlightMode& m = Gui::LightBlue);
bool hasObject(const char*)const;
void objectDeleted(const ViewProviderDocumentObject& viewProviderIn);
- protected:
- std::map _ObjectMap;
+ bool hasObject(App::DocumentObject *obj, const char *, const char *subname=0) const;
+
+ private:
+ struct ObjectInfo;
+ void setHighlight(const ObjectInfo &info, Gui::HighlightMode mode, bool enable);
+ App::DocumentObject *getObject(const ObjectInfo &info, bool resolve,
+ App::DocumentObject **parent=0, std::string *subname=0) const;
+ ObjectInfo getObjectInfo(App::DocumentObject *obj, const char *subname) const;
+
+ private:
+ struct ObjectInfo {
+ App::DocumentObject *obj;
+ std::string subname;
+ };
+ std::map _ObjectMap;
+ Document *_Doc;
};
} //namespace Gui
diff --git a/src/Gui/MDIView.h b/src/Gui/MDIView.h
index a10be328c9..064a68e346 100644
--- a/src/Gui/MDIView.h
+++ b/src/Gui/MDIView.h
@@ -113,18 +113,22 @@ public:
/// access getter for the active object list
template
- inline _T getActiveObject(const char* name) const
+ inline _T getActiveObject(const char* name, App::DocumentObject **parent=0, std::string *subname=0) const
{
- return ActiveObjects.getObject<_T>(name);
+ return ActiveObjects.getObject<_T>(name,parent,subname);
}
- void setActiveObject(App::DocumentObject*o, const char*n)
+ void setActiveObject(App::DocumentObject*o, const char*n, const char *subname=0)
{
- ActiveObjects.setObject(o, n);
+ ActiveObjects.setObject(o, n, subname);
}
bool hasActiveObject(const char*n) const
{
return ActiveObjects.hasObject(n);
}
+ bool isActiveObject(App::DocumentObject*o, const char*n, const char *subname=0) const
+ {
+ return ActiveObjects.hasObject(o,n,subname);
+ }
public Q_SLOTS:
virtual void setOverrideCursor(const QCursor&);
diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp
index f376519dd7..fe3079bb40 100644
--- a/src/Gui/View3DPy.cpp
+++ b/src/Gui/View3DPy.cpp
@@ -64,6 +64,7 @@
#include
#include
#include
+#include
#include
using namespace Gui;
@@ -178,8 +179,8 @@ void View3DInventorPy::init_type()
"Remove the DraggerCalback function from the coin node\n"
"Possibles types :\n"
"'addFinishCallback','addStartCallback','addMotionCallback','addValueChangedCallback'\n");
- add_varargs_method("setActiveObject", &View3DInventorPy::setActiveObject, "setActiveObject(name,object)\nadd or set a new active object");
- add_varargs_method("getActiveObject", &View3DInventorPy::getActiveObject, "getActiveObject(name)\nreturns the active object for the given type");
+ add_varargs_method("setActiveObject", &View3DInventorPy::setActiveObject, "setActiveObject(name,object,subname=None)\nadd or set a new active object");
+ add_varargs_method("getActiveObject", &View3DInventorPy::getActiveObject, "getActiveObject(name,resolve=True)\nreturns the active object for the given type");
add_varargs_method("getViewProvidersOfType", &View3DInventorPy::getViewProvidersOfType, "getViewProvidersOfType(name)\nreturns a list of view providers for the given type");
add_varargs_method("redraw", &View3DInventorPy::redraw, "redraw(): renders the scene on screen (useful for animations)");
add_varargs_method("setName",&View3DInventorPy::setName,"setName(str): sets a name to this viewer\nThe name sets the widget's windowTitle and appears on the viewer tab");
@@ -1372,19 +1373,41 @@ Py::Object View3DInventorPy::getObjectInfo(const Py::Tuple& args)
dict.setItem("z", Py::Float(pt[2]));
Gui::Document* doc = _view->getViewer()->getDocument();
- ViewProvider *vp = doc ? doc->getViewProviderByPathFromTail(Point->getPath())
- : _view->getViewer()->getViewProviderByPathFromTail(Point->getPath());
- if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
+ ViewProvider *vp = doc ? doc->getViewProviderByPathFromHead(Point->getPath())
+ : _view->getViewer()->getViewProviderByPath(Point->getPath());
+ if(vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
+ if(!vp->isSelectable())
+ return ret;
ViewProviderDocumentObject* vpd = static_cast(vp);
- dict.setItem("Document",
- Py::String(vpd->getObject()->getDocument()->getName()));
- dict.setItem("Object",
- Py::String(vpd->getObject()->getNameInDocument()));
- if (vp->useNewSelectionModel()) {
- dict.setItem("Component",
- Py::String(vpd->getElement(Point->getDetail())));
- }
- else {
+ if(vp->useNewSelectionModel()) {
+ std::string subname;
+ if(!vp->getElementPicked(Point,subname))
+ return ret;
+ auto obj = vpd->getObject();
+ if(!obj)
+ return ret;
+ if(subname.size()) {
+ std::pair elementName;
+ auto sobj = App::GeoFeature::resolveElement(obj,subname.c_str(),elementName);
+ if(!sobj)
+ return ret;
+ if(sobj!=obj) {
+ dict.setItem("ParentObject",Py::Object(obj->getPyObject(),true));
+ dict.setItem("SubName",Py::String(subname));
+ obj = sobj;
+ }
+ subname = elementName.second.size()?elementName.second:elementName.first;
+ }
+ dict.setItem("Document",
+ Py::String(obj->getDocument()->getName()));
+ dict.setItem("Object",
+ Py::String(obj->getNameInDocument()));
+ dict.setItem("Component",Py::String(subname));
+ } else {
+ dict.setItem("Document",
+ Py::String(vpd->getObject()->getDocument()->getName()));
+ dict.setItem("Object",
+ Py::String(vpd->getObject()->getNameInDocument()));
// search for a SoFCSelection node
SoFCDocumentObjectAction objaction;
objaction.apply(Point->getPath());
@@ -1461,19 +1484,41 @@ Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args)
dict.setItem("y", Py::Float(pt[1]));
dict.setItem("z", Py::Float(pt[2]));
- ViewProvider *vp = doc ? doc->getViewProviderByPathFromTail(point->getPath())
- : _view->getViewer()->getViewProviderByPathFromTail(point->getPath());
- if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
+ ViewProvider *vp = doc ? doc->getViewProviderByPathFromHead(point->getPath())
+ : _view->getViewer()->getViewProviderByPath(point->getPath());
+ if(vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
+ if(!vp->isSelectable())
+ continue;
ViewProviderDocumentObject* vpd = static_cast(vp);
- dict.setItem("Document",
- Py::String(vpd->getObject()->getDocument()->getName()));
- dict.setItem("Object",
- Py::String(vpd->getObject()->getNameInDocument()));
- if (vp->useNewSelectionModel()) {
- dict.setItem("Component",
- Py::String(vpd->getElement(point->getDetail())));
- }
- else {
+ if(vp->useNewSelectionModel()) {
+ std::string subname;
+ if(!vp->getElementPicked(point,subname))
+ continue;
+ auto obj = vpd->getObject();
+ if(!obj)
+ continue;
+ if(subname.size()) {
+ std::pair elementName;
+ auto sobj = App::GeoFeature::resolveElement(obj,subname.c_str(),elementName);
+ if(!sobj)
+ continue;
+ if(sobj!=obj) {
+ dict.setItem("ParentObject",Py::Object(obj->getPyObject(),true));
+ dict.setItem("SubName",Py::String(subname));
+ obj = sobj;
+ }
+ subname = elementName.second.size()?elementName.second:elementName.first;
+ }
+ dict.setItem("Document",
+ Py::String(obj->getDocument()->getName()));
+ dict.setItem("Object",
+ Py::String(obj->getNameInDocument()));
+ dict.setItem("Component",Py::String(subname));
+ } else {
+ dict.setItem("Document",
+ Py::String(vpd->getObject()->getDocument()->getName()));
+ dict.setItem("Object",
+ Py::String(vpd->getObject()->getNameInDocument()));
// search for a SoFCSelection node
SoFCDocumentObjectAction objaction;
objaction.apply(point->getPath());
@@ -2403,37 +2448,43 @@ Py::Object View3DInventorPy::removeDraggerCallback(const Py::Tuple& args)
Py::Object View3DInventorPy::setActiveObject(const Py::Tuple& args)
{
- PyObject* docObject = 0;
- char* name;
+ PyObject* docObject = Py_None;
+ char* name;
+ char *subname = 0;
+ if (!PyArg_ParseTuple(args.ptr(), "s|Os", &name, &docObject, &subname))
+ throw Py::Exception();
- //allow reset of active object by setting "None"
- if (args.length() == 2 && args.back() == Py::None()) {
- PyArg_Parse(args.front().ptr(), "s", &name);
- _view->setActiveObject(NULL, name);
- return Py::None();
- }
-
- if (!PyArg_ParseTuple(args.ptr(), "sO!", &name, &App::DocumentObjectPy::Type, &docObject))
- throw Py::Exception();
-
- if (docObject){
- App::DocumentObject* obj = static_cast(docObject)->getDocumentObjectPtr();
- _view->setActiveObject(obj, name);
- }
- return Py::None();
+ if (docObject == Py_None)
+ _view->setActiveObject(0, name);
+ else{
+ if(!PyObject_TypeCheck(docObject, &App::DocumentObjectPy::Type))
+ throw Py::TypeError("Expect the second argument to be a document object or None");
+ App::DocumentObject* obj = static_cast(docObject)->getDocumentObjectPtr();
+ _view->setActiveObject(obj, name, subname);
+ }
+ return Py::None();
}
Py::Object View3DInventorPy::getActiveObject(const Py::Tuple& args)
{
char* name;
- if (!PyArg_ParseTuple(args.ptr(), "s", &name))
- throw Py::Exception();
-
- App::DocumentObject* obj = _view->getActiveObject(name);
+ PyObject *resolve = Py_True;
+ if (!PyArg_ParseTuple(args.ptr(), "s|O", &name,&resolve))
+ throw Py::Exception();
+
+ App::DocumentObject *parent = 0;
+ std::string subname;
+ App::DocumentObject* obj = _view->getActiveObject(name,&parent,&subname);
if(!obj)
return Py::None();
- return Py::Object(obj->getPyObject());
+ if(PyObject_IsTrue(resolve))
+ return Py::asObject(obj->getPyObject());
+
+ return Py::TupleN(
+ Py::asObject(obj->getPyObject()),
+ Py::asObject(parent->getPyObject()),
+ Py::String(subname.c_str()));
}
Py::Object View3DInventorPy::getViewProvidersOfType(const Py::Tuple& args)