App: add New APIs for future Link function

DocumentObject:

* getSubObject(): the most important API for Link to work with
  hierarchies. The function is a inspired from and replaces the
  getPySubObjects(). It returns a child object following a dot separated
  subname reference, and can optionally return accumulated
  transformation, and/or a python object of the refered
  sub-object/element. The default implementation here is to look for
  link type property, and search for the referenced object. This patch also
  include other specialized implementation of this API, such as
  (GeoFeature)GroupExtension (through extensionGetSubObject()),
  PartDesign::Body, and so on. A link type object is expected to
  call the linked object's getSubObject() for resolving.

* getSubObjectList(): helper function to return a list of object
  referenced in the given subname.

* getSubObjects(): return a list of subname references of all children
  objects. The purpose of this function is similar to
  ViewProvider::claimChildren().  Container type object is expected to
  implement this function.  The reason it returns subname references
  instead of just object is to allow the container to skip hierarchies.
  For example, the Assembly3 container uses this to skip the constraint
  and element group.

* getLinkedObject(), obtain the linked object, and optionally with the
  accumulated transformation. It is expected to return a linked object
  or the object itself if it is not a link. In case there are multiple
  levels of linking involved, this function allows the caller to retrieve
  the linked object recursively.

* hasChildElement(), set/isElementVisible(), controls the children
  visibility for a group type object. Because the child object may be
  claimed by other objects, it is essential to have independent control
  of children visibilities. These APIs are designed to abstract how
  group manages the child visibility. For performance reason, these
  function are meant to control only the immediate child object.

* resolve(), helper function to parse subname reference and resolve the
  final object, and optionally the immediate parent of the final object,
  the final object reference name (for calling `set/isElementVisible()`),
  and the subname reference if there is one.

* touch(), add optional argument 'noRecompute' for better backward
  compatibility with the NoRecompute flag. By default, touch() causes
  recompute unless noRecompute is true

* signalChanged/signalBeforeChange, two new signal for tracking changes
  of a specific object.

* getViewProviderNameOverride(), return a string of the view provider
  type of this object. This allows Python class to override the view
  provider of an object. This feature will be used by ViewProviderLink
  which is designed to work with any object that has LinkBaseExtension.

* canLinkProperties(), will be used by Gui::PropertyView to display
  linked object properties together with the object's own properties.

* redirectSubname(), will be used by Gui::Tree to allow an object to
  redirect selection to some other object when (pre)selected in the tree
  view.

* Visibility, new property serve as the same purpose as view provider
  property of the same name. It is added here so that App namespace
  code can check for visibility without Gui module. This is useful,
  for example, when constructing a compound shape of a container that
  respects the children visibility.

* (has)hasHiddenMarker(), return or check for a special sub-element
  name used as marker for overriding sub-object visibility. Will be
  used by Gui::ViewProvider, it is put here for the same reason as
  adding Visibility property.

* getID(), return object internal identifier. Each object is now
  assigned an integer identifier that is unique within its containing
  document.

Document:

* ShowHidden, new property to tell tree view whether to show hidden
  object items.

* signalTouchedObject, new signal triggered when manually touch an
  object when calling its touch() function

* getObjectByID(), get object by its identifier

* addObject() is modified to allow overriding view provider

* has/getLinksTo(), helper function to obtain links to a given object.

Application:

* checkLinkDepth(), helper function to check recursive depth for link
  traversal. The depth is checked against the total object count of
  all opened documents. The count (_objCount) is internally updated
  whenever object is added or removed.

* has/getLinksTo(), same as Document::has/getLinksTo() but return links
  from all opened documents.

GroupExtension/OriginGroupExtension/DatumFeature/DatumCS/Part::Feature:
implement sepcialized getSubObject/getSubObjects().
This commit is contained in:
Zheng, Lei
2019-06-24 16:30:08 +08:00
committed by wmayer
parent 2d9ca92594
commit 6731e83bf5
31 changed files with 1762 additions and 172 deletions

View File

