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:
Zheng, Lei
2019-07-11 17:07:31 +08:00
committed by wmayer
parent 08f0511b1f
commit a9b866caa5
4 changed files with 243 additions and 100 deletions

View File

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

View File

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

View File

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

View File

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