Gui: Selection API changes

Mostly about API changes to SelectionSingleton. Also include related
changes to SelectionObject, SelectionChange, and SelectionView.

Please check out the summary of changes [here](https://git.io/fjimC)
This commit is contained in:
Zheng, Lei
2019-07-07 11:46:38 +08:00
committed by wmayer
parent b1c0de8dae
commit 49b6944a20
7 changed files with 1941 additions and 662 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,7 @@
#include <vector>
#include <list>
#include <map>
#include <deque>
#include <boost/signals2.hpp>
#include <CXX/Objects.hxx>
@@ -68,20 +69,102 @@ public:
RmvSelection,
SetSelection,
ClrSelection,
SetPreselect,
RmvPreselect
SetPreselect, // to signal observer the preselect has changed
RmvPreselect,
SetPreselectSignal, // to request 3D view to change preselect
PickedListChanged,
ShowSelection, // to show a selection
HideSelection, // to hide a selection
RmvPreselectSignal, // to request 3D view to remove preselect
MovePreselect, // to signal observer the mouse movement when preselect
};
SelectionChanges()
: Type(ClrSelection)
, pDocName(0)
, pObjectName(0)
, pSubName(0)
, pTypeName(0)
, x(0),y(0),z(0)
SelectionChanges(MsgType type = ClrSelection,
const char *docName=0, const char *objName=0,
const char *subName=0, const char *typeName=0,
float x=0, float y=0, float z=0, int subtype=0)
: Type(type),SubType(subtype)
, x(x),y(y),z(z)
{
if(docName) DocName=docName;
pDocName = DocName.c_str();
if(objName) ObjName = objName;
pObjectName = ObjName.c_str();
if(subName) SubName = subName;
pSubName = SubName.c_str();
if(typeName) TypeName = typeName;
pTypeName = TypeName.c_str();
}
SelectionChanges(MsgType type,
const std::string &docName,
const std::string &objName,
const std::string &subName,
const std::string &typeName = std::string(),
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)
, TypeName(typeName)
{
pDocName = DocName.c_str();
pObjectName = ObjName.c_str();
pSubName = SubName.c_str();
pTypeName = TypeName.c_str();
}
SelectionChanges(const SelectionChanges &other) {
*this = other;
}
SelectionChanges &operator=(const SelectionChanges &other) {
Type = other.Type;
SubType = other.SubType;
x = other.x;
y = other.y;
z = other.z;
DocName = other.DocName;
ObjName = other.ObjName;
SubName = other.SubName;
TypeName = other.TypeName;
pDocName = DocName.c_str();
pObjectName = ObjName.c_str();
pSubName = SubName.c_str();
pTypeName = TypeName.c_str();
pOriginalMsg = other.pOriginalMsg;
pSubObject = other.pSubObject;
pParentObject = other.pParentObject;
return *this;
}
SelectionChanges(SelectionChanges &&other) {
*this = std::move(other);
}
SelectionChanges &operator=(SelectionChanges &&other) {
Type = other.Type;
SubType = other.SubType;
x = other.x;
y = other.y;
z = other.z;
DocName = std::move(other.DocName);
ObjName = std::move(other.ObjName);
SubName = std::move(other.SubName);
TypeName = std::move(other.TypeName);
pDocName = DocName.c_str();
pObjectName = ObjName.c_str();
pSubName = SubName.c_str();
pTypeName = TypeName.c_str();
pOriginalMsg = other.pOriginalMsg;
pSubObject = other.pSubObject;
pParentObject = other.pParentObject;
return *this;
}
MsgType Type;
int SubType;
const char* pDocName;
const char* pObjectName;
@@ -90,6 +173,22 @@ public:
float x;
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;
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;
};
} //namespace Gui
@@ -118,6 +217,7 @@ template class GuiExport Base::Subject<const Gui::SelectionChanges&>;
namespace Gui
{
class ViewProviderDocumentObject;
/**
* The SelectionObserver class simplifies the step to write classes that listen
@@ -130,10 +230,12 @@ class GuiExport SelectionObserver
public:
/// Constructor
SelectionObserver();
SelectionObserver(bool attach = true, int resolve = 1);
SelectionObserver(const Gui::ViewProviderDocumentObject *vp, bool attach=true, int resolve=1);
virtual ~SelectionObserver();
bool blockConnection(bool block);
bool isConnectionBlocked() const;
bool isConnectionAttached() const;
/** Attaches to the selection. */
void attachSelection();
@@ -147,6 +249,9 @@ private:
private:
typedef boost::signals2::connection Connection;
Connection connectSelection;
std::string filterDocName;
std::string filterObjName;
int resolve;
bool blockSelection;
};
@@ -162,10 +267,10 @@ class GuiExport SelectionObserverPython : public SelectionObserver
public:
/// Constructor
SelectionObserverPython(const Py::Object& obj);
SelectionObserverPython(const Py::Object& obj, int resolve=1);
virtual ~SelectionObserverPython();
static void addObserver(const Py::Object& obj);
static void addObserver(const Py::Object& obj, int resolve=1);
static void removeObserver(const Py::Object& obj);
private:
@@ -176,9 +281,26 @@ private:
void clearSelection(const SelectionChanges&);
void setPreselection(const SelectionChanges&);
void removePreselection(const SelectionChanges&);
void pickedListChanged();
private:
Py::Object inst;
#define FC_PY_SEL_OBSERVER \
FC_PY_ELEMENT(onSelectionChanged) \
FC_PY_ELEMENT(addSelection) \
FC_PY_ELEMENT(removeSelection) \
FC_PY_ELEMENT(setSelection) \
FC_PY_ELEMENT(clearSelection) \
FC_PY_ELEMENT(setPreselection) \
FC_PY_ELEMENT(removePreselection) \
FC_PY_ELEMENT(pickedListChanged)
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) Py::Object py_##_name;
FC_PY_SEL_OBSERVER
static std::vector<SelectionObserverPython*> _instances;
};
@@ -201,6 +323,18 @@ public:
std::string notAllowedReason;
};
/** SelectionGateFilterExternal
* The selection gate disallows any external object
*/
class GuiExport SelectionGateFilterExternal: public SelectionGate
{
public:
SelectionGateFilterExternal(const char *docName, const char *objName=0);
virtual bool allow(App::Document*,App::DocumentObject*, const char*) override;
private:
std::string DocName;
std::string ObjName;
};
/** The Selection class
* The selection singleton keeps track of the selection state of
@@ -220,70 +354,6 @@ public:
class GuiExport SelectionSingleton : public Base::Subject<const SelectionChanges&>
{
public:
/// Add to selection
bool addSelection(const char* pDocName, const char* pObjectName=0, const char* pSubName=0, float x=0, float y=0, float z=0);
/// Add to selection with several sub-elements
bool addSelection(const char* pDocName, const char* pObjectName, const std::vector<std::string>& pSubNames);
/// Add to selection
bool addSelection(const SelectionObject&);
/// Remove from selection (for internal use)
void rmvSelection(const char* pDocName, const char* pObjectName=0, const char* pSubName=0);
/// Set the selection for a document
void setSelection(const char* pDocName, const std::vector<App::DocumentObject*>&);
/// Clear the selection of document \a pDocName. If the document name is not given the selection of the active document is cleared.
void clearSelection(const char* pDocName=0);
/// Clear the selection of all documents
void clearCompleteSelection();
/// Check if selected
bool isSelected(const char* pDocName, const char* pObjectName=0, const char* pSubName=0) const;
/// Check if selected
bool isSelected(App::DocumentObject*, const char* pSubName=0) const;
/// set the preselected object (mostly by the 3D view)
bool setPreselect(const char* pDocName, const char* pObjectName, const char* pSubName, float x=0, float y=0, float z=0);
/// remove the present preselection
void rmvPreselect();
/// sets different coords for the preselection
void setPreselectCoord(float x, float y, float z);
/// returns the present preselection
const SelectionChanges& getPreselection(void) const;
/// add a SelectionGate to control what is selectable
void addSelectionGate(Gui::SelectionGate *gate);
/// remove the active SelectionGate
void rmvSelectionGate(void);
/** Returns the number of selected objects with a special object type
* It's the convenient way to check if the right objects are selected to
* perform an operation (GuiCommand). The check also detects base types.
* E.g. "Part" also fits on "PartImport" or "PartTransform types.
* If no document name is given the active document is assumed.
*/
unsigned int countObjectsOfType(const Base::Type& typeId, const char* pDocName=0) const;
/**
* Does basically the same as the method above unless that it accepts a string literal as first argument.
* \a typeName must be a registered type, otherwise 0 is returned.
*/
unsigned int countObjectsOfType(const char* typeName, const char* pDocName=0) const;
/** Returns a vector of objects of type \a TypeName selected for the given document name \a pDocName.
* If no document name is specified the objects from the active document are regarded.
* If no objects of this document are selected an empty vector is returned.
* @note The vector reflects the sequence of selection.
*/
std::vector<App::DocumentObject*> getObjectsOfType(const Base::Type& typeId, const char* pDocName=0) const;
/**
* Does basically the same as the method above unless that it accepts a string literal as first argument.
* \a typeName must be a registered type otherwise an empty array is returned.
*/
std::vector<App::DocumentObject*> getObjectsOfType(const char* typeName, const char* pDocName=0) const;
/**
* A convenience template-based method that returns an array with the correct types already.
*/
template<typename T> inline std::vector<T*> getObjectsOfType(const char* pDocName=0) const;
struct SelObj {
const char* DocName;
const char* FeatName;
@@ -291,24 +361,139 @@ public:
const char* TypeName;
App::Document* pDoc;
App::DocumentObject* pObject;
App::DocumentObject* pResolvedObject;
float x,y,z;
};
/// Add to selection
bool addSelection(const char* pDocName, const char* pObjectName=0, const char* pSubName=0,
float x=0, float y=0, float z=0, const std::vector<SelObj> *pickedList = 0, bool clearPreSelect=true);
bool addSelection2(const char* pDocName, const char* pObjectName=0, const char* pSubName=0,
float x=0, float y=0, float z=0, const std::vector<SelObj> *pickedList = 0)
{
return addSelection(pDocName,pObjectName,pSubName,x,y,z,pickedList,false);
}
/// Add to selection
bool addSelection(const SelectionObject&, bool clearPreSelect=true);
/// Add to selection with several sub-elements
bool addSelections(const char* pDocName, const char* pObjectName, const std::vector<std::string>& pSubNames);
/// Update a selection
bool updateSelection(bool show, const char* pDocName, const char* pObjectName=0, const char* pSubName=0);
/// Remove from selection (for internal use)
void rmvSelection(const char* pDocName, const char* pObjectName=0, const char* pSubName=0,
const std::vector<SelObj> *pickedList = 0);
/// Set the selection for a document
void setSelection(const char* pDocName, const std::vector<App::DocumentObject*>&);
/// Clear the selection of document \a pDocName. If the document name is not given the selection of the active document is cleared.
void clearSelection(const char* pDocName=0, bool clearPreSelect=true);
/// Clear the selection of all documents
void clearCompleteSelection(bool clearPreSelect=true);
/// Check if selected
bool isSelected(const char* pDocName, const char* pObjectName=0,
const char* pSubName=0, int resolve=1) const;
/// Check if selected
bool isSelected(App::DocumentObject*, const char* pSubName=0, int resolve=1) const;
const char *getSelectedElement(App::DocumentObject*, const char* pSubName) const;
/// set the preselected object (mostly by the 3D view)
int setPreselect(const char* pDocName, const char* pObjectName,
const char* pSubName, float x=0, float y=0, float z=0, int signal=0);
/// remove the present preselection
void rmvPreselect(bool signal=false);
/// sets different coords for the preselection
void setPreselectCoord(float x, float y, float z);
/// returns the present preselection
const SelectionChanges& getPreselection(void) const;
/// add a SelectionGate to control what is selectable
void addSelectionGate(Gui::SelectionGate *gate, int resolve = 1);
/// remove the active SelectionGate
void rmvSelectionGate(void);
int disableCommandLog();
int enableCommandLog(bool silent=false);
/** Returns the number of selected objects with a special object type
* It's the convenient way to check if the right objects are selected to
* perform an operation (GuiCommand). The check also detects base types.
* E.g. "Part" also fits on "PartImport" or "PartTransform types.
* If no document name is given the active document is assumed.
*
* Set 'resolve' to true to resolve any sub object inside selection SubName
* field
*/
unsigned int countObjectsOfType(const Base::Type& typeId=App::DocumentObject::getClassTypeId(),
const char* pDocName=0, int resolve=1) const;
/**
* Does basically the same as the method above unless that it accepts a string literal as first argument.
* \a typeName must be a registered type, otherwise 0 is returned.
*/
unsigned int countObjectsOfType(const char* typeName,
const char* pDocName=0, int resolve=1) const;
/** Returns a vector of objects of type \a TypeName selected for the given document name \a pDocName.
* If no document name is specified the objects from the active document are regarded.
* If no objects of this document are selected an empty vector is returned.
* @note The vector reflects the sequence of selection.
*/
std::vector<App::DocumentObject*> getObjectsOfType(const Base::Type& typeId,
const char* pDocName=0, int resolve=1) const;
/**
* Does basically the same as the method above unless that it accepts a string literal as first argument.
* \a typeName must be a registered type otherwise an empty array is returned.
*/
std::vector<App::DocumentObject*> getObjectsOfType(const char* typeName,
const char* pDocName=0, int resolve=1) const;
/**
* A convenience template-based method that returns an array with the correct types already.
*/
template<typename T> inline std::vector<T*> getObjectsOfType(
const char* pDocName=0, int resolve=1) const;
/** Set selection object visibility
*
* @param visible: 1: make visible, 0: make invisible, -1: toggle visibility
*/
void setVisible(int visible);
/// signal on new object
boost::signals2::signal<void (const SelectionChanges& msg)> signalSelectionChanged;
/// signal on selection change with resolved object
boost::signals2::signal<void (const SelectionChanges& msg)> signalSelectionChanged2;
/// signal on selection change with resolved object and sub element map
boost::signals2::signal<void (const SelectionChanges& msg)> signalSelectionChanged3;
/** Returns a vector of selection objects
* If no document name is given the objects of the active are returned.
* If nothing for this Document is selected an empty vector is returned.
* The vector reflects the sequence of selection.
*
* @param pDocName: document name. If no document name is given the objects
* of the active are returned. If nothing for this Document is selected an
* empty vector is returned. If document name is "*", then all document is
* considered.
* @param resolve: whether to resolve the subname reference of the selection
* @param single: if set to true, then it will return an empty vector if
* there is more than one selections.
*
* @return The returned vector reflects the sequence of selection.
*/
std::vector<SelObj> getSelection(const char* pDocName=0) const;
std::vector<SelObj> getSelection(const char* pDocName=0, int resolve=1, bool single=false) const;
/** Returns a vector of selection objects
* If no document name is given the objects of the active are returned.
* If nothing for this document is selected an empty vector is returned.
* The vector reflects the sequence of selection.
*
* @param pDocName: document name. If no document name is given the objects
* of the active are returned. If nothing for this Document is selected an
* empty vector is returned. If document name is "*", then all document is
* considered.
* @param typeId: specify the type of object to be returned.
* @param resolve: whether to resolve the subname reference of the selection
* @param single: if set to true, then it will return an empty vector if
* there is more than one selections.
*
* @return The returned vector reflects the sequence of selection.
*/
std::vector<Gui::SelectionObject> getSelectionEx(const char* pDocName=0,Base::Type typeId=App::DocumentObject::getClassTypeId()) const;
std::vector<Gui::SelectionObject> getSelectionEx(const char* pDocName=0,Base::Type typeId=App::DocumentObject::getClassTypeId(),int resolve=1, bool single=false) const;
/**
* @brief getAsPropertyLinkSubList fills PropertyLinkSubList with current selection.
@@ -318,15 +503,29 @@ public:
int getAsPropertyLinkSubList(App::PropertyLinkSubList &prop) const;
/** Returns a vector of all selection objects of all documents. */
std::vector<SelObj> getCompleteSelection() const;
std::vector<SelObj> getCompleteSelection(int resolve=1) const;
bool hasSelection() const;
bool hasSelection(const char* doc) const;
bool hasSelection(const char* doc, bool resolve=true) const;
bool hasSubSelection(const char *doc=0) const;
bool hasPreselection() const;
/// Size of selected entities for all documents
unsigned int size(void) const {
return static_cast<unsigned int>(_SelList.size());
}
int selStackBackSize() const {return _SelStackBack.size();}
int selStackForwardSize() const {return _SelStackForward.size();}
std::vector<Gui::SelectionObject> selStackGet(const char* pDocName=0,int resolve=1,int index=0) const;
void selStackGoBack(int count=1);
void selStackGoForward(int count=1);
void selStackPush(bool clearForward=true, bool overwrite=false);
bool needPickedList() const;
void enablePickedList(bool);
bool hasPickedList() const;
std::vector<SelectionSingleton::SelObj> getPickedList(const char* pDocName) const;
std::vector<Gui::SelectionObject> getPickedListEx(const char* pDocName=0,Base::Type typeId=App::DocumentObject::getClassTypeId()) const;
static SelectionSingleton& instance(void);
static void destruct (void);
friend class SelectionFilter;
@@ -336,12 +535,13 @@ public:
protected:
static PyObject *sAddSelection (PyObject *self,PyObject *args);
static PyObject *sUpdateSelection (PyObject *self,PyObject *args);
static PyObject *sRemoveSelection (PyObject *self,PyObject *args);
static PyObject *sClearSelection (PyObject *self,PyObject *args);
static PyObject *sIsSelected (PyObject *self,PyObject *args);
static PyObject *sCountObjectsOfType (PyObject *self,PyObject *args);
static PyObject *sGetSelection (PyObject *self,PyObject *args);
static PyObject *sSetPreselection (PyObject *self,PyObject *args);
static PyObject *sSetPreselection (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetPreselection (PyObject *self,PyObject *args);
static PyObject *sRemPreselection (PyObject *self,PyObject *args);
static PyObject *sGetCompleteSelection(PyObject *self,PyObject *args);
@@ -351,6 +551,14 @@ protected:
static PyObject *sRemSelObserver (PyObject *self,PyObject *args);
static PyObject *sAddSelectionGate (PyObject *self,PyObject *args);
static PyObject *sRemoveSelectionGate (PyObject *self,PyObject *args);
static PyObject *sGetPickedList (PyObject *self,PyObject *args);
static PyObject *sEnablePickedList (PyObject *self,PyObject *args);
static PyObject *sPreselect (PyObject *self,PyObject *args);
static PyObject *sSetVisible (PyObject *self,PyObject *args);
static PyObject *sPushSelStack (PyObject *self,PyObject *args);
static PyObject *sHasSelection (PyObject *self,PyObject *args);
static PyObject *sHasSubSelection (PyObject *self,PyObject *args);
static PyObject *sGetSelectionFromStack(PyObject *self,PyObject *args);
protected:
/// Construction
@@ -364,8 +572,16 @@ protected:
/// helper to retrieve document by name
App::Document* getDocument(const char* pDocName=0) const;
void slotSelectionChanged(const SelectionChanges& msg);
SelectionChanges CurrentPreselection;
std::deque<SelectionChanges> NotificationQueue;
bool Notifying = false;
void notify(SelectionChanges &&Chng);
void notify(const SelectionChanges &Chng) { notify(SelectionChanges(Chng)); }
struct _SelObj {
std::string DocName;
std::string FeatName;
@@ -374,8 +590,29 @@ protected:
App::Document* pDoc;
App::DocumentObject* pObject;
float x,y,z;
bool logged = false;
std::pair<std::string,std::string> elementName;
App::DocumentObject* pResolvedObject = 0;
void log(bool remove=false, bool clearPreselect=true);
};
std::list<_SelObj> _SelList;
mutable std::list<_SelObj> _SelList;
mutable std::list<_SelObj> _PickedList;
bool _needPickedList;
typedef std::set<std::array<std::string,3> > SelStackItem;
std::deque<SelStackItem> _SelStackBack;
std::deque<SelStackItem> _SelStackForward;
int checkSelection(const char *pDocName, const char *pObjectName,
const char *pSubName,int resolve, _SelObj &sel, const std::list<_SelObj> *selList=0) const;
std::vector<Gui::SelectionObject> getObjectList(const char* pDocName,Base::Type typeId, std::list<_SelObj> &objs, int resolve, bool single=false) const;
static App::DocumentObject *getObjectOfType(_SelObj &sel, Base::Type type,
int resolve, const char **subelement=0);
static SelectionSingleton* _pcSingleton;
@@ -385,16 +622,20 @@ protected:
float hx,hy,hz;
Gui::SelectionGate *ActiveGate;
int gateResolve;
int logDisabled = 0;
bool logHasSelection = false;
};
/**
* A convenience template-based method that returns an array with the correct types already.
*/
template<typename T>
inline std::vector<T*> SelectionSingleton::getObjectsOfType(const char* pDocName) const
inline std::vector<T*> SelectionSingleton::getObjectsOfType(const char* pDocName, int resolve) const
{
std::vector<T*> type;
std::vector<App::DocumentObject*> obj = this->getObjectsOfType(T::getClassTypeId(), pDocName);
std::vector<App::DocumentObject*> obj = this->getObjectsOfType(T::getClassTypeId(), pDocName, resolve);
type.reserve(obj.size());
for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it)
type.push_back(static_cast<T*>(*it));
@@ -407,6 +648,18 @@ inline SelectionSingleton& Selection(void)
return SelectionSingleton::instance();
}
class GuiExport SelectionLogDisabler {
public:
SelectionLogDisabler(bool silent=false) :silent(silent) {
Selection().disableCommandLog();
}
~SelectionLogDisabler() {
Selection().enableCommandLog(silent);
}
private:
bool silent;
};
} //namespace Gui
#endif // GUI_SELECTION_H