@@ -30,6 +30,7 @@
#include <App/PropertyExpressionEngine.h>
#include <Base/TimeInfo.h>
#include <Base/Matrix.h>
#include <CXX/Objects.hxx>
#include <bitset>
@@ -46,7 +47,7 @@ enum ObjectStatus {
Touch = 0,
Error = 1,
New = 2,
Recompute = 3,
Recompute = 3, // set when the object is currently being recomputed
Restore = 4,
Remove = 5,
PythonCall = 6,
@@ -86,18 +87,35 @@ class AppExport DocumentObject: public App::TransactionalObject
public:
PropertyString Label;
PropertyString Label2;
PropertyExpressionEngine ExpressionEngine;
/// Allow control visibility status in App name space
PropertyBool Visibility;
/// signal before changing a property of this object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChange;
/// signal on changed property of this object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChanged;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
return "";
}
/// This function is introduced to allow Python feature override its view provider
virtual const char *getViewProviderNameOverride() const {
return getViewProviderName();
}
/// Constructor
DocumentObject(void);
virtual ~DocumentObject();
/// returns the name which is set in the document for this object (not the name property!)
const char *getNameInDocument(void) const;
/// Return the object ID that is unique within its owner document
long getID() const {return _Id;}
/// Return the object full name of the form DocName#ObjName
std::string getFullName() const;
virtual bool isAttachedToDocument() const;
virtual const char* detachFromDocument();
/// gets the document in which this Object is handled
@@ -107,7 +125,7 @@ public:
*/
//@{
/// set this document object touched (cause recomputation on dependent features)
void touch(void);
void touch(bool noRecompute=false);
/// test if this document object is touched
bool isTouched(void) const;
/// Enforce this document object to be recomputed
@@ -137,6 +155,31 @@ public:
void setStatus(ObjectStatus pos, bool on) {StatusBits.set((size_t)pos, on);}
//@}
/** Child element handling
*/
//@{
/** Set sub-element visibility
*
* For performance reason, \c element must not contain any further
* sub-elements, i.e. there should be no '.' inside \c element.
*
* @return -1 if element visiblity is not supported, 0 if element is not
* found, 1 if success
*/
virtual int setElementVisible(const char *element, bool visible);
/** Get sub-element visibility
*
* @return -1 if element visiblity is not supported or element not found, 0
* if element is invisible, or else 1
*/
virtual int isElementVisible(const char *element) const;
/// return true to activate tree view group object handling and element visibility
virtual bool hasChildElement() const;
//@}
/** DAG handling
This part of the interface deals with viewing the document as
a DAG (directed acyclic graph).
@@ -214,8 +257,89 @@ public:
*/
virtual void onLostLinkToObject(DocumentObject*);
virtual PyObject *getPyObject(void);
/// its used to get the python sub objects by name (e.g. by the selection)
virtual std::vector<PyObject *> getPySubObjects(const std::vector<std::string>&) const;
/** Get the sub element/object by name
*
* @param subname: a string which is dot separated name to refer to a sub
* element or object. An empty string can be used to refer to the object
* itself
*
* @param pyObj: if non zero, returns the python object corresponding to
* this sub object. The actual type of this python object is implementation
* dependent. For example, The current implementation of Part::Feature will
* return the TopoShapePy, event if there is no sub-element reference, in
* which case it returns the whole shape.
*
* @param mat: If non zero, it is used as the current transformation matrix
* on input. And output as the accumulated transformation up until and
* include the transformation applied by the final object reference in \c
* subname. For Part::Feature, the transformation is applied to the
* TopoShape inside \c pyObj before returning.
*
* @param transform: if false, then it will not apply the object's own
* transformation to \c mat, which lets you override the object's placement
* (and possibly scale).
*
* @param depth: depth limitation as hint for cyclic link detection
*
* @return The last document object refered in subname. If subname is empty,
* then it shall return itself. If subname is invalid, then it shall return
* zero.
*/
virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj=0,
Base::Matrix4D *mat=0, bool transform=true, int depth=0) const;
/// Return a list of objects referenced by a given subname including this object
std::vector<DocumentObject*> getSubObjectList(const char *subname) const;
/// reason of calling getSubObjects()
enum GSReason {
/// default, mostly for exporting shape objects
GS_DEFAULT,
/// for element selection
GS_SELECT,
};
/** Return name reference of all sub-objects
*
* @param reason: indicate reason of obtaining the sub objects
*
* The default implementation returns all object references in
* PropertyLink, and PropertyLinkList, if any
*
* @return Return a vector of subname references for all sub-objects. In
* most cases, the name returned will be the object name plus an ending
* '.', which can be passed directly to getSubObject() to retrieve the
* name. The reason to return the name reference instead of the sub object
* itself is because there may be no real sub object, or the sub object
* need special transformation. For example, sub objects of an array type
* of object.
*/
virtual std::vector<std::string> getSubObjects(int reason=0) const;
///Obtain top parents and subnames of this object using its InList
std::vector<std::pair<App::DocumentObject*,std::string> > getParents(int depth=0) const;
/** Return the linked object with optional transformation
*
* @param recurse: If false, return the immediate linked object, or else
* recursively call this function to return the final linked object.
*
* @param mat: If non zero, it is used as the current transformation matrix
* on input. And output as the accumulated transformation till the final
* linked object.
*
* @param transform: if false, then it will not accumulate the object's own
* placement into \c mat, which lets you override the object's placement.
*
* @return Return the linked object. This function must return itself if the
* it is not a link or the link is invalid.
*/
virtual DocumentObject *getLinkedObject(bool recurse=true,
Base::Matrix4D *mat=0, bool transform=false, int depth=0) const;
/* Return true to cause PropertyView to show linked object's property */
virtual bool canLinkProperties() const {return true;}
friend class Document;
friend class Transaction;
@@ -237,6 +361,51 @@ public:
const std::string & getOldLabel() const { return oldLabel; }
const char *getViewProviderNameStored() const {
return _pcViewProviderName.c_str();
}
/** Resolve the last document object referenced in the subname
*
* @param subname: dot separated subname
* @param parent: return the direct parent of the object
* @param childName: return child name to be passed to is/setElementVisible()
* @param subElement: return non-object sub-element name if found. The
* pointer is guaranteed to be within the buffer pointed to by 'subname'
*
* @sa getSubObject()
* @return Returns the last referenced document object in the subname. If no
* such object in subname, return pObject.
*/
App::DocumentObject *resolve(const char *subname, App::DocumentObject **parent=0,
std::string *childName=0, const char **subElement=0,
PyObject **pyObj=0, Base::Matrix4D *mat=0, bool transform=true, int depth=0) const;
/** Allow object to redirect a subname path
*
* @param ss: input as the current subname path from \a topParent leading
* just before this object, i.e. ends at the parent of this object. This
* function should append its own name to this path, or redirect the
* subname to other place.
* @param topParent: top parent of this subname path
* @param child: the immediate child object in the path
*
* This function is called by tree view to generate a subname path when an
* item is selected in the tree. Document object can use this function to
* redirect the selection to some other objects.
*/
virtual bool redirectSubName(std::ostringstream &ss,
DocumentObject *topParent, DocumentObject *child) const;
/** Sepecial marker to mark the object has hidden
*
* It is used by Gui::ViewProvider::getElementColors(), but exposed here
* for convenience
*/
static const std::string &hiddenMarker();
/// Check if the subname reference ends with hidden marker.
static const char *hasHiddenMarker(const char *subname);
protected:
/// recompute only this object
virtual App::DocumentObjectExecReturn *recompute(void);
@@ -301,6 +470,13 @@ protected: // attributes
// pointer to the document name string (for performance)
const std::string *pcNameInDocument;
private:
// accessed by App::Document to record and restore the correct view provider type
std::string _pcViewProviderName;
// unique identifier (ammong a document) of this object.
long _Id;
private:
// Back pointer to all the fathers in a DAG of the document
// this is used by the document (via friend) to have a effective DAG handling