Gui: ActiveObjectList API changes
Support sub-object in ActiveObjectList. This means that it can now distinguish the same object being activated under different parent, which may be in a different document through external linking.
This commit is contained in:
@@ -28,44 +28,116 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include "ActiveObjectList.h"
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/ViewProviderDocumentObject.h>
|
||||
#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<App::DocumentObject*>(name);
|
||||
Gui::Document* doc = Application::Instance->getDocument(act->getDocument());
|
||||
Gui::ViewProviderDocumentObject* viewProvider = static_cast
|
||||
<Gui::ViewProviderDocumentObject*>(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<ViewProviderDocumentObject*>(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
|
||||
<Gui::ViewProviderDocumentObject*>(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<std::string, App::DocumentObject*>::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;
|
||||
|
||||
@@ -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<typename _T>
|
||||
inline _T getObject(const char* name) const
|
||||
{
|
||||
std::map<std::string, App::DocumentObject*>::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<std::string, App::DocumentObject*> _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<std::string, ObjectInfo> _ObjectMap;
|
||||
Document *_Doc;
|
||||
};
|
||||
|
||||
} //namespace Gui
|
||||
|
||||
@@ -113,18 +113,22 @@ public:
|
||||
|
||||
/// access getter for the active object list
|
||||
template<typename _T>
|
||||
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&);
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <CXX/Objects.hxx>
|
||||
|
||||
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<ViewProviderDocumentObject*>(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<std::string,std::string> 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<ViewProviderDocumentObject*>(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<std::string,std::string> 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<App::DocumentObjectPy*>(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<App::DocumentObjectPy*>(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<App::DocumentObject*>(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<App::DocumentObject*>(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)
|
||||
|
||||
Reference in New Issue
Block a user