View File

@@ -33,6 +33,7 @@
#include "SelectionObject.h"
#include "Selection.h"
#include "Application.h"
#include "Command.h"
#include <Gui/SelectionObjectPy.h>
using namespace Gui;
@@ -94,22 +95,12 @@ bool SelectionObject::isObjectTypeOf(const Base::Type& typeId) const
std::string SelectionObject::getAsPropertyLinkSubString(void)const
{
std::string buf;
buf += "(App.";
buf += "ActiveDocument";//getObject()->getDocument()->getName();
buf += ".";
buf += getObject()->getNameInDocument();
buf += ",[";
for(std::vector<std::string>::const_iterator it = SubNames.begin();it!=SubNames.end();++it){
buf += "\"";
buf += *it;
buf += "\"";
if(it != --SubNames.end())
buf += ",";
}
buf += "])";
return buf;
std::ostringstream str;
str << "(" << Gui::Command::getObjectCmd(getObject()) << ",[";
for(std::vector<std::string>::const_iterator it = SubNames.begin();it!=SubNames.end();++it)
str << "'" << *it << "',";
str << "])";
return str.str();
}
PyObject* SelectionObject::getPyObject()

View File

@@ -49,7 +49,7 @@ public:
/*! Constructs a SelectionObject from the SelectionChanges structure.
*/
SelectionObject(const SelectionChanges& msg);
SelectionObject(App::DocumentObject*);
explicit SelectionObject(App::DocumentObject*);
virtual ~SelectionObject();
/**
* The default implementation returns an instance of @ref SelectionObjectPy.
@@ -89,6 +89,9 @@ protected:
std::string TypeName;
std::vector<Base::Vector3d> SelPoses;
private:
/// to make sure no duplicates of subnames
std::set<std::string> _SubNameSet;
};

View File

@@ -110,7 +110,14 @@ Py::Object SelectionObjectPy::getObject(void) const
Py::Tuple SelectionObjectPy::getSubObjects(void) const
{
std::vector<PyObject *> objs = getSelectionObjectPtr()->getObject()->getPySubObjects(getSelectionObjectPtr()->getSubNames());
std::vector<PyObject *> objs;
for(const auto &subname : getSelectionObjectPtr()->getSubNames()) {
PyObject *pyObj=0;
Base::Matrix4D mat;
getSelectionObjectPtr()->getObject()->getSubObject(subname.c_str(),&pyObj,&mat);
if(pyObj) objs.push_back(pyObj);
}
Py::Tuple temp(objs.size());
Py::sequence_index_type index = 0;

View File

@@ -29,11 +29,13 @@
# include <QLineEdit>
# include <QTextStream>
# include <QToolButton>
#include <QCheckBox>
# include <QMenu>
# include <QLabel>
#endif
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <App/Document.h>
#include <App/GeoFeature.h>
#include "SelectionView.h"
@@ -43,7 +45,7 @@
#include "ViewProvider.h"
#include "BitmapFactory.h"
FC_LOG_LEVEL_INIT("Selection",true,true,true)
using namespace Gui;
using namespace Gui::DockWnd;
@@ -53,6 +55,7 @@ using namespace Gui::DockWnd;
SelectionView::SelectionView(Gui::Document* pcDocument, QWidget *parent)
: DockWindow(pcDocument,parent)
, SelectionObserver(false,0)
{
setWindowTitle(tr("Selection View"));
@@ -85,27 +88,45 @@ SelectionView::SelectionView(Gui::Document* pcDocument, QWidget *parent)
selectionView = new QListWidget(this);
selectionView->setContextMenuPolicy(Qt::CustomContextMenu);
vLayout->addWidget( selectionView );
enablePickList = new QCheckBox(this);
enablePickList->setText(tr("Picked object list"));
vLayout->addWidget(enablePickList);
pickList = new QListWidget(this);
pickList->setVisible(false);
vLayout->addWidget(pickList);
#if QT_VERSION >= 0x040200
selectionView->setMouseTracking(true); // needed for itemEntered() to work
pickList->setMouseTracking(true);
#endif
resize(200, 200);
connect(clearButton, SIGNAL(clicked()), searchBox, SLOT(clear()));
connect(searchBox, SIGNAL(textChanged(QString)), this, SLOT(search(QString)));
connect(searchBox, SIGNAL(editingFinished()), this, SLOT(validateSearch()));
connect(selectionView, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(select(QListWidgetItem*)));
connect(selectionView, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(toggleSelect(QListWidgetItem*)));
connect(selectionView, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(preselect(QListWidgetItem*)));
connect(pickList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(toggleSelect(QListWidgetItem*)));
connect(pickList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(preselect(QListWidgetItem*)));
connect(selectionView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onItemContextMenu(QPoint)));
connect(enablePickList, SIGNAL(stateChanged(int)), this, SLOT(onEnablePickList()));
Gui::Selection().Attach(this);
}
SelectionView::~SelectionView()
{
Gui::Selection().Detach(this);
}
void SelectionView::leaveEvent(QEvent *)
{
Selection().rmvPreselect();
}
/// @cond DOXERR
void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
Gui::SelectionSingleton::MessageType Reason)
void SelectionView::onSelectionChanged(const SelectionChanges &Reason)
{
Q_UNUSED(rCaller);
QString selObject;
QTextStream str(&selObject);
if (Reason.Type == SelectionChanges::AddSelection) {
@@ -116,16 +137,17 @@ void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
// insert the selection as item
str << Reason.pDocName;
str << ".";
str << "#";
str << Reason.pObjectName;
App::Document* doc = App::GetApplication().getDocument(Reason.pDocName);
App::DocumentObject* obj = doc->getObject(Reason.pObjectName);
if (Reason.pSubName[0] != 0 ) {
str << ".";
str << Reason.pSubName;
list << QString::fromLatin1(Reason.pSubName);
auto subObj = obj->getSubObject(Reason.pSubName);
if(subObj)
obj = subObj;
}
App::Document* doc = App::GetApplication().getDocument(Reason.pDocName);
App::DocumentObject* obj = doc->getObject(Reason.pObjectName);
str << " (";
str << QString::fromUtf8(obj->Label.getValue());
str << ")";
@@ -134,26 +156,31 @@ void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
item->setData(Qt::UserRole, list);
}
else if (Reason.Type == SelectionChanges::ClrSelection) {
// remove all items
selectionView->clear();
if(!Reason.pDocName[0]) {
// remove all items
selectionView->clear();
}else{
// build name
str << Reason.pDocName;
str << "#";
// remove all items
for(auto item : selectionView->findItems(selObject,Qt::MatchStartsWith))
delete item;
}
}
else if (Reason.Type == SelectionChanges::RmvSelection) {
// build name
str << Reason.pDocName;
str << ".";
str << "#";
str << Reason.pObjectName;
if (Reason.pSubName[0] != 0) {
str << ".";
str << Reason.pSubName;
}
App::Document* doc = App::GetApplication().getDocument(Reason.pDocName);
App::DocumentObject* obj = doc->getObject(Reason.pObjectName);
str << " (";
str << QString::fromUtf8(obj->Label.getValue());
str << ")";
// remove all items
QList<QListWidgetItem *> l = selectionView->findItems(selObject,Qt::MatchExactly);
QList<QListWidgetItem *> l = selectionView->findItems(selObject,Qt::MatchStartsWith);
if (l.size() == 1)
delete l[0];
@@ -161,7 +188,7 @@ void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
else if (Reason.Type == SelectionChanges::SetSelection) {
// remove all items
selectionView->clear();
std::vector<SelectionSingleton::SelObj> objs = Gui::Selection().getSelection(Reason.pDocName);
std::vector<SelectionSingleton::SelObj> objs = Gui::Selection().getSelection(Reason.pDocName,0);
for (std::vector<SelectionSingleton::SelObj>::iterator it = objs.begin(); it != objs.end(); ++it) {
// save as user data
QStringList list;
@@ -170,16 +197,17 @@ void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
// build name
str << it->DocName;
str << ".";
str << "#";
str << it->FeatName;
App::Document* doc = App::GetApplication().getDocument(it->DocName);
App::DocumentObject* obj = doc->getObject(it->FeatName);
if (it->SubName && it->SubName[0] != '\0') {
str << ".";
str << it->SubName;
list << QString::fromLatin1(it->SubName);
auto subObj = obj->getSubObject(Reason.pSubName);
if(subObj)
obj = subObj;
}
App::Document* doc = App::GetApplication().getDocument(it->DocName);
App::DocumentObject* obj = doc->getObject(it->FeatName);
str << " (";
str << QString::fromUtf8(obj->Label.getValue());
str << ")";
@@ -189,6 +217,43 @@ void SelectionView::OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
selObject.clear();
}
}
else if (Reason.Type == SelectionChanges::PickedListChanged) {
bool picking = Selection().needPickedList();
enablePickList->setChecked(picking);
pickList->setVisible(picking);
pickList->clear();
if(picking) {
const auto &sels = Selection().getPickedList(Reason.pDocName);
for(const auto &sel : sels) {
App::Document* doc = App::GetApplication().getDocument(sel.DocName);
if(!doc) continue;
App::DocumentObject* obj = doc->getObject(sel.FeatName);
if(!obj) continue;
QString selObject;
QTextStream str(&selObject);
str << sel.DocName;
str << "#";
str << sel.FeatName;
if (sel.SubName[0] != 0 ) {
str << ".";
str << sel.SubName;
auto subObj = obj->getSubObject(sel.SubName);
if(subObj)
obj = subObj;
}
str << " (";
str << QString::fromUtf8(obj->Label.getValue());
str << ")";
this->x = sel.x;
this->y = sel.y;
this->z = sel.z;
new QListWidgetItem(selObject, pickList);
}
}
}
countLabel->setText(QString::number(selectionView->count()));
}
@@ -213,8 +278,8 @@ void SelectionView::search(const QString& text)
list << QString::fromLatin1(doc->getName());
list << QString::fromLatin1((*it)->getNameInDocument());
// build name
str << doc->getName();
str << ".";
str << QString::fromUtf8(doc->Label.getValue());
str << "#";
str << (*it)->getNameInDocument();
str << " (";
str << label;
@@ -235,9 +300,7 @@ void SelectionView::validateSearch(void)
if (doc) {
Gui::Selection().clearSelection();
for (std::vector<App::DocumentObject*>::iterator it = searchList.begin(); it != searchList.end(); ++it) {
if (!Gui::Selection().hasSelection((*it)->getNameInDocument())) {
Gui::Selection().addSelection(doc->getName(),(*it)->getNameInDocument(),0);
}
Gui::Selection().addSelection(doc->getName(),(*it)->getNameInDocument(),0);
}
}
}
@@ -253,11 +316,15 @@ void SelectionView::select(QListWidgetItem* item)
if (elements.size() < 2)
return;
//Gui::Selection().clearSelection();
Gui::Command::runCommand(Gui::Command::Gui,"Gui.Selection.clearSelection()");
//Gui::Selection().addSelection(elements[0].toLatin1(),elements[1].toLatin1(),0);
QString cmd = QString::fromLatin1("Gui.Selection.addSelection(App.getDocument(\"%1\").getObject(\"%2\"))").arg(elements[0], elements[1]);
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
try {
//Gui::Selection().clearSelection();
Gui::Command::runCommand(Gui::Command::Gui,"Gui.Selection.clearSelection()");
//Gui::Selection().addSelection(elements[0].toLatin1(),elements[1].toLatin1(),0);
QString cmd = QString::fromLatin1("Gui.Selection.addSelection(App.getDocument(\"%1\").getObject(\"%2\"))").arg(elements[0],elements[1]);
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::deselect(void)
@@ -270,20 +337,99 @@ void SelectionView::deselect(void)
return;
//Gui::Selection().rmvSelection(elements[0].toLatin1(),elements[1].toLatin1(),0);
QString cmd = QString::fromLatin1("Gui.Selection.removeSelection(App.getDocument(\"%1\").getObject(\"%2\"))").arg(elements[0], elements[1]);
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
QString cmd = QString::fromLatin1("Gui.Selection.removeSelection(App.getDocument(\"%1\").getObject(\"%2\"))").arg(elements[0],elements[1]);
try {
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::toggleSelect(QListWidgetItem* item)
{
if (!item) return;
std::string name = item->text().toLatin1().constData();
char *docname = &name.at(0);
char *objname = std::strchr(docname,'#');
if(!objname) return;
*objname++ = 0;
char *subname = std::strchr(objname,'.');
if(subname) {
*subname++ = 0;
char *end = std::strchr(subname,' ');
if(end) *end = 0;
}else {
char *end = std::strchr(objname,' ');
if(end) *end = 0;
}
QString cmd;
if(Gui::Selection().isSelected(docname,objname,subname))
cmd = QString::fromLatin1("Gui.Selection.removeSelection("
"App.getDocument('%1').getObject('%2'),'%3')")
.arg(QString::fromLatin1(docname))
.arg(QString::fromLatin1(objname))
.arg(QString::fromLatin1(subname));
else
cmd = QString::fromLatin1("Gui.Selection.addSelection("
"App.getDocument('%1').getObject('%2'),'%3',%4,%5,%6)")
.arg(QString::fromLatin1(docname))
.arg(QString::fromLatin1(objname))
.arg(QString::fromLatin1(subname))
.arg(x).arg(y).arg(z);
try {
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::preselect(QListWidgetItem* item)
{
if (!item) return;
std::string name = item->text().toLatin1().constData();
char *docname = &name.at(0);
char *objname = std::strchr(docname,'#');
if(!objname) return;
*objname++ = 0;
char *subname = std::strchr(objname,'.');
if(subname) {
*subname++ = 0;
char *end = std::strchr(subname,' ');
if(end) *end = 0;
}else {
char *end = std::strchr(objname,' ');
if(end) *end = 0;
}
QString cmd = QString::fromLatin1("Gui.Selection.setPreselection("
"App.getDocument('%1').getObject('%2'),'%3',tp=2)")
.arg(QString::fromLatin1(docname))
.arg(QString::fromLatin1(objname))
.arg(QString::fromLatin1(subname));
try {
Gui::Command::runCommand(Gui::Command::Gui,cmd.toLatin1());
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::zoom(void)
{
select();
Gui::Command::runCommand(Gui::Command::Gui,"Gui.SendMsgToActiveView(\"ViewSelection\")");
try {
Gui::Command::runCommand(Gui::Command::Gui,"Gui.SendMsgToActiveView(\"ViewSelection\")");
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::treeSelect(void)
{
select();
Gui::Command::runCommand(Gui::Command::Gui,"Gui.runCommand(\"Std_TreeSelection\")");
try {
Gui::Command::runCommand(Gui::Command::Gui,"Gui.runCommand(\"Std_TreeSelection\")");
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::touch(void)
@@ -294,8 +440,12 @@ void SelectionView::touch(void)
QStringList elements = item->data(Qt::UserRole).toStringList();
if (elements.size() < 2)
return;
QString cmd = QString::fromLatin1("App.getDocument(\"%1\").getObject(\"%2\").touch()").arg(elements[0], elements[1]);
Gui::Command::runCommand(Gui::Command::Doc,cmd.toLatin1());
QString cmd = QString::fromLatin1("App.getDocument(\"%1\").getObject(\"%2\").touch()").arg(elements[0],elements[1]);
try {
Gui::Command::runCommand(Gui::Command::Doc,cmd.toLatin1());
}catch(Base::Exception &e) {
e.ReportException();
}
}
void SelectionView::toPython(void)
@@ -455,6 +605,26 @@ bool SelectionView::onMsg(const char* /*pMsg*/,const char** /*ppReturn*/)
{
return false;
}
void SelectionView::hideEvent(QHideEvent *ev) {
FC_TRACE(this << " detaching selection observer");
this->detachSelection();
DockWindow::hideEvent(ev);
}
void SelectionView::showEvent(QShowEvent *ev) {
FC_TRACE(this << " attaching selection observer");
this->attachSelection();
enablePickList->setChecked(Selection().needPickedList());
Gui::DockWindow::showEvent(ev);
}
void SelectionView::onEnablePickList() {
bool enabled = enablePickList->isChecked();
Selection().enablePickedList(enabled);
pickList->setVisible(enabled);
}
/// @endcond
#include "moc_SelectionView.cpp"

View File

@@ -30,6 +30,8 @@
#include "Selection.h"
class QListWidget;
class QListWidgetItem;
class QCheckBox;
class QLabel;
namespace App {
@@ -42,7 +44,7 @@ namespace DockWnd {
/** A test class. A more elaborate class description.
*/
class SelectionView : public Gui::DockWindow,
public Gui::SelectionSingleton::ObserverType
public Gui::SelectionObserver
{
Q_OBJECT
@@ -60,9 +62,9 @@ public:
virtual ~SelectionView();
/// Observer message from the Selection
virtual void OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
Gui::SelectionSingleton::MessageType Reason);
virtual void onSelectionChanged(const SelectionChanges& msg);
virtual void leaveEvent(QEvent*) override;
bool onMsg(const char* pMsg,const char** ppReturn);
@@ -74,6 +76,9 @@ public:
QListWidget* selectionView;
QLabel* countLabel;
QCheckBox *enablePickList;
QListWidget *pickList;
public Q_SLOTS:
/// get called when text is entered in the search box
void search(const QString& text);
@@ -89,11 +94,21 @@ public Q_SLOTS:
void toPython(void);
void touch(void);
void showPart(void);
void onEnablePickList();
void toggleSelect(QListWidgetItem* item=0);
void preselect(QListWidgetItem* item=0);
protected:
void showEvent(QShowEvent *) override;
void hideEvent(QHideEvent *) override;
private:
QString getModule(const char* type) const;
QString getProperty(App::DocumentObject* obj) const;
bool supportPart(App::DocumentObject* obj, const QString& part) const;
private:
float x,y,z;
std::vector<App::DocumentObject*> searchList;
};