Implementation of Link
This patch includes the actual implementation of Link, which is implemented as an extension named LinkBaseExtension in App namespace, and a full view provider ViewProviderLink in Gui. The reason of not using ViewProviderExtension is because it need full control when display, not just extending existing functionalities. Please see [here](https://git.io/fjPue) for more details of the implementation. This patch also includes a set of link manipulation commands, and a task panel for overriding geometry element colors.
This commit is contained in:
@@ -112,6 +112,7 @@
|
||||
#include "Transactions.h"
|
||||
#include <App/MaterialPy.h>
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
#include "Link.h"
|
||||
|
||||
// If you stumble here, run the target "BuildExtractRevision" on Windows systems
|
||||
// or the Python script "SubWCRev.py" on Linux based systems which builds
|
||||
@@ -1835,6 +1836,10 @@ void Application::initTypes(void)
|
||||
App ::GeoFeatureGroupExtensionPython::init();
|
||||
App ::OriginGroupExtension ::init();
|
||||
App ::OriginGroupExtensionPython ::init();
|
||||
App ::LinkBaseExtension ::init();
|
||||
App ::LinkBaseExtensionPython ::init();
|
||||
App ::LinkExtension ::init();
|
||||
App ::LinkExtensionPython ::init();
|
||||
|
||||
// Document classes
|
||||
App ::TransactionalObject ::init();
|
||||
@@ -1862,6 +1867,12 @@ void Application::initTypes(void)
|
||||
App ::Line ::init();
|
||||
App ::Part ::init();
|
||||
App ::Origin ::init();
|
||||
App ::Link ::init();
|
||||
App ::LinkPython ::init();
|
||||
App ::LinkElement ::init();
|
||||
App ::LinkElementPython ::init();
|
||||
App ::LinkGroup ::init();
|
||||
App ::LinkGroupPython ::init();
|
||||
|
||||
// Expression classes
|
||||
App ::Expression ::init();
|
||||
|
||||
@@ -90,6 +90,7 @@ generate_from_xml(ExtensionPy)
|
||||
generate_from_xml(ExtensionContainerPy)
|
||||
generate_from_xml(DocumentObjectExtensionPy)
|
||||
generate_from_xml(GroupExtensionPy)
|
||||
generate_from_xml(LinkBaseExtensionPy)
|
||||
generate_from_xml(DocumentObjectGroupPy)
|
||||
generate_from_xml(GeoFeaturePy)
|
||||
generate_from_xml(GeoFeatureGroupExtensionPy)
|
||||
@@ -108,6 +109,7 @@ SET(FreeCADApp_XML_SRCS
|
||||
ExtensionContainerPy.xml
|
||||
DocumentObjectExtensionPy.xml
|
||||
GroupExtensionPy.xml
|
||||
LinkBaseExtensionPy.xml
|
||||
DocumentObjectGroupPy.xml
|
||||
DocumentObjectPy.xml
|
||||
GeoFeaturePy.xml
|
||||
@@ -165,6 +167,8 @@ SET(Document_CPP_SRCS
|
||||
MaterialObject.cpp
|
||||
MergeDocuments.cpp
|
||||
TextDocument.cpp
|
||||
Link.cpp
|
||||
LinkBaseExtensionPyImp.cpp
|
||||
)
|
||||
|
||||
SET(Document_HPP_SRCS
|
||||
@@ -203,6 +207,7 @@ SET(Document_HPP_SRCS
|
||||
MaterialObject.h
|
||||
MergeDocuments.h
|
||||
TextDocument.h
|
||||
Link.h
|
||||
)
|
||||
SET(Document_SRCS
|
||||
${Document_CPP_SRCS}
|
||||
|
||||
1390
src/App/Link.cpp
Normal file
1390
src/App/Link.cpp
Normal file
File diff suppressed because it is too large
Load Diff
529
src/App/Link.h
Normal file
529
src/App/Link.h
Normal file
@@ -0,0 +1,529 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef APP_LINK_H
|
||||
#define APP_LINK_H
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/preprocessor/facilities/expand.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/seq/cat.hpp>
|
||||
#include <boost/preprocessor/tuple/elem.hpp>
|
||||
#include <boost/preprocessor/tuple/enum.hpp>
|
||||
#include "DocumentObject.h"
|
||||
#include "FeaturePython.h"
|
||||
#include "PropertyLinks.h"
|
||||
#include "DocumentObjectExtension.h"
|
||||
#include "FeaturePython.h"
|
||||
#include "GroupExtension.h"
|
||||
|
||||
#define LINK_THROW(_type,_msg) do{\
|
||||
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))\
|
||||
FC_ERR(_msg);\
|
||||
throw _type(_msg);\
|
||||
}while(0)
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport LinkBaseExtension : public App::DocumentObjectExtension
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER(App::LinkExtension);
|
||||
typedef App::DocumentObjectExtension inherited;
|
||||
|
||||
public:
|
||||
LinkBaseExtension();
|
||||
virtual ~LinkBaseExtension();
|
||||
|
||||
PropertyBool _LinkRecomputed;
|
||||
PropertyLinkList _ChildCache; // cache for plain group expansion
|
||||
|
||||
enum {
|
||||
LinkModeNone,
|
||||
LinkModeAutoDelete,
|
||||
LinkModeAutoLink,
|
||||
LinkModeAutoUnlink,
|
||||
};
|
||||
|
||||
/** \name Parameter definition
|
||||
*
|
||||
* Parameter definition (Name, Type, Property Type, Default, Document).
|
||||
* The variadic is here so that the parameter can be extended by adding
|
||||
* extra fields. See LINK_PARAM_EXT() for an example
|
||||
*/
|
||||
//@{
|
||||
|
||||
#define LINK_PARAM_LINK_PLACEMENT(...) \
|
||||
(LinkPlacement, Base::Placement, App::PropertyPlacement, Base::Placement(), "Link placement", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_PLACEMENT(...) \
|
||||
(Placement, Base::Placement, App::PropertyPlacement, Base::Placement(), \
|
||||
"Alias to LinkPlacement to make the link object compatibale with other objects", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_OBJECT(...) \
|
||||
(LinkedObject, App::DocumentObject*, App::PropertyLink, 0, "Linked object", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_SUB_ELEMENT(...) \
|
||||
(SubElements, std::vector<std::string>, App::PropertyStringList, std::vector<std::string>(), \
|
||||
"Non-object Sub-element list of the linked object, e.g. Face1", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_TRANSFORM(...) \
|
||||
(LinkTransform, bool, App::PropertyBool, false, \
|
||||
"Set to false to override linked object's placement", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_SCALE(...) \
|
||||
(Scale, double, App::PropertyFloat, 1.0, "Scale factor", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_SCALE_VECTOR(...) \
|
||||
(ScaleVector, Base::Vector3d, App::PropertyVector, Base::Vector3d(1,1,1), "Scale factors", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_PLACEMENTS(...) \
|
||||
(PlacementList, std::vector<Base::Placement>, App::PropertyPlacementList, std::vector<Base::Placement>(),\
|
||||
"The placement for each link element", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_SCALES(...) \
|
||||
(ScaleList, std::vector<Base::Vector3d>, App::PropertyVectorList, std::vector<Base::Vector3d>(),\
|
||||
"The scale factors for each link element", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_VISIBILITIES(...) \
|
||||
(VisibilityList, boost::dynamic_bitset<>, App::PropertyBoolList, boost::dynamic_bitset<>(),\
|
||||
"The visibility state of each link element", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_COUNT(...) \
|
||||
(ElementCount, int, App::PropertyInteger, 0, "Link element count", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_ELEMENTS(...) \
|
||||
(ElementList, std::vector<App::DocumentObject*>, App::PropertyLinkList, std::vector<App::DocumentObject*>(),\
|
||||
"The link element object list", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_SHOW_ELEMENT(...) \
|
||||
(ShowElement, bool, App::PropertyBool, true, "Enable link element list", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_MODE(...) \
|
||||
(LinkMode, long, App::PropertyEnumeration, ((long)0), "Link group mode", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM_COLORED_ELEMENTS(...) \
|
||||
(ColoredElements, App::DocumentObject*, App::PropertyLinkSubHidden, \
|
||||
0, "Link colored elements", ##__VA_ARGS__)
|
||||
|
||||
#define LINK_PARAM(_param) (LINK_PARAM_##_param())
|
||||
|
||||
#define LINK_PNAME(_param) BOOST_PP_TUPLE_ELEM(0,_param)
|
||||
#define LINK_PTYPE(_param) BOOST_PP_TUPLE_ELEM(1,_param)
|
||||
#define LINK_PPTYPE(_param) BOOST_PP_TUPLE_ELEM(2,_param)
|
||||
#define LINK_PDEF(_param) BOOST_PP_TUPLE_ELEM(3,_param)
|
||||
#define LINK_PDOC(_param) BOOST_PP_TUPLE_ELEM(4,_param)
|
||||
|
||||
#define LINK_PINDEX(_param) BOOST_PP_CAT(Prop,LINK_PNAME(_param))
|
||||
//@}
|
||||
|
||||
#define LINK_PARAMS \
|
||||
LINK_PARAM(PLACEMENT)\
|
||||
LINK_PARAM(LINK_PLACEMENT)\
|
||||
LINK_PARAM(OBJECT)\
|
||||
LINK_PARAM(SUB_ELEMENT)\
|
||||
LINK_PARAM(TRANSFORM)\
|
||||
LINK_PARAM(SCALE)\
|
||||
LINK_PARAM(SCALE_VECTOR)\
|
||||
LINK_PARAM(PLACEMENTS)\
|
||||
LINK_PARAM(SCALES)\
|
||||
LINK_PARAM(VISIBILITIES)\
|
||||
LINK_PARAM(COUNT)\
|
||||
LINK_PARAM(ELEMENTS)\
|
||||
LINK_PARAM(SHOW_ELEMENT)\
|
||||
LINK_PARAM(MODE)\
|
||||
LINK_PARAM(COLORED_ELEMENTS)
|
||||
|
||||
enum PropIndex {
|
||||
#define LINK_PINDEX_DEFINE(_1,_2,_param) LINK_PINDEX(_param),
|
||||
|
||||
// defines Prop##Name enumeration value
|
||||
BOOST_PP_SEQ_FOR_EACH(LINK_PINDEX_DEFINE,_,LINK_PARAMS)
|
||||
PropMax
|
||||
};
|
||||
|
||||
virtual void setProperty(int idx, Property *prop);
|
||||
Property *getProperty(int idx);
|
||||
Property *getProperty(const char *);
|
||||
|
||||
struct PropInfo {
|
||||
int index;
|
||||
const char *name;
|
||||
Base::Type type;
|
||||
const char *doc;
|
||||
|
||||
PropInfo(int index, const char *name,Base::Type type,const char *doc)
|
||||
:index(index),name(name),type(type),doc(doc)
|
||||
{}
|
||||
|
||||
PropInfo() {}
|
||||
};
|
||||
|
||||
#define LINK_PROP_INFO(_1,_var,_param) \
|
||||
_var.push_back(PropInfo(BOOST_PP_CAT(Prop,LINK_PNAME(_param)),\
|
||||
BOOST_PP_STRINGIZE(LINK_PNAME(_param)),\
|
||||
LINK_PPTYPE(_param)::getClassTypeId(), \
|
||||
LINK_PDOC(_param)));
|
||||
|
||||
virtual const std::vector<PropInfo> &getPropertyInfo() const;
|
||||
|
||||
typedef std::map<std::string, PropInfo> PropInfoMap;
|
||||
virtual const PropInfoMap &getPropertyInfoMap() const;
|
||||
|
||||
#define LINK_PROP_GET(_1,_2,_param) \
|
||||
LINK_PTYPE(_param) BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Value)) () const {\
|
||||
auto prop = props[LINK_PINDEX(_param)];\
|
||||
if(!prop) return LINK_PDEF(_param);\
|
||||
return static_cast<const LINK_PPTYPE(_param) *>(prop)->getValue();\
|
||||
}\
|
||||
const LINK_PPTYPE(_param) *BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Property)) () const {\
|
||||
auto prop = props[LINK_PINDEX(_param)];\
|
||||
return static_cast<const LINK_PPTYPE(_param) *>(prop);\
|
||||
}\
|
||||
LINK_PPTYPE(_param) *BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Property)) () {\
|
||||
auto prop = props[LINK_PINDEX(_param)];\
|
||||
return static_cast<LINK_PPTYPE(_param) *>(prop);\
|
||||
}\
|
||||
|
||||
// defines get##Name() and get##Name##Property() accessor
|
||||
BOOST_PP_SEQ_FOR_EACH(LINK_PROP_GET,_,LINK_PARAMS)
|
||||
|
||||
PropertyLinkList *_getElementListProperty() const;
|
||||
const std::vector<App::DocumentObject*> &_getElementListValue() const;
|
||||
|
||||
PropertyBool *_getShowElementProperty() const;
|
||||
bool _getShowElementValue() const;
|
||||
|
||||
PropertyInteger *_getElementCountProperty() const;
|
||||
int _getElementCountValue() const;
|
||||
|
||||
std::vector<DocumentObject*> getLinkedChildren(bool filter=true) const;
|
||||
|
||||
const char *flattenSubname(const char *subname) const;
|
||||
void expandSubname(std::string &subname) const;
|
||||
|
||||
DocumentObject *getLink(int depth=0) const;
|
||||
|
||||
Base::Matrix4D getTransform(bool transform) const;
|
||||
Base::Vector3d getScaleVector() const;
|
||||
|
||||
App::GroupExtension *linkedPlainGroup() const;
|
||||
|
||||
bool linkTransform() const;
|
||||
|
||||
const char *getSubName() const {
|
||||
parseSubName();
|
||||
return mySubName.size()?mySubName.c_str():0;
|
||||
}
|
||||
const char *getSubElement() const {
|
||||
parseSubName();
|
||||
return mySubElement.size()?mySubElement.c_str():0;
|
||||
}
|
||||
|
||||
bool extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj=0, Base::Matrix4D *mat=0, bool transform=false, int depth=0) const override;
|
||||
|
||||
bool extensionGetSubObjects(std::vector<std::string>&ret, int reason) const override;
|
||||
|
||||
bool extensionGetLinkedObject(DocumentObject *&ret,
|
||||
bool recurse, Base::Matrix4D *mat, bool transform, int depth) const override;
|
||||
|
||||
virtual App::DocumentObjectExecReturn *extensionExecute(void) override;
|
||||
virtual short extensionMustExecute(void) override;
|
||||
virtual void extensionOnChanged(const Property* p) override;
|
||||
virtual void onExtendedUnsetupObject () override;
|
||||
virtual void onExtendedDocumentRestored() override;
|
||||
|
||||
virtual int extensionSetElementVisible(const char *, bool) override;
|
||||
virtual int extensionIsElementVisible(const char *) override;
|
||||
virtual bool extensionHasChildElement() const override;
|
||||
|
||||
virtual PyObject* getExtensionPyObject(void) override;
|
||||
|
||||
virtual Property *extensionGetPropertyByName(const char* name) const override;
|
||||
|
||||
static int getArrayIndex(const char *subname, const char **psubname=0);
|
||||
int getElementIndex(const char *subname, const char **psubname=0) const;
|
||||
void elementNameFromIndex(int idx, std::ostream &ss) const;
|
||||
|
||||
DocumentObject *getContainer();
|
||||
const DocumentObject *getContainer() const;
|
||||
|
||||
void setLink(int index, DocumentObject *obj, const char *subname=0,
|
||||
const std::vector<std::string> &subs = std::vector<std::string>());
|
||||
|
||||
DocumentObject *getTrueLinkedObject(bool recurse,
|
||||
Base::Matrix4D *mat=0,int depth=0, bool noElement=false) const;
|
||||
|
||||
typedef std::map<const Property*,std::pair<LinkBaseExtension*,int> > LinkPropMap;
|
||||
|
||||
bool hasPlacement() const {
|
||||
return getLinkPlacementProperty() || getPlacementProperty();
|
||||
}
|
||||
|
||||
void cacheChildLabel(int enable=-1) const;
|
||||
|
||||
protected:
|
||||
void parseSubName() const;
|
||||
void update(App::DocumentObject *parent, const Property *prop);
|
||||
void syncElementList();
|
||||
void detachElement(App::DocumentObject *obj);
|
||||
void checkGeoElementMap(const App::DocumentObject *obj,
|
||||
const App::DocumentObject *linked, PyObject **pyObj, const char *postfix) const;
|
||||
void updateGroup();
|
||||
void slotChangedPlainGroup(const App::DocumentObject &, const App::Property &);
|
||||
|
||||
protected:
|
||||
std::vector<Property *> props;
|
||||
std::unordered_set<const App::DocumentObject*> myHiddenElements;
|
||||
mutable std::string mySubElement;
|
||||
mutable std::string mySubName;
|
||||
|
||||
std::unordered_map<const App::DocumentObject*,
|
||||
boost::signals2::scoped_connection> plainGroupConns;
|
||||
|
||||
mutable std::unordered_map<std::string,int> myLabelCache; // for label based subname lookup
|
||||
mutable bool enableLabelCache;
|
||||
|
||||
long myOwner;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef ExtensionPythonT<LinkBaseExtension> LinkBaseExtensionPython;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppExport LinkExtension : public LinkBaseExtension
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER(App::LinkExtension);
|
||||
typedef LinkBaseExtension inherited;
|
||||
|
||||
public:
|
||||
LinkExtension();
|
||||
virtual ~LinkExtension();
|
||||
|
||||
/** \name Helpers for defining extended parameter
|
||||
*
|
||||
* extended parameter definition
|
||||
* (Name, Type, Property_Type, Default, Document, Property_Name,
|
||||
* Derived_Property_Type, App_Property_Type, Group)
|
||||
*
|
||||
* This helper simply reuses Name as Property_Name, Property_Type as
|
||||
* Derived_Property_type, Prop_None as App_Propert_Type
|
||||
*
|
||||
* Note: Because PropertyView will merge linked object's properties into
|
||||
* ours, we set the default group name as ' Link' with a leading space to
|
||||
* try to make our group before others
|
||||
*/
|
||||
//@{
|
||||
|
||||
#define LINK_ENAME(_param) BOOST_PP_TUPLE_ELEM(5,_param)
|
||||
#define LINK_ETYPE(_param) BOOST_PP_TUPLE_ELEM(6,_param)
|
||||
#define LINK_EPTYPE(_param) BOOST_PP_TUPLE_ELEM(7,_param)
|
||||
#define LINK_EGROUP(_param) BOOST_PP_TUPLE_ELEM(8,_param)
|
||||
|
||||
#define _LINK_PROP_ADD(_add_property, _param) \
|
||||
_add_property(BOOST_PP_STRINGIZE(LINK_ENAME(_param)),LINK_ENAME(_param),\
|
||||
(LINK_PDEF(_param)),LINK_EGROUP(_param),LINK_EPTYPE(_param),LINK_PDOC(_param));\
|
||||
setProperty(LINK_PINDEX(_param),&LINK_ENAME(_param));
|
||||
|
||||
#define LINK_PROP_ADD(_1,_2,_param) \
|
||||
_LINK_PROP_ADD(_ADD_PROPERTY_TYPE,_param);
|
||||
|
||||
#define LINK_PROP_ADD_EXTENSION(_1,_2,_param) \
|
||||
_LINK_PROP_ADD(_EXTENSION_ADD_PROPERTY_TYPE,_param);
|
||||
|
||||
#define LINK_PROPS_ADD(_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(LINK_PROP_ADD,_,_seq)
|
||||
|
||||
#define LINK_PROPS_ADD_EXTENSION(_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(LINK_PROP_ADD_EXTENSION,_,_seq)
|
||||
|
||||
#define _LINK_PROP_SET(_1,_2,_param) \
|
||||
setProperty(LINK_PINDEX(_param),&LINK_ENAME(_param));
|
||||
|
||||
#define LINK_PROPS_SET(_seq) BOOST_PP_SEQ_FOR_EACH(_LINK_PROP_SET,_,_seq)
|
||||
|
||||
/// Helper for defining default extended parameter
|
||||
#define _LINK_PARAM_EXT(_name,_type,_ptype,_def,_doc,...) \
|
||||
((_name,_type,_ptype,_def,_doc,_name,_ptype,App::Prop_None," Link"))
|
||||
|
||||
/** Define default extended parameter
|
||||
* It simply reuses Name as Property_Name, Property_Type as
|
||||
* Derived_Property_Type, and App::Prop_None as App::PropertyType
|
||||
*/
|
||||
#define LINK_PARAM_EXT(_param) BOOST_PP_EXPAND(_LINK_PARAM_EXT LINK_PARAM_##_param())
|
||||
|
||||
/// Helper for extended parameter with app property type
|
||||
#define _LINK_PARAM_EXT_ATYPE(_name,_type,_ptype,_def,_doc,_atype) \
|
||||
((_name,_type,_ptype,_def,_doc,_name,_ptype,_atype," Link"))
|
||||
|
||||
/// Define extended parameter with app property type
|
||||
#define LINK_PARAM_EXT_ATYPE(_param,_atype) \
|
||||
BOOST_PP_EXPAND(_LINK_PARAM_EXT_ATYPE LINK_PARAM_##_param(_atype))
|
||||
|
||||
/// Helper for extended parameter with derived property type
|
||||
#define _LINK_PARAM_EXT_TYPE(_name,_type,_ptype,_def,_doc,_dtype) \
|
||||
((_name,_type,_ptype,_def,_doc,_name,_dtype,App::Prop_None," Link"))
|
||||
|
||||
/// Define extended parameter with derived property type
|
||||
#define LINK_PARAM_EXT_TYPE(_param,_dtype) \
|
||||
BOOST_PP_EXPAND(_LINK_PARAM_EXT_TYPE LINK_PARAM_##_param(_dtype))
|
||||
|
||||
/// Helper for extended parameter with a different property name
|
||||
#define _LINK_PARAM_EXT_NAME(_name,_type,_ptype,_def,_doc,_pname) \
|
||||
((_name,_type,_ptype,_def,_doc,_pname,_ptype,App::Prop_None," Link"))
|
||||
|
||||
/// Define extended parameter with a different property name
|
||||
#define LINK_PARAM_EXT_NAME(_param,_pname) BOOST_PP_EXPAND(_LINK_PARAM_EXT_NAME LINK_PARAM_##_param(_pname))
|
||||
//@}
|
||||
|
||||
#define LINK_PARAMS_EXT \
|
||||
LINK_PARAM_EXT(SCALE)\
|
||||
LINK_PARAM_EXT(SCALES)\
|
||||
LINK_PARAM_EXT(VISIBILITIES)\
|
||||
LINK_PARAM_EXT(PLACEMENTS)\
|
||||
LINK_PARAM_EXT(ELEMENTS)
|
||||
|
||||
#define LINK_PROP_DEFINE(_1,_2,_param) LINK_ETYPE(_param) LINK_ENAME(_param);
|
||||
#define LINK_PROPS_DEFINE(_seq) BOOST_PP_SEQ_FOR_EACH(LINK_PROP_DEFINE,_,_seq)
|
||||
|
||||
// defines the actual properties
|
||||
LINK_PROPS_DEFINE(LINK_PARAMS_EXT)
|
||||
|
||||
void onExtendedDocumentRestored() override {
|
||||
LINK_PROPS_SET(LINK_PARAMS_EXT);
|
||||
inherited::onExtendedDocumentRestored();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef ExtensionPythonT<LinkExtension> LinkExtensionPython;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppExport Link : public App::DocumentObject, public App::LinkExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(App::Link);
|
||||
typedef App::DocumentObject inherited;
|
||||
public:
|
||||
|
||||
#define LINK_PARAMS_LINK \
|
||||
LINK_PARAM_EXT_TYPE(OBJECT, App::PropertyXLink)\
|
||||
LINK_PARAM_EXT(TRANSFORM)\
|
||||
LINK_PARAM_EXT(LINK_PLACEMENT)\
|
||||
LINK_PARAM_EXT(PLACEMENT)\
|
||||
LINK_PARAM_EXT(SUB_ELEMENT)\
|
||||
LINK_PARAM_EXT(SHOW_ELEMENT)\
|
||||
LINK_PARAM_EXT_TYPE(COUNT,App::PropertyIntegerConstraint)\
|
||||
LINK_PARAM_EXT_ATYPE(COLORED_ELEMENTS,App::Prop_Hidden)
|
||||
|
||||
LINK_PROPS_DEFINE(LINK_PARAMS_LINK)
|
||||
|
||||
Link(void);
|
||||
|
||||
const char* getViewProviderName(void) const override{
|
||||
return "Gui::ViewProviderLink";
|
||||
}
|
||||
|
||||
void onDocumentRestored() override {
|
||||
LINK_PROPS_SET(LINK_PARAMS_LINK);
|
||||
inherited::onDocumentRestored();
|
||||
}
|
||||
|
||||
bool canLinkProperties() const override;
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<Link> LinkPython;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppExport LinkElement : public App::DocumentObject, public App::LinkBaseExtension {
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkElement);
|
||||
typedef App::DocumentObject inherited;
|
||||
public:
|
||||
|
||||
#define LINK_PARAMS_ELEMENT \
|
||||
LINK_PARAM_EXT(SCALE)\
|
||||
LINK_PARAM_EXT_TYPE(OBJECT, App::PropertyXLink)\
|
||||
LINK_PARAM_EXT(TRANSFORM) \
|
||||
LINK_PARAM_EXT(LINK_PLACEMENT)\
|
||||
LINK_PARAM_EXT(PLACEMENT)\
|
||||
LINK_PARAM_EXT(SUB_ELEMENT)
|
||||
|
||||
// defines the actual properties
|
||||
LINK_PROPS_DEFINE(LINK_PARAMS_ELEMENT)
|
||||
|
||||
LinkElement();
|
||||
const char* getViewProviderName(void) const override{
|
||||
return "Gui::ViewProviderLink";
|
||||
}
|
||||
|
||||
void onDocumentRestored() override {
|
||||
LINK_PROPS_SET(LINK_PARAMS_ELEMENT);
|
||||
inherited::onDocumentRestored();
|
||||
}
|
||||
|
||||
bool canDelete() const;
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<LinkElement> LinkElementPython;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppExport LinkGroup : public App::DocumentObject, public App::LinkBaseExtension {
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkGroup);
|
||||
typedef App::DocumentObject inherited;
|
||||
public:
|
||||
|
||||
#define LINK_PARAMS_GROUP \
|
||||
LINK_PARAM_EXT(ELEMENTS)\
|
||||
LINK_PARAM_EXT(PLACEMENT)\
|
||||
LINK_PARAM_EXT(VISIBILITIES)\
|
||||
LINK_PARAM_EXT(MODE)\
|
||||
LINK_PARAM_EXT_ATYPE(COLORED_ELEMENTS,App::Prop_Hidden)
|
||||
|
||||
// defines the actual properties
|
||||
LINK_PROPS_DEFINE(LINK_PARAMS_GROUP)
|
||||
|
||||
LinkGroup();
|
||||
|
||||
const char* getViewProviderName(void) const override{
|
||||
return "Gui::ViewProviderLink";
|
||||
}
|
||||
|
||||
void onDocumentRestored() override {
|
||||
LINK_PROPS_SET(LINK_PARAMS_GROUP);
|
||||
inherited::onDocumentRestored();
|
||||
}
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<LinkGroup> LinkGroupPython;
|
||||
|
||||
} //namespace App
|
||||
|
||||
|
||||
#endif // APP_LINK_H
|
||||
117
src/App/LinkBaseExtensionPy.xml
Normal file
117
src/App/LinkBaseExtensionPy.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectExtensionPy"
|
||||
Name="LinkBaseExtensionPy"
|
||||
TwinPointer="LinkBaseExtension"
|
||||
Twin="LinkBaseExtension"
|
||||
Include="App/Link.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/DocumentObjectExtensionPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>Link extension base class</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="configLinkProperty" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
configLinkProperty(key=val,...): property configuration
|
||||
configLinkProperty(key,...): property configuration with default name
|
||||
|
||||
This methode is here to impelement what I called Property Design
|
||||
Pattern. The extension operates on a predefined set of properties,
|
||||
but it relies on the extended object to supply the actual property by
|
||||
calling this methode. You can choose a sub set of functionality of
|
||||
this extension by supplying only some of the supported properties.
|
||||
|
||||
The 'key' are names used to refer to properties supported by this
|
||||
extension, and 'val' is the actual name of the property of your
|
||||
object. You can obtain the key names and expected types using
|
||||
getLinkPropertyInfo(). You can use property of derived type when
|
||||
calling configLinkProperty(). Other types will cause exception to
|
||||
ben thrown. The actual properties supported may be different
|
||||
depending on the actual extension object underlying this python
|
||||
object.
|
||||
|
||||
If 'val' is omitted, i.e. calling configLinkProperty(key,...), then
|
||||
it is assumed the the actualy property name is the same as 'key'
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getLinkExtProperty">
|
||||
<Documentation>
|
||||
<UserDocu>getLinkExtProperty(name): return the property value by its predefined name </UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getLinkExtPropertyName">
|
||||
<Documentation>
|
||||
<UserDocu>getLinkExtPropertyName(name): lookup the property name by its predefined name </UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getLinkPropertyInfo">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getLinkPropertyInfo(): return a tuple of (name,type,doc) for all supported properties.
|
||||
|
||||
getLinkPropertyInfo(index): return (name,type,doc) of a specific property
|
||||
|
||||
getLinkPropertyInfo(name): return (type,doc) of a specific property
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setLink">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setLink(obj,subName=None,subElements=None): Set link object.
|
||||
|
||||
setLink([obj,...]),
|
||||
setLink([(obj,subName,subElements),...]),
|
||||
setLink({index:obj,...}),
|
||||
setLink({index:(obj,subName,subElements),...}): set link element of a link group.
|
||||
|
||||
obj (DocumentObject): the object to link to. If this is None, then the link is cleared
|
||||
|
||||
subName (String): Dot separated object path.
|
||||
|
||||
subElements (String|tuple(String)): non-object sub-elements, e.g. Face1, Edge2.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="cacheChildLabel">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
cacheChildLabel(enable=True): enable/disable child label cache
|
||||
|
||||
The cache is not updated on child label change for performance reason. You must
|
||||
call this function on any child label change
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="flattenSubname">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
flattenSubname(subname) -> string
|
||||
|
||||
Return a flattened subname in case it references an object inside a linked plain group
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="expandSubname">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
expandSubname(subname) -> string
|
||||
|
||||
Return an expanded subname in case it references an object inside a linked plain group
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<CustomAttributes />
|
||||
<Attribute Name="LinkedChildren" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return a flattend (in case grouped by plain group) list of linked children</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LinkedChildren" Type="List"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
316
src/App/LinkBaseExtensionPyImp.cpp
Normal file
316
src/App/LinkBaseExtensionPyImp.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#endif
|
||||
|
||||
#include "DocumentObjectPy.h"
|
||||
#include "LinkBaseExtensionPy.h"
|
||||
#include "LinkBaseExtensionPy.cpp"
|
||||
|
||||
using namespace App;
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string LinkBaseExtensionPy::representation(void) const
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << "<" << getLinkBaseExtensionPtr()->getExtensionClassTypeId().getName() << ">";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
typedef std::map<std::string, std::pair<int,Property*> > PropTmpMap;
|
||||
typedef std::map<std::string, Property*> PropMap;
|
||||
|
||||
static bool getProperty(PropTmpMap &props, const LinkBaseExtension::PropInfoMap &infoMap,
|
||||
const PropMap &propMap, PyObject *key, PyObject *value)
|
||||
{
|
||||
std::ostringstream str;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if(!PyString_Check(key)) {
|
||||
PyErr_SetString(PyExc_TypeError, "key must be string");
|
||||
return false;
|
||||
}
|
||||
const char *keyStr = PyString_AsString(key);
|
||||
#else
|
||||
if(!PyUnicode_Check(key)) {
|
||||
PyErr_SetString(PyExc_TypeError, "key must be a unicode string");
|
||||
return false;
|
||||
}
|
||||
const char *keyStr = PyUnicode_AsUTF8(key);
|
||||
#endif
|
||||
auto it = infoMap.find(keyStr);
|
||||
if(it == infoMap.end()){
|
||||
str << "unknown key '" << keyStr << "'";
|
||||
PyErr_SetString(PyExc_KeyError, str.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *valStr = 0;
|
||||
if(key == value)
|
||||
valStr = keyStr;
|
||||
else if (value!=Py_None) {
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if(!PyString_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be string");
|
||||
return false;
|
||||
}
|
||||
valStr = PyString_AsString(value);
|
||||
#else
|
||||
if(!PyUnicode_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be unicode string");
|
||||
return false;
|
||||
}
|
||||
valStr = PyUnicode_AsUTF8(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
App::Property *prop = 0;
|
||||
auto &info = it->second;
|
||||
if(valStr) {
|
||||
auto pIt = propMap.find(valStr);
|
||||
if(pIt == propMap.end()) {
|
||||
str << "cannot find property '" << valStr << "'";
|
||||
PyErr_SetString(PyExc_ValueError, str.str().c_str());
|
||||
return false;
|
||||
}
|
||||
prop = pIt->second;
|
||||
if(!prop->isDerivedFrom(info.type)) {
|
||||
str << "expect property '" << keyStr << "(" << valStr
|
||||
<< ") to be derived from '" << info.type.getName()
|
||||
<< "', instead of '" << prop->getTypeId().getName() << "'";
|
||||
PyErr_SetString(PyExc_TypeError, str.str().c_str());
|
||||
}
|
||||
}
|
||||
props[keyStr] = std::make_pair(info.index,prop);
|
||||
return true;
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::configLinkProperty(PyObject *args, PyObject *keywds) {
|
||||
auto ext = getLinkBaseExtensionPtr();
|
||||
const auto &info = ext->getPropertyInfoMap();
|
||||
|
||||
PropMap propMap;
|
||||
ext->getExtendedContainer()->getPropertyMap(propMap);
|
||||
|
||||
PropTmpMap props;
|
||||
|
||||
if(args && PyTuple_Check(args)) {
|
||||
for(Py_ssize_t pos=0;pos<PyTuple_GET_SIZE(args);++pos) {
|
||||
auto key = PyTuple_GET_ITEM(args,pos);
|
||||
if(!getProperty(props,info,propMap,key,key))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(keywds && PyDict_Check(keywds)) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
while (PyDict_Next(keywds, &pos, &key, &value)) {
|
||||
if(!getProperty(props,info,propMap,key,value))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for(auto &v : props)
|
||||
ext->setProperty(v.second.first,v.second.second);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::getLinkExtProperty(PyObject *args)
|
||||
{
|
||||
const char *name;
|
||||
if(!PyArg_ParseTuple(args,"s",&name))
|
||||
return 0;
|
||||
auto prop = getLinkBaseExtensionPtr()->getProperty(name);
|
||||
if(!prop) {
|
||||
PyErr_SetString(PyExc_AttributeError, "unknown property name");
|
||||
return 0;
|
||||
}
|
||||
return prop->getPyObject();
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::getLinkExtPropertyName(PyObject *args) {
|
||||
const char *name;
|
||||
if(!PyArg_ParseTuple(args,"s",&name))
|
||||
return 0;
|
||||
auto prop = getLinkBaseExtensionPtr()->getProperty(name);
|
||||
if(!prop) {
|
||||
PyErr_SetString(PyExc_AttributeError, "unknown property name");
|
||||
return 0;
|
||||
}
|
||||
auto container = getLinkBaseExtensionPtr()->getExtendedContainer();
|
||||
if(!container) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "no extended container");
|
||||
return 0;
|
||||
}
|
||||
name = container->getPropertyName(prop);
|
||||
if(!name) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "cannot find property name");
|
||||
return 0;
|
||||
}
|
||||
return Py::new_reference_to(Py::String(name));
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::getLinkPropertyInfo(PyObject *args)
|
||||
{
|
||||
auto ext = getLinkBaseExtensionPtr();
|
||||
|
||||
const auto &infos = ext->getPropertyInfo();
|
||||
|
||||
if(PyArg_ParseTuple(args,"")) {
|
||||
Py::Tuple ret(infos.size());
|
||||
int i=0;
|
||||
for(const auto &info : infos) {
|
||||
ret.setItem(i++,Py::TupleN(Py::String(info.name),
|
||||
Py::String(info.type.getName()),Py::String(info.doc)));
|
||||
}
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
short index = 0;
|
||||
if(PyArg_ParseTuple(args,"h",&index)) {
|
||||
if(index<0 || index>=(int)infos.size()) {
|
||||
PyErr_SetString(PyExc_ValueError, "index out of range");
|
||||
return 0;
|
||||
}
|
||||
Py::TupleN ret(Py::String(infos[index].name),
|
||||
Py::String(infos[index].type.getName()),Py::String(infos[index].doc));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
char *name;
|
||||
if(PyArg_ParseTuple(args,"s",&name)) {
|
||||
for(int i=0;i<(int)infos.size();++i) {
|
||||
if(strcmp(infos[i].name,name)==0) {
|
||||
Py::TupleN ret(Py::String(infos[i].type.getName()),
|
||||
Py::String(infos[i].doc));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "unknown property name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_ValueError, "invalid arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void parseLink(LinkBaseExtension *ext, int index, PyObject *value) {
|
||||
App::DocumentObject *obj = 0;
|
||||
PropertyStringList subs;
|
||||
PropertyString sub;
|
||||
if(value!=Py_None) {
|
||||
if(PyObject_TypeCheck(value,&DocumentObjectPy::Type)) {
|
||||
obj = static_cast<DocumentObjectPy*>(value)->getDocumentObjectPtr();
|
||||
}else if(!PySequence_Check(value))
|
||||
throw Base::TypeError("Expects type of DocumentObject or sequence");
|
||||
else{
|
||||
Py::Sequence seq(value);
|
||||
if(seq[0].ptr() != Py_None) {
|
||||
if(!PyObject_TypeCheck(seq[0].ptr(),&DocumentObjectPy::Type))
|
||||
throw Base::TypeError("Expects the first argument to be DocumentObject in sequence");
|
||||
obj = static_cast<DocumentObjectPy*>(seq[0].ptr())->getDocumentObjectPtr();
|
||||
if(seq.size()>1) {
|
||||
sub.setPyObject(seq[1].ptr());
|
||||
if(seq.size()>2)
|
||||
subs.setPyObject(seq[2].ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ext->setLink(index,obj,sub.getValue(),subs.getValue());
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::setLink(PyObject *_args)
|
||||
{
|
||||
Py::Sequence args(_args);
|
||||
PY_TRY {
|
||||
auto ext = getLinkBaseExtensionPtr();
|
||||
PyObject *pcObj = args.size()?args[0].ptr():Py_None;
|
||||
if(pcObj == Py_None) {
|
||||
ext->setLink(-1,0);
|
||||
}else if(PyDict_Check(pcObj)) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
while(PyDict_Next(pcObj, &pos, &key, &value))
|
||||
parseLink(ext,Py::Int(key),value);
|
||||
}else if(PySequence_Check(pcObj)) {
|
||||
ext->setLink(-1,0);
|
||||
Py::Sequence seq(pcObj);
|
||||
for(size_t i=0;i<seq.size();++i)
|
||||
parseLink(ext,i,seq[i].ptr());
|
||||
}else
|
||||
parseLink(ext,-1,_args);
|
||||
|
||||
Py_Return;
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::cacheChildLabel(PyObject *args) {
|
||||
PyObject *enable = Py_True;
|
||||
if(!PyArg_ParseTuple(args,"|O",&enable))
|
||||
return 0;
|
||||
PY_TRY {
|
||||
getLinkBaseExtensionPtr()->cacheChildLabel(PyObject_IsTrue(enable)?-1:0);
|
||||
Py_Return;
|
||||
}PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::flattenSubname(PyObject *args) {
|
||||
const char *subname;
|
||||
if(!PyArg_ParseTuple(args,"s",&subname))
|
||||
return 0;
|
||||
PY_TRY {
|
||||
return Py::new_reference_to(Py::String(
|
||||
getLinkBaseExtensionPtr()->flattenSubname(subname)));
|
||||
}PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkBaseExtensionPy::expandSubname(PyObject *args) {
|
||||
const char *subname;
|
||||
if(!PyArg_ParseTuple(args,"s",&subname))
|
||||
return 0;
|
||||
PY_TRY {
|
||||
std::string sub(subname);
|
||||
getLinkBaseExtensionPtr()->expandSubname(sub);
|
||||
return Py::new_reference_to(Py::String(sub));
|
||||
}PY_CATCH;
|
||||
}
|
||||
|
||||
Py::List LinkBaseExtensionPy::getLinkedChildren() const {
|
||||
Py::List ret;
|
||||
for(auto o : getLinkBaseExtensionPtr()->getLinkedChildren(true))
|
||||
ret.append(Py::asObject(o->getPyObject()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *LinkBaseExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LinkBaseExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -282,6 +282,18 @@ public:
|
||||
float transparency;
|
||||
//@}
|
||||
|
||||
bool operator==(const Material& m) const
|
||||
{
|
||||
return _matType!=m._matType || shininess!=m.shininess ||
|
||||
transparency!=m.transparency || ambientColor!=m.ambientColor ||
|
||||
diffuseColor!=m.diffuseColor || specularColor!=m.specularColor ||
|
||||
emissiveColor!=m.emissiveColor;
|
||||
}
|
||||
bool operator!=(const Material& m) const
|
||||
{
|
||||
return !operator==(m);
|
||||
}
|
||||
|
||||
private:
|
||||
MaterialType _matType;
|
||||
};
|
||||
|
||||
@@ -119,6 +119,8 @@
|
||||
#include "ViewProviderMaterialObject.h"
|
||||
#include "ViewProviderTextDocument.h"
|
||||
#include "ViewProviderGroupExtension.h"
|
||||
#include "ViewProviderLink.h"
|
||||
#include "LinkViewPy.h"
|
||||
|
||||
#include "Language/Translator.h"
|
||||
#include "TaskView/TaskView.h"
|
||||
@@ -401,6 +403,7 @@ Application::Application(bool GUIenabled)
|
||||
Gui::TaskView::ControlPy::init_type();
|
||||
Py::Module(module).setAttr(std::string("Control"),
|
||||
Py::Object(Gui::TaskView::ControlPy::getInstance(), true));
|
||||
Base::Interpreter().addType(&LinkViewPy::Type,module,"LinkView");
|
||||
}
|
||||
|
||||
Base::PyGILStateLocker lock;
|
||||
@@ -668,6 +671,7 @@ void Application::createStandardOperations()
|
||||
Gui::CreateWindowStdCommands();
|
||||
Gui::CreateStructureCommands();
|
||||
Gui::CreateTestCommands();
|
||||
Gui::CreateLinkCommands();
|
||||
}
|
||||
|
||||
void Application::slotNewDocument(const App::Document& Doc, bool isMainDoc)
|
||||
@@ -1681,6 +1685,10 @@ void Application::initTypes(void)
|
||||
Gui::ViewProviderMaterialObject ::init();
|
||||
Gui::ViewProviderMaterialObjectPython ::init();
|
||||
Gui::ViewProviderTextDocument ::init();
|
||||
Gui::ViewProviderLinkObserver ::init();
|
||||
Gui::LinkView ::init();
|
||||
Gui::ViewProviderLink ::init();
|
||||
Gui::ViewProviderLinkPython ::init();
|
||||
|
||||
// Workbench
|
||||
Gui::Workbench ::init();
|
||||
|
||||
@@ -210,6 +210,8 @@ generate_from_xml(ViewProviderPy)
|
||||
generate_from_xml(ViewProviderDocumentObjectPy)
|
||||
generate_from_xml(WorkbenchPy)
|
||||
generate_from_xml(SelectionObjectPy)
|
||||
generate_from_xml(LinkViewPy)
|
||||
generate_from_xml(ViewProviderLinkPy)
|
||||
|
||||
generate_from_py(FreeCADGuiInit GuiInitScript.h)
|
||||
|
||||
@@ -221,6 +223,8 @@ SET(FreeCADGui_XML_SRCS
|
||||
WorkbenchPy.xml
|
||||
SelectionObjectPy.xml
|
||||
DocumentPy.xml
|
||||
LinkViewPy.xml
|
||||
ViewProviderLinkPy.xml
|
||||
)
|
||||
SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS})
|
||||
|
||||
@@ -361,6 +365,7 @@ set(Gui_MOC_HDRS
|
||||
TaskView/TaskView.h
|
||||
DAGView/DAGView.h
|
||||
DAGView/DAGModel.h
|
||||
TaskElementColors.h
|
||||
DlgObjectSelection.h
|
||||
${FreeCADGui_SDK_MOC_HDRS}
|
||||
)
|
||||
@@ -434,6 +439,7 @@ SET(Gui_UIC_SRCS
|
||||
TextureMapping.ui
|
||||
TaskView/TaskAppearance.ui
|
||||
TaskView/TaskSelectLinkProperty.ui
|
||||
TaskElementColors.ui
|
||||
DlgObjectSelection.ui
|
||||
)
|
||||
|
||||
@@ -466,6 +472,7 @@ SET(Command_CPP_SRCS
|
||||
CommandTest.cpp
|
||||
CommandView.cpp
|
||||
CommandStructure.cpp
|
||||
CommandLink.cpp
|
||||
)
|
||||
SET(Command_SRCS
|
||||
${Command_CPP_SRCS}
|
||||
@@ -507,6 +514,7 @@ SET(Dialog_CPP_SRCS
|
||||
DownloadItem.cpp
|
||||
DownloadManager.cpp
|
||||
DocumentRecovery.cpp
|
||||
TaskElementColors.cpp
|
||||
DlgObjectSelection.cpp
|
||||
)
|
||||
|
||||
@@ -541,6 +549,7 @@ SET(Dialog_HPP_SRCS
|
||||
DownloadItem.h
|
||||
DownloadManager.h
|
||||
DocumentRecovery.h
|
||||
TaskElementColors.h
|
||||
DlgObjectSelection.h
|
||||
)
|
||||
|
||||
@@ -577,6 +586,7 @@ SET(Dialog_SRCS
|
||||
Placement.ui
|
||||
SceneInspector.ui
|
||||
TextureMapping.ui
|
||||
TaskElementColors.ui
|
||||
DlgObjectSelection.ui
|
||||
)
|
||||
SOURCE_GROUP("Dialog" FILES ${Dialog_SRCS})
|
||||
@@ -983,6 +993,9 @@ SET(Viewprovider_CPP_SRCS
|
||||
ViewProviderOrigin.cpp
|
||||
ViewProviderMaterialObject.cpp
|
||||
ViewProviderTextDocument.cpp
|
||||
ViewProviderLink.cpp
|
||||
LinkViewPyImp.cpp
|
||||
ViewProviderLinkPyImp.cpp
|
||||
)
|
||||
SET(Viewprovider_SRCS
|
||||
${Viewprovider_CPP_SRCS}
|
||||
@@ -1013,6 +1026,7 @@ SET(Viewprovider_SRCS
|
||||
ViewProviderOrigin.h
|
||||
ViewProviderMaterialObject.h
|
||||
ViewProviderTextDocument.h
|
||||
ViewProviderLink.h
|
||||
)
|
||||
SOURCE_GROUP("View3D\\Viewprovider" FILES ${Viewprovider_SRCS})
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Selection.h"
|
||||
#include "ViewProvider.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "ViewProviderLink.h"
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
@@ -89,11 +90,17 @@ void StdCmdRandomColor::activated(int iMsg)
|
||||
float fBlu = (float)rand()/fMax;
|
||||
|
||||
ViewProvider* view = Application::Instance->getDocument(it->pDoc)->getViewProvider(it->pObject);
|
||||
App::Property* color = view->getPropertyByName("ShapeColor");
|
||||
if (color && color->getTypeId() == App::PropertyColor::getClassTypeId()) {
|
||||
auto vpLink = dynamic_cast<ViewProviderLink*>(view);
|
||||
if(vpLink) {
|
||||
if(!vpLink->OverrideMaterial.getValue())
|
||||
FCMD_VOBJ_CMD2("OverrideMaterial = True",it->pObject);
|
||||
FCMD_VOBJ_CMD2("ShapeMaterial.DiffuseColor=(%.2f,%.2f,%.2f)", it->pObject, fRed, fGrn, fBlu);
|
||||
continue;
|
||||
}
|
||||
auto color = dynamic_cast<App::PropertyColor*>(view->getPropertyByName("ShapeColor"));
|
||||
if (color) {
|
||||
// get the view provider of the selected object and set the shape color
|
||||
doCommand(Gui, "Gui.getDocument(\"%s\").getObject(\"%s\").ShapeColor=(%.2f,%.2f,%.2f)"
|
||||
, it->DocName, it->FeatName, fRed, fGrn, fBlu);
|
||||
FCMD_VOBJ_CMD2("ShapeColor=(%.2f,%.2f,%.2f)" , it->pObject, fRed, fGrn, fBlu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
810
src/Gui/CommandLink.cpp
Normal file
810
src/Gui/CommandLink.cpp
Normal file
@@ -0,0 +1,810 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
# include <QMessageBox>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "Command.h"
|
||||
#include "Action.h"
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Tree.h"
|
||||
#include "Document.h"
|
||||
#include "Selection.h"
|
||||
#include "WaitCursor.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <App/Link.h>
|
||||
|
||||
FC_LOG_LEVEL_INIT("CommandLink",true,true);
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
static void setLinkLabel(App::DocumentObject *obj, const char *doc, const char *name) {
|
||||
const char *label = obj->Label.getValue();
|
||||
Command::doCommand(Command::Doc,"App.getDocument('%s').getObject('%s').Label='%s'",doc,name,label);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class StdCmdLinkMakeGroup : public Gui::Command
|
||||
{
|
||||
public:
|
||||
StdCmdLinkMakeGroup();
|
||||
const char* className() const
|
||||
{ return "StdCmdLinkMakeGroup"; }
|
||||
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual bool isActive(void);
|
||||
virtual Action * createAction(void);
|
||||
virtual void languageChange();
|
||||
};
|
||||
|
||||
StdCmdLinkMakeGroup::StdCmdLinkMakeGroup()
|
||||
: Command("Std_LinkMakeGroup")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Make link group");
|
||||
sToolTipText = QT_TR_NOOP("Create a group of links");
|
||||
sWhatsThis = "Std_LinkMakeGroup";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "LinkGroup";
|
||||
}
|
||||
|
||||
bool StdCmdLinkMakeGroup::isActive() {
|
||||
return !!App::GetApplication().getActiveDocument();
|
||||
}
|
||||
|
||||
Action * StdCmdLinkMakeGroup::createAction(void)
|
||||
{
|
||||
ActionGroup* pcAction = new ActionGroup(this, getMainWindow());
|
||||
pcAction->setDropDownMenu(true);
|
||||
applyCommandData(this->className(), pcAction);
|
||||
|
||||
// add the action items
|
||||
pcAction->addAction(QObject::tr("Simple group"));
|
||||
pcAction->addAction(QObject::tr("Group with links"));
|
||||
pcAction->addAction(QObject::tr("Group with transform links"));
|
||||
return pcAction;
|
||||
}
|
||||
|
||||
void StdCmdLinkMakeGroup::languageChange()
|
||||
{
|
||||
Command::languageChange();
|
||||
|
||||
if (!_pcAction)
|
||||
return;
|
||||
ActionGroup* pcAction = qobject_cast<ActionGroup*>(_pcAction);
|
||||
QList<QAction*> acts = pcAction->actions();
|
||||
acts[0]->setText(QObject::tr("Simple group"));
|
||||
acts[1]->setText(QObject::tr("Group with links"));
|
||||
acts[2]->setText(QObject::tr("Group with transform links"));
|
||||
}
|
||||
|
||||
|
||||
void StdCmdLinkMakeGroup::activated(int option) {
|
||||
|
||||
std::vector<App::DocumentObject*> objs;
|
||||
std::set<App::DocumentObject*> objset;
|
||||
|
||||
auto doc = App::GetApplication().getActiveDocument();
|
||||
if(!doc) {
|
||||
FC_ERR("no active document");
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &sel : Selection().getCompleteSelection()) {
|
||||
if(sel.pObject && sel.pObject->getNameInDocument() &&
|
||||
objset.insert(sel.pObject).second)
|
||||
objs.push_back(sel.pObject);
|
||||
}
|
||||
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
|
||||
Command::openCommand("Make link group");
|
||||
try {
|
||||
std::string groupName = doc->getUniqueObjectName("LinkGroup");
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::LinkGroup','%s')",doc->getName(),groupName.c_str());
|
||||
if(objs.empty()) {
|
||||
Selection().addSelection(doc->getName(),groupName.c_str());
|
||||
Selection().selStackPush();
|
||||
}else{
|
||||
Command::doCommand(Command::Doc,"__objs__ = []");
|
||||
for(auto obj : objs) {
|
||||
std::string name;
|
||||
if(option!=0 || doc!=obj->getDocument()) {
|
||||
name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s').setLink("
|
||||
"App.getDocument('%s').getObject('%s'))",
|
||||
doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
|
||||
setLinkLabel(obj,doc->getName(),name.c_str());
|
||||
if(option==2)
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').getObject('%s').LinkTransform = True",
|
||||
doc->getName(),name.c_str());
|
||||
else if(obj->getPropertyByName("Placement"))
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').getObject('%s').Placement = "
|
||||
"App.getDocument('%s').getObject('%s').Placement",
|
||||
doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
|
||||
}else
|
||||
name = obj->getNameInDocument();
|
||||
Command::doCommand(Command::Doc,"__objs__.append(App.getDocument('%s').getObject('%s'))",
|
||||
doc->getName(),name.c_str());
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').getObject('%s').ViewObject.Visibility=False",
|
||||
doc->getName(),name.c_str());
|
||||
}
|
||||
Command::doCommand(Command::Doc,"App.getDocument('%s').getObject('%s').setLink(__objs__)",
|
||||
doc->getName(),groupName.c_str());
|
||||
Command::doCommand(Command::Doc,"del __objs__");
|
||||
|
||||
for(size_t i=0;i<objs.size();++i) {
|
||||
auto name = std::to_string(i)+".";
|
||||
Selection().addSelection(doc->getName(),groupName.c_str(),name.c_str());
|
||||
}
|
||||
Selection().selStackPush();
|
||||
}
|
||||
if(option!=0) {
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').getObject('%s').LinkMode = 'Auto Delete'",
|
||||
doc->getName(),groupName.c_str());
|
||||
}
|
||||
Command::commitCommand();
|
||||
} catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Create link group failed"),
|
||||
QString::fromLatin1(e.what()));
|
||||
Command::abortCommand();
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD(StdCmdLinkMake)
|
||||
|
||||
StdCmdLinkMake::StdCmdLinkMake()
|
||||
: Command("Std_LinkMake")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Make link");
|
||||
sToolTipText = QT_TR_NOOP("Create a link to the selected object(s)");
|
||||
sWhatsThis = "Std_LinkMake";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "Link";
|
||||
}
|
||||
|
||||
void StdCmdLinkMake::activated(int) {
|
||||
auto doc = App::GetApplication().getActiveDocument();
|
||||
if(!doc) {
|
||||
FC_ERR("no active document");
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<App::DocumentObject*> objs;
|
||||
for(auto &sel : Selection().getCompleteSelection()) {
|
||||
if(sel.pObject && sel.pObject->getNameInDocument())
|
||||
objs.insert(sel.pObject);
|
||||
}
|
||||
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
|
||||
Command::openCommand("Make link");
|
||||
try {
|
||||
if(objs.empty()) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(Command::Doc, "App.getDocument('%s').addObject('App::Link','%s')",
|
||||
doc->getName(),name.c_str());
|
||||
Selection().addSelection(doc->getName(),name.c_str());
|
||||
}else{
|
||||
for(auto obj : objs) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s').setLink(App.getDocument('%s').%s)",
|
||||
doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
|
||||
setLinkLabel(obj,doc->getName(),name.c_str());
|
||||
Selection().addSelection(doc->getName(),name.c_str());
|
||||
}
|
||||
}
|
||||
Selection().selStackPush();
|
||||
Command::commitCommand();
|
||||
} catch (const Base::Exception& e) {
|
||||
Command::abortCommand();
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Create link failed"),
|
||||
QString::fromLatin1(e.what()));
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkMakeRelative)
|
||||
|
||||
StdCmdLinkMakeRelative::StdCmdLinkMakeRelative()
|
||||
: Command("Std_LinkMakeRelative")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Make relative link");
|
||||
sToolTipText = QT_TR_NOOP("Create a relative link of two selected objects");
|
||||
sWhatsThis = "Std_LinkMakeRelative";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "LinkSub";
|
||||
}
|
||||
|
||||
bool StdCmdLinkMakeRelative::isActive() {
|
||||
return Selection().hasSubSelection();
|
||||
}
|
||||
|
||||
void StdCmdLinkMakeRelative::activated(int) {
|
||||
auto doc = App::GetApplication().getActiveDocument();
|
||||
if(!doc) {
|
||||
FC_ERR("no active document");
|
||||
return;
|
||||
}
|
||||
Command::openCommand("Make relative link");
|
||||
try {
|
||||
std::vector<std::string> newNames;
|
||||
for(auto &sel : Selection().getCompleteSelection(0)) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
FCMD_DOC_CMD(doc,"addObject('App::Link','" << name << "').setLink("
|
||||
<< getObjectCmd(sel.pObject) << ",'" << sel.SubName << "')");
|
||||
auto link = doc->getObject(name.c_str());
|
||||
FCMD_OBJ_CMD(link,"LinkTransform = True");
|
||||
setLinkLabel(sel.pResolvedObject,doc->getName(),name.c_str());
|
||||
|
||||
newNames.push_back(std::move(name));
|
||||
}
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
for(auto &name : newNames)
|
||||
Selection().addSelection(doc->getName(),name.c_str());
|
||||
Selection().selStackPush();
|
||||
|
||||
Command::commitCommand();
|
||||
} catch (const Base::Exception& e) {
|
||||
Command::abortCommand();
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Failed to create relative link"),
|
||||
QString::fromLatin1(e.what()));
|
||||
e.ReportException();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Info {
|
||||
bool inited = false;
|
||||
App::DocumentObjectT topParent;
|
||||
std::string subname;
|
||||
App::DocumentObjectT parent;
|
||||
App::DocumentObjectT obj;
|
||||
};
|
||||
|
||||
static void linkConvert(bool unlink) {
|
||||
// We are trying to replace an object with a link (App::Link), or replace a
|
||||
// link back to its linked object (i.e. unlink). This is a very complex
|
||||
// operation. It works by reassign the link property of the parent of the
|
||||
// selected object(s) to a newly created link to the original object.
|
||||
// Everything should remain the same. This complexity is now largely handled
|
||||
// by ViewProviderDocumentObject::replaceObject(), which in turn relies on
|
||||
// PropertyLinkBase::CopyOnLinkReplace().
|
||||
|
||||
std::map<std::pair<App::DocumentObject*,App::DocumentObject*>, Info> infos;
|
||||
for(auto sel : TreeWidget::getSelection()) {
|
||||
auto obj = sel.vp->getObject();
|
||||
auto parent = sel.parentVp;
|
||||
if(!parent) {
|
||||
FC_WARN("skip '" << obj->getFullName() << "' with no parent");
|
||||
continue;
|
||||
}
|
||||
auto parentObj = parent->getObject();
|
||||
auto &info = infos[std::make_pair(parentObj,obj)];
|
||||
if(info.inited)
|
||||
continue;
|
||||
info.inited = true;
|
||||
if(unlink) {
|
||||
auto linked = obj->getLinkedObject(false);
|
||||
if(!linked || !linked->getNameInDocument() || linked == obj) {
|
||||
FC_WARN("skip non link");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
info.topParent = sel.topParent;
|
||||
info.parent = parentObj;
|
||||
info.obj = obj;
|
||||
}
|
||||
|
||||
if(infos.empty())
|
||||
return;
|
||||
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
|
||||
// now, do actual operation
|
||||
const char *transactionName = unlink?"Unlink":"Replace with link";
|
||||
Command::openCommand(transactionName);
|
||||
try {
|
||||
std::unordered_map<App::DocumentObject*,App::DocumentObjectT> recomputeSet;
|
||||
for(auto &v : infos) {
|
||||
auto &info = v.second;
|
||||
auto parent = info.parent.getObject();
|
||||
auto parentVp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
|
||||
Application::Instance->getViewProvider(parent));
|
||||
auto obj = info.obj.getObject();
|
||||
if(!parent || !obj || !parentVp)
|
||||
continue;
|
||||
if(!recomputeSet.count(parent))
|
||||
recomputeSet.emplace(parent,parent);
|
||||
auto doc = parent->getDocument();
|
||||
App::DocumentObject *replaceObj;
|
||||
if(unlink) {
|
||||
replaceObj = obj->getLinkedObject(false);
|
||||
if(!replaceObj || !replaceObj->getNameInDocument() || replaceObj == obj)
|
||||
continue;
|
||||
}else{
|
||||
auto name = doc->getUniqueObjectName("Link");
|
||||
auto link = static_cast<App::Link*>(doc->addObject("App::Link",name.c_str()));
|
||||
if(!link)
|
||||
FC_THROWM(Base::RuntimeError,"Failed to create link");
|
||||
link->setLink(-1,obj);
|
||||
link->Label.setValue(obj->Label.getValue());
|
||||
auto pla = Base::freecad_dynamic_cast<App::PropertyPlacement>(
|
||||
obj->getPropertyByName("Placement"));
|
||||
if(pla)
|
||||
link->Placement.setValue(pla->getValue());
|
||||
else
|
||||
link->LinkTransform.setValue(true);
|
||||
replaceObj = link;
|
||||
}
|
||||
|
||||
// adjust subname for the the new object
|
||||
auto pos = info.subname.rfind('.');
|
||||
if(pos==std::string::npos && pos)
|
||||
info.subname.clear();
|
||||
else {
|
||||
pos = info.subname.rfind('.',pos-1);
|
||||
if(pos==std::string::npos)
|
||||
info.subname.clear();
|
||||
else {
|
||||
info.subname.resize(pos+1);
|
||||
info.subname += replaceObj->getNameInDocument();
|
||||
info.subname += ".";
|
||||
}
|
||||
}
|
||||
|
||||
// do the replacement operation
|
||||
if(parentVp->replaceObject(obj,replaceObj)<=0)
|
||||
FC_THROWM(Base::RuntimeError,
|
||||
"Failed to change link for " << parent->getFullName());
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject *> recomputes;
|
||||
for(auto &v : recomputeSet) {
|
||||
auto obj = v.second.getObject();
|
||||
if(obj)
|
||||
recomputes.push_back(obj);
|
||||
}
|
||||
if(recomputes.size())
|
||||
recomputes.front()->getDocument()->recompute(recomputes);
|
||||
|
||||
Command::commitCommand();
|
||||
|
||||
} catch (const Base::Exception& e) {
|
||||
Command::abortCommand();
|
||||
auto title = unlink?QObject::tr("Unlink failed"):QObject::tr("Replace link failed");
|
||||
QMessageBox::critical(getMainWindow(), title, QString::fromLatin1(e.what()));
|
||||
e.ReportException();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool linkConvertible(bool unlink) {
|
||||
int count = 0;
|
||||
for(auto &sel : TreeWidget::getSelection()) {
|
||||
auto parent = sel.parentVp;
|
||||
if(!parent) return false;
|
||||
auto obj = sel.vp->getObject();
|
||||
if(unlink) {
|
||||
auto linked = obj->getLinkedObject(false);
|
||||
if(!linked || linked == obj)
|
||||
return false;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
return count!=0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkReplace)
|
||||
|
||||
StdCmdLinkReplace::StdCmdLinkReplace()
|
||||
: Command("Std_LinkReplace")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Replace with link");
|
||||
sToolTipText = QT_TR_NOOP("Replace the selected object(s) with link");
|
||||
sWhatsThis = "Std_LinkReplace";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "LinkReplace";
|
||||
}
|
||||
|
||||
bool StdCmdLinkReplace::isActive() {
|
||||
return linkConvertible(false);
|
||||
}
|
||||
|
||||
void StdCmdLinkReplace::activated(int) {
|
||||
linkConvert(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkUnlink)
|
||||
|
||||
StdCmdLinkUnlink::StdCmdLinkUnlink()
|
||||
: Command("Std_LinkUnlink")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Unlink");
|
||||
sToolTipText = QT_TR_NOOP("Strip on level of link");
|
||||
sWhatsThis = "Std_LinkUnlink";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "Unlink";
|
||||
}
|
||||
|
||||
bool StdCmdLinkUnlink::isActive() {
|
||||
return linkConvertible(true);
|
||||
}
|
||||
|
||||
void StdCmdLinkUnlink::activated(int) {
|
||||
linkConvert(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkImport)
|
||||
|
||||
StdCmdLinkImport::StdCmdLinkImport()
|
||||
: Command("Std_LinkImport")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Import links");
|
||||
sToolTipText = QT_TR_NOOP("Import selected external link(s)");
|
||||
sWhatsThis = "Std_LinkImport";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "LinkImport";
|
||||
}
|
||||
|
||||
static std::map<App::Document*, std::vector<App::DocumentObject*> > getLinkImportSelections()
|
||||
{
|
||||
std::map<App::Document*, std::vector<App::DocumentObject*> > objMap;
|
||||
for(auto &sel : Selection().getCompleteSelection(false)) {
|
||||
auto obj = sel.pObject->resolve(sel.SubName);
|
||||
if(!obj || !obj->getNameInDocument())
|
||||
continue;
|
||||
for(auto o : obj->getOutList()) {
|
||||
if(o && o->getNameInDocument() && o->getDocument()!=obj->getDocument()) {
|
||||
objMap[obj->getDocument()].push_back(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return objMap;
|
||||
}
|
||||
|
||||
bool StdCmdLinkImport::isActive() {
|
||||
auto links = getLinkImportSelections();
|
||||
if(links.empty())
|
||||
return false;
|
||||
for(auto &v : links) {
|
||||
if(v.first->testStatus(App::Document::PartialDoc))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void StdCmdLinkImport::activated(int) {
|
||||
Command::openCommand("Import links");
|
||||
try {
|
||||
WaitCursor wc;
|
||||
wc.setIgnoreEvents(WaitCursor::NoEvents);
|
||||
for(auto &v : getLinkImportSelections()) {
|
||||
auto doc = v.first;
|
||||
// TODO: Is it possible to do this using interpreter?
|
||||
for(auto obj : doc->importLinks(v.second))
|
||||
obj->Visibility.setValue(false);
|
||||
}
|
||||
Command::commitCommand();
|
||||
}catch (const Base::Exception& e) {
|
||||
Command::abortCommand();
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Failed to import links"),
|
||||
QString::fromLatin1(e.what()));
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkImportAll)
|
||||
|
||||
StdCmdLinkImportAll::StdCmdLinkImportAll()
|
||||
: Command("Std_LinkImportAll")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Import all links");
|
||||
sToolTipText = QT_TR_NOOP("Import all links of the active document");
|
||||
sWhatsThis = "Std_LinkImportAll";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterDoc;
|
||||
sPixmap = "LinkImportAll";
|
||||
}
|
||||
|
||||
bool StdCmdLinkImportAll::isActive() {
|
||||
auto doc = App::GetApplication().getActiveDocument();
|
||||
return doc && !doc->testStatus(App::Document::PartialDoc) && App::PropertyXLink::hasXLink(doc);
|
||||
}
|
||||
|
||||
void StdCmdLinkImportAll::activated(int) {
|
||||
Command::openCommand("Import all links");
|
||||
try {
|
||||
WaitCursor wc;
|
||||
wc.setIgnoreEvents(WaitCursor::NoEvents);
|
||||
auto doc = App::GetApplication().getActiveDocument();
|
||||
if(doc) {
|
||||
for(auto obj : doc->importLinks())
|
||||
obj->Visibility.setValue(false);
|
||||
}
|
||||
Command::commitCommand();
|
||||
} catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Failed to import all links"),
|
||||
QString::fromLatin1(e.what()));
|
||||
Command::abortCommand();
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkSelectLinked)
|
||||
|
||||
StdCmdLinkSelectLinked::StdCmdLinkSelectLinked()
|
||||
: Command("Std_LinkSelectLinked")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Select linked object");
|
||||
sToolTipText = QT_TR_NOOP("Select the linked object");
|
||||
sWhatsThis = "Std_LinkSelectLinked";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterSelection;
|
||||
sPixmap = "LinkSelect";
|
||||
sAccel = "S, G";
|
||||
}
|
||||
|
||||
static App::DocumentObject *getSelectedLink(bool finalLink, std::string *subname=0) {
|
||||
const auto &sels = Selection().getSelection("*",0,true);
|
||||
if(sels.empty())
|
||||
return 0;
|
||||
auto sobj = sels[0].pObject->getSubObject(sels[0].SubName);
|
||||
if(!sobj)
|
||||
return 0;
|
||||
auto vp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
|
||||
Application::Instance->getViewProvider(sobj));
|
||||
if(!vp)
|
||||
return 0;
|
||||
|
||||
auto linkedVp = vp->getLinkedViewProvider(subname,finalLink);
|
||||
if(!linkedVp || linkedVp==vp)
|
||||
return 0;
|
||||
|
||||
if(finalLink && linkedVp == vp->getLinkedViewProvider())
|
||||
return 0;
|
||||
|
||||
auto linked = linkedVp->getObject();
|
||||
if(!linked || !linked->getNameInDocument())
|
||||
return 0;
|
||||
|
||||
if(subname && sels[0].pObject!=sobj && sels[0].SubName) {
|
||||
bool found = false;
|
||||
int pre_len=0;
|
||||
std::size_t post_len=0;
|
||||
std::string prefix;
|
||||
std::string prefix2;
|
||||
// An object can be claimed by multiple objects. Let's try select one
|
||||
// that causes minimum jump in tree view, and prefer upper over lower
|
||||
// hierarchy (because of less depth/complexity of tree expansion)
|
||||
for(auto &v : linked->getParents()) {
|
||||
if(v.first != sels[0].pObject)
|
||||
continue;
|
||||
|
||||
const char *sub = v.second.c_str();
|
||||
const char *dot = sub;
|
||||
for(const char *s=sels[0].SubName; *s && *sub==*s; ++s,++sub) {
|
||||
if(*sub == '.')
|
||||
dot = sub;
|
||||
}
|
||||
found = true;
|
||||
if(dot-v.second.c_str() > pre_len
|
||||
|| (dot-v.second.c_str()==pre_len
|
||||
&& v.second.size()<post_len))
|
||||
{
|
||||
pre_len = dot-v.second.c_str();
|
||||
prefix = std::string(sels[0].SubName,pre_len) + (v.second.c_str()+pre_len);
|
||||
post_len = v.second.size();
|
||||
}else if(!pre_len) {
|
||||
if(prefix2.empty() || prefix2.size() > v.second.size())
|
||||
prefix2 = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
linked = sels[0].pObject;
|
||||
*subname = prefix.size()?prefix:prefix2 + *subname;
|
||||
}
|
||||
}
|
||||
|
||||
return linked;
|
||||
}
|
||||
|
||||
bool StdCmdLinkSelectLinked::isActive() {
|
||||
return getSelectedLink(false)!=0;
|
||||
}
|
||||
|
||||
void StdCmdLinkSelectLinked::activated(int)
|
||||
{
|
||||
std::string subname;
|
||||
auto linked = getSelectedLink(false,&subname);
|
||||
if(!linked){
|
||||
FC_WARN("invalid selection");
|
||||
return;
|
||||
}
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
if(subname.size()) {
|
||||
Selection().addSelection(linked->getDocument()->getName(),linked->getNameInDocument(),subname.c_str());
|
||||
auto doc = Application::Instance->getDocument(linked->getDocument());
|
||||
if(doc) {
|
||||
auto vp = dynamic_cast<ViewProviderDocumentObject*>(Application::Instance->getViewProvider(linked));
|
||||
doc->setActiveView(vp);
|
||||
}
|
||||
} else {
|
||||
for(auto tree : getMainWindow()->findChildren<TreeWidget*>())
|
||||
tree->selectLinkedObject(linked);
|
||||
}
|
||||
Selection().selStackPush();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkSelectLinkedFinal)
|
||||
|
||||
StdCmdLinkSelectLinkedFinal::StdCmdLinkSelectLinkedFinal()
|
||||
: Command("Std_LinkSelectLinkedFinal")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Select the deepest linked object");
|
||||
sToolTipText = QT_TR_NOOP("Select the deepest linked object");
|
||||
sWhatsThis = "Std_LinkSelectLinkedFinal";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterSelection;
|
||||
sPixmap = "LinkSelectFinal";
|
||||
sAccel = "S, D";
|
||||
}
|
||||
|
||||
bool StdCmdLinkSelectLinkedFinal::isActive() {
|
||||
return getSelectedLink(true)!=0;
|
||||
}
|
||||
|
||||
void StdCmdLinkSelectLinkedFinal::activated(int) {
|
||||
auto linked = getSelectedLink(true);
|
||||
if(!linked){
|
||||
FC_WARN("invalid selection");
|
||||
return;
|
||||
}
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
for(auto tree : getMainWindow()->findChildren<TreeWidget*>())
|
||||
tree->selectLinkedObject(linked);
|
||||
Selection().selStackPush();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_STD_CMD_A(StdCmdLinkSelectAllLinks)
|
||||
|
||||
StdCmdLinkSelectAllLinks::StdCmdLinkSelectAllLinks()
|
||||
: Command("Std_LinkSelectAllLinks")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Link");
|
||||
sMenuText = QT_TR_NOOP("Select all links");
|
||||
sToolTipText = QT_TR_NOOP("Select all links to the current selected object");
|
||||
sWhatsThis = "Std_LinkSelectAllLinks";
|
||||
sStatusTip = sToolTipText;
|
||||
eType = AlterSelection;
|
||||
sPixmap = "LinkSelectAll";
|
||||
}
|
||||
|
||||
bool StdCmdLinkSelectAllLinks::isActive() {
|
||||
const auto &sels = Selection().getSelection("*",true,true);
|
||||
if(sels.empty())
|
||||
return false;
|
||||
return App::GetApplication().hasLinksTo(sels[0].pObject);
|
||||
}
|
||||
|
||||
void StdCmdLinkSelectAllLinks::activated(int)
|
||||
{
|
||||
auto sels = Selection().getSelection("*",true,true);
|
||||
if(sels.empty())
|
||||
return;
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
for(auto tree : getMainWindow()->findChildren<TreeWidget*>())
|
||||
tree->selectAllLinks(sels[0].pObject);
|
||||
Selection().selStackPush();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Instantiation
|
||||
//===========================================================================
|
||||
|
||||
|
||||
namespace Gui {
|
||||
|
||||
void CreateLinkCommands(void)
|
||||
{
|
||||
CommandManager &rcCmdMgr = Application::Instance->commandManager();
|
||||
rcCmdMgr.addCommand(new StdCmdLinkSelectLinked());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkSelectLinkedFinal());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkSelectAllLinks());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkMake());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkMakeRelative());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkMakeGroup());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkReplace());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkUnlink());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkImport());
|
||||
rcCmdMgr.addCommand(new StdCmdLinkImportAll());
|
||||
}
|
||||
|
||||
} // namespace Gui
|
||||
|
||||
165
src/Gui/LinkViewPy.xml
Normal file
165
src/Gui/LinkViewPy.xml
Normal file
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="LinkViewPy"
|
||||
Twin="LinkView"
|
||||
TwinPointer="LinkView"
|
||||
Include="Gui/ViewProviderLink.h"
|
||||
Namespace="Gui"
|
||||
FatherInclude="Base/BaseClass.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>Helper class to link to a view object</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="reset">
|
||||
<Documentation>
|
||||
<UserDocu>Reset the link view and clear the links</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setMaterial">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setMaterial(Material): set the override material of the entire linked object
|
||||
|
||||
setMaterial([Material,...]): set the materials for the elements of the link
|
||||
array/group.
|
||||
|
||||
setMaterial({Int:Material,...}): set the material for the elements of the
|
||||
link array/group by index.
|
||||
|
||||
If material is None, then the material is unset. If the material of an element
|
||||
is unset, it defaults to the override material of the linked object, if there
|
||||
is one
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setType">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setType(type, sublink=True): set the link type.
|
||||
|
||||
type=0: override transformation and visibility
|
||||
type=1: override visibility
|
||||
type=2: no override
|
||||
type=-1: sub-object link with override visibility
|
||||
type=-2: sub-object link with override transformation and visibility
|
||||
|
||||
sublink: auto delegate to the sub-object references in the link, if there is
|
||||
one and only one.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setTransform">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setTransform(matrix): set transformation of the linked object
|
||||
|
||||
setTransform([matrix,...]): set transformation for the elements of the link
|
||||
array/group
|
||||
|
||||
setTransform({index:matrix,...}): set transformation for elements of the link
|
||||
array/group by index
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setChildren">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setChildren([obj...],vis=[],type=0)
|
||||
Group a list of children objects. Note, this mode of operation is incompatible
|
||||
with link array. Calling this function will deactivate link array. And calling
|
||||
setSize() will reset all linked children.
|
||||
|
||||
vis: initial visibility status of the children
|
||||
|
||||
type: children linking type,
|
||||
0: override transformation and visibility,
|
||||
1: override visibility,
|
||||
2: override none.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setLink">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setLink(object): Set the link
|
||||
|
||||
setLink(object, subname): Set the link with a sub-object reference
|
||||
|
||||
setLink(object, [subname,...]): Set the link with a list of sub object references
|
||||
|
||||
object: The linked document object or its view object
|
||||
|
||||
subname: a string or tuple/list of strings sub-name references to sub object
|
||||
or sub elements (e.g. Face1, Edge2) belonging to the linked object.
|
||||
The sub-name must end with a '.' if it is referencing an sub-object,
|
||||
or else it is considered a sub-element reference.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getDetailPath">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getDetailPath(element): get the 3d path an detail of an element.
|
||||
|
||||
Return a tuple(path,detail) for the coin3D SoPath and SoDetail of the element
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementPicked">
|
||||
<Documentation>
|
||||
<UserDocu>getElementPicked(pickPoint): get the element under a 3d pick point. </UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getBoundBox">
|
||||
<Documentation>
|
||||
<UserDocu>getBoundBox(vobj=None): get the bounding box. </UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="LinkedView" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The linked view object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LinkedView" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="SubNames" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The sub-object reference of the link</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="SubNames" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="RootNode" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A pivy node holding the cloned representation of the linked view object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="RootNode" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Owner">
|
||||
<Documentation>
|
||||
<UserDocu>The owner view object of this link handle</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Owner" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Visibilities">
|
||||
<Documentation>
|
||||
<UserDocu>Get/set the child element visibility</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Visibilities" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Count">
|
||||
<Documentation>
|
||||
<UserDocu>Set the element size to create an array of linked object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Count" Type="Int" />
|
||||
</Attribute>
|
||||
<Methode Name="getChildren" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get children view objects</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
403
src/Gui/LinkViewPyImp.cpp
Normal file
403
src/Gui/LinkViewPyImp.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
#endif
|
||||
|
||||
#include <Base/MatrixPy.h>
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/BoundBoxPy.h>
|
||||
#include <App/MaterialPy.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
|
||||
#include "ViewProviderDocumentObjectPy.h"
|
||||
#include "ViewProviderLink.h"
|
||||
#include "WidgetFactory.h"
|
||||
|
||||
#include "LinkViewPy.h"
|
||||
#include "LinkViewPy.cpp"
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
PyObject *LinkViewPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
{
|
||||
return new LinkViewPy(new LinkView);
|
||||
}
|
||||
|
||||
int LinkViewPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string LinkViewPy::representation(void) const
|
||||
{
|
||||
return "<Link view>";
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::reset(PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return 0;
|
||||
|
||||
PY_TRY {
|
||||
auto lv = getLinkViewPtr();
|
||||
lv->setSize(0);
|
||||
lv->setLink(0);
|
||||
Py_Return;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::setMaterial(PyObject *args) {
|
||||
PyObject *pyObj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyObj))
|
||||
return 0;
|
||||
|
||||
PY_TRY {
|
||||
auto lv = getLinkViewPtr();
|
||||
if(pyObj == Py_None) {
|
||||
lv->setMaterial(-1,0);
|
||||
Py_Return;
|
||||
}
|
||||
if(PyObject_TypeCheck(&pyObj,&App::MaterialPy::Type)) {
|
||||
lv->setMaterial(-1,static_cast<App::MaterialPy*>(pyObj)->getMaterialPtr());
|
||||
Py_Return;
|
||||
}
|
||||
if(PyDict_Check(pyObj)) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
std::map<int,App::Material*> materials;
|
||||
while(PyDict_Next(pyObj, &pos, &key, &value)) {
|
||||
Py::Int idx(key);
|
||||
if(value == Py_None)
|
||||
materials[(int)idx] = 0;
|
||||
else if(!PyObject_TypeCheck(&value,&App::MaterialPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of material");
|
||||
return 0;
|
||||
}else
|
||||
materials[(int)idx] = static_cast<App::MaterialPy*>(value)->getMaterialPtr();
|
||||
}
|
||||
for(auto &v : materials)
|
||||
lv->setMaterial(v.first,v.second);
|
||||
Py_Return;
|
||||
}
|
||||
if(PySequence_Check(pyObj)) {
|
||||
Py::Sequence seq(pyObj);
|
||||
std::vector<App::Material*> materials;
|
||||
materials.resize(seq.size(),0);
|
||||
for(size_t i=0;i<seq.size();++i) {
|
||||
PyObject* item = seq[i].ptr();
|
||||
if(item == Py_None) continue;
|
||||
if(!PyObject_TypeCheck(&item,&App::MaterialPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of material");
|
||||
return 0;
|
||||
}
|
||||
materials[i] = static_cast<App::MaterialPy*>(item)->getMaterialPtr();
|
||||
}
|
||||
for(size_t i=0;i<materials.size();++i)
|
||||
lv->setMaterial(i,materials[i]);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of Material, [Material,...] or {Int:Material,}");
|
||||
return 0;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::setTransform(PyObject *args) {
|
||||
PyObject *pyObj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyObj))
|
||||
return 0;
|
||||
|
||||
PY_TRY {
|
||||
auto lv = getLinkViewPtr();
|
||||
if(PyObject_TypeCheck(pyObj,&Base::MatrixPy::Type)) {
|
||||
lv->setTransform(-1,*static_cast<Base::MatrixPy*>(pyObj)->getMatrixPtr());
|
||||
Py_Return;
|
||||
}
|
||||
if(PyDict_Check(pyObj)) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
std::map<int,Base::Matrix4D*> mat;
|
||||
while(PyDict_Next(pyObj, &pos, &key, &value)) {
|
||||
Py::Int idx(key);
|
||||
if(!PyObject_TypeCheck(&value,&Base::MatrixPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of Matrix");
|
||||
return 0;
|
||||
}else
|
||||
mat[(int)idx] = static_cast<Base::MatrixPy*>(value)->getMatrixPtr();
|
||||
}
|
||||
for(auto &v : mat)
|
||||
lv->setTransform(v.first,*v.second);
|
||||
Py_Return;
|
||||
}
|
||||
if(PySequence_Check(pyObj)) {
|
||||
Py::Sequence seq(pyObj);
|
||||
std::vector<Base::Matrix4D*> mat;
|
||||
mat.resize(seq.size(),0);
|
||||
for(size_t i=0;i<seq.size();++i) {
|
||||
PyObject* item = seq[i].ptr();
|
||||
if(!PyObject_TypeCheck(&item,&Base::MatrixPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of Matrix");
|
||||
return 0;
|
||||
}
|
||||
mat[i] = static_cast<Base::MatrixPy*>(item)->getMatrixPtr();
|
||||
}
|
||||
for(size_t i=0;i<mat.size();++i)
|
||||
lv->setTransform(i,*mat[i]);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of Matrix, [Matrix,...] or {Int:Matrix,...}");
|
||||
return 0;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::setType(PyObject *args) {
|
||||
short type;
|
||||
PyObject *sublink = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "h|O", &type,&sublink))
|
||||
return 0;
|
||||
|
||||
PY_TRY{
|
||||
getLinkViewPtr()->setNodeType((LinkView::SnapshotType)type,PyObject_IsTrue(sublink));
|
||||
Py_Return;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::setChildren(PyObject *args) {
|
||||
PyObject *pyObj;
|
||||
PyObject *pyVis = Py_None;
|
||||
short type=0;
|
||||
if (!PyArg_ParseTuple(args, "O|Os",&pyObj,&pyVis,&type))
|
||||
return 0;
|
||||
|
||||
PY_TRY{
|
||||
App::PropertyBoolList vis;
|
||||
App::PropertyLinkList links;
|
||||
if(pyObj!=Py_None)
|
||||
links.setPyObject(pyObj);
|
||||
if(pyVis!=Py_None)
|
||||
vis.setPyObject(pyVis);
|
||||
getLinkViewPtr()->setChildren(links.getValue(),vis.getValue(),(LinkView::SnapshotType)type);
|
||||
Py_Return;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::setLink(PyObject *args)
|
||||
{
|
||||
PyObject *pyObj;
|
||||
PyObject *pySubName = Py_None;
|
||||
if (!PyArg_ParseTuple(args, "O|O",&pyObj,&pySubName))
|
||||
return 0;
|
||||
|
||||
PY_TRY {
|
||||
ViewProviderDocumentObject *vpd = 0;
|
||||
App::DocumentObject *obj = 0;
|
||||
if(pyObj!=Py_None) {
|
||||
if(PyObject_TypeCheck(pyObj,&App::DocumentObjectPy::Type))
|
||||
obj = static_cast<App::DocumentObjectPy*>(pyObj)->getDocumentObjectPtr();
|
||||
else if(PyObject_TypeCheck(pyObj,&ViewProviderDocumentObjectPy::Type))
|
||||
vpd = static_cast<ViewProviderDocumentObjectPy*>(pyObj)->getViewProviderDocumentObjectPtr();
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"exepcting a type of DocumentObject or ViewProviderDocumentObject");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Too lazy to parse the argument...
|
||||
App::PropertyStringList prop;
|
||||
if(pySubName!=Py_None)
|
||||
prop.setPyObject(pySubName);
|
||||
|
||||
if(obj)
|
||||
getLinkViewPtr()->setLink(obj,prop.getValue());
|
||||
else
|
||||
getLinkViewPtr()->setLinkViewObject(vpd,prop.getValue());
|
||||
Py_Return;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
Py::Object LinkViewPy::getOwner() const {
|
||||
auto owner = getLinkViewPtr()->getOwner();
|
||||
if(!owner) return Py::Object();
|
||||
return Py::Object(owner->getPyObject(),true);
|
||||
}
|
||||
|
||||
void LinkViewPy::setOwner(Py::Object owner) {
|
||||
ViewProviderDocumentObject *vp = 0;
|
||||
if(!owner.isNone()) {
|
||||
if(!PyObject_TypeCheck(owner.ptr(),&ViewProviderDocumentObjectPy::Type))
|
||||
throw Py::TypeError("exepcting the owner to be of ViewProviderDocumentObject");
|
||||
vp = static_cast<ViewProviderDocumentObjectPy*>(
|
||||
owner.ptr())->getViewProviderDocumentObjectPtr();
|
||||
}
|
||||
getLinkViewPtr()->setOwner(vp);
|
||||
}
|
||||
|
||||
Py::Object LinkViewPy::getLinkedView() const {
|
||||
auto linked = getLinkViewPtr()->getLinkedView();
|
||||
if(!linked)
|
||||
return Py::Object();
|
||||
return Py::Object(linked->getPyObject(),true);
|
||||
}
|
||||
|
||||
Py::Object LinkViewPy::getSubNames() const {
|
||||
const auto &subs = getLinkViewPtr()->getSubNames();
|
||||
if(subs.empty())
|
||||
return Py::Object();
|
||||
Py::Tuple ret(subs.size());
|
||||
int i=0;
|
||||
for(auto &s : subs)
|
||||
ret.setItem(i++,Py::String(s.c_str()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::getElementPicked(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O",&obj))
|
||||
return NULL;
|
||||
void *ptr = 0;
|
||||
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoPickedPoint *", obj, &ptr, 0);
|
||||
SoPickedPoint *pp = reinterpret_cast<SoPickedPoint*>(ptr);
|
||||
if(!pp)
|
||||
throw Py::TypeError("type must be of coin.SoPickedPoint");
|
||||
PY_TRY{
|
||||
std::string name;
|
||||
if(!getLinkViewPtr()->linkGetElementPicked(pp,name))
|
||||
Py_Return;
|
||||
return Py::new_reference_to(Py::String(name));
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::getDetailPath(PyObject* args)
|
||||
{
|
||||
const char *sub;
|
||||
PyObject *path;
|
||||
if (!PyArg_ParseTuple(args, "sO",&sub,&path))
|
||||
return NULL;
|
||||
void *ptr = 0;
|
||||
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoPath *", path, &ptr, 0);
|
||||
SoPath *pPath = reinterpret_cast<SoPath*>(ptr);
|
||||
if(!pPath)
|
||||
throw Py::TypeError("type must be of coin.SoPath");
|
||||
PY_TRY{
|
||||
SoDetail *det = 0;
|
||||
getLinkViewPtr()->linkGetDetailPath(sub,static_cast<SoFullPath*>(pPath),det);
|
||||
if(!det)
|
||||
Py_Return;
|
||||
return Base::Interpreter().createSWIGPointerObj("pivy.coin", "SoDetail *", (void*)det, 0);
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::getBoundBox(PyObject* args) {
|
||||
PyObject *vobj = Py_None;
|
||||
if (!PyArg_ParseTuple(args, "O",&vobj))
|
||||
return 0;
|
||||
ViewProviderDocumentObject *vpd = 0;
|
||||
if(vobj!=Py_None) {
|
||||
if(!PyObject_TypeCheck(vobj,&ViewProviderDocumentObjectPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError, "exepcting a type of ViewProviderDocumentObject");
|
||||
return 0;
|
||||
}
|
||||
vpd = static_cast<ViewProviderDocumentObjectPy*>(vobj)->getViewProviderDocumentObjectPtr();
|
||||
}
|
||||
PY_TRY {
|
||||
auto bbox = getLinkViewPtr()->getBoundBox(vpd);
|
||||
Py::Object ret(new Base::BoundBoxPy(new Base::BoundBox3d(bbox)));
|
||||
return Py::new_reference_to(ret);
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
PyObject *LinkViewPy::getCustomAttributes(const char*) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LinkViewPy::setCustomAttributes(const char*, PyObject*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::Object LinkViewPy::getRootNode(void) const
|
||||
{
|
||||
try {
|
||||
SoNode* node = getLinkViewPtr()->getLinkRoot();
|
||||
PyObject* Ptr = Base::Interpreter().createSWIGPointerObj("pivy.coin","SoSeparator *", node, 1);
|
||||
node->ref();
|
||||
return Py::Object(Ptr, true);
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
throw Py::RuntimeError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
Py::Object LinkViewPy::getVisibilities() const {
|
||||
auto linked = getLinkViewPtr();
|
||||
if(!linked->getSize())
|
||||
return Py::Object();
|
||||
Py::Tuple ret(linked->getSize());
|
||||
for(int i=0;i<linked->getSize();++i)
|
||||
ret.setItem(i,Py::Boolean(linked->isElementVisible(i)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LinkViewPy::setVisibilities(Py::Object value) {
|
||||
App::PropertyBoolList v;
|
||||
if(!value.isNone())
|
||||
v.setPyObject(value.ptr());
|
||||
|
||||
auto linked = getLinkViewPtr();
|
||||
const auto &vis = v.getValue();
|
||||
for(int i=0;i<linked->getSize();++i)
|
||||
linked->setElementVisible(i,i>=(int)vis.size()||vis[i]);
|
||||
}
|
||||
|
||||
PyObject* LinkViewPy::getChildren(PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return 0;
|
||||
auto children = getLinkViewPtr()->getChildren();
|
||||
if(children.empty())
|
||||
Py_Return;
|
||||
Py::Tuple ret(children.size());
|
||||
int i=0;
|
||||
for(auto vp : children)
|
||||
ret.setItem(i++,Py::Object(vp->getPyObject(),true));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
Py::Int LinkViewPy::getCount() const {
|
||||
return Py::Int(getLinkViewPtr()->getSize());
|
||||
}
|
||||
|
||||
void LinkViewPy::setCount(Py::Int count) {
|
||||
try {
|
||||
getLinkViewPtr()->setSize((int)count);
|
||||
} catch (const Base::Exception& e) {
|
||||
throw Py::RuntimeError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ static double degreesToRadains(const double °reesIn)
|
||||
static double lastTranslationIncrement = 1.0;
|
||||
static double lastRotationIncrement = degreesToRadains(15.0);
|
||||
|
||||
TaskCSysDragger::TaskCSysDragger(Gui::ViewProviderDragger* vpObjectIn, Gui::SoFCCSysDragger* draggerIn) :
|
||||
TaskCSysDragger::TaskCSysDragger(Gui::ViewProviderDocumentObject* vpObjectIn, Gui::SoFCCSysDragger* draggerIn) :
|
||||
dragger(draggerIn)
|
||||
{
|
||||
assert(vpObjectIn);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Gui
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TaskCSysDragger(ViewProviderDragger *vpObjectIn, SoFCCSysDragger *draggerIn);
|
||||
TaskCSysDragger(ViewProviderDocumentObject *vpObjectIn, SoFCCSysDragger *draggerIn);
|
||||
virtual ~TaskCSysDragger() override;
|
||||
virtual QDialogButtonBox::StandardButtons getStandardButtons() const override
|
||||
{ return QDialogButtonBox::Ok;}
|
||||
|
||||
533
src/Gui/TaskElementColors.cpp
Normal file
533
src/Gui/TaskElementColors.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2018 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#endif
|
||||
|
||||
#include <QColorDialog>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include "ui_TaskElementColors.h"
|
||||
#include "TaskElementColors.h"
|
||||
#include "ViewProviderLink.h"
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/ComplexGeoData.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Control.h"
|
||||
#include "Document.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Selection.h"
|
||||
#include "BitmapFactory.h"
|
||||
#include "Command.h"
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
|
||||
FC_LOG_LEVEL_INIT("Gui",true,true)
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
class ElementColors::Private: public Gui::SelectionGate
|
||||
{
|
||||
public:
|
||||
typedef boost::signals2::connection Connection;
|
||||
std::unique_ptr<Ui_TaskElementColors> ui;
|
||||
ViewProviderDocumentObject *vp;
|
||||
ViewProviderDocumentObject *vpParent;
|
||||
Document *vpDoc;
|
||||
std::map<std::string,QListWidgetItem*> elements;
|
||||
std::vector<QListWidgetItem*> items;
|
||||
std::string hiddenSub;
|
||||
Connection connectDelDoc;
|
||||
Connection connectDelObj;
|
||||
QPixmap px;
|
||||
bool busy;
|
||||
long onTopMode;
|
||||
bool touched;
|
||||
|
||||
std::string editDoc;
|
||||
std::string editObj;
|
||||
std::string editSub;
|
||||
std::string editElement;
|
||||
|
||||
Private(ViewProviderDocumentObject* vp, const char *element="")
|
||||
: ui(new Ui_TaskElementColors()), vp(vp),editElement(element)
|
||||
{
|
||||
vpDoc = vp->getDocument();
|
||||
vpParent = vp;
|
||||
auto doc = Application::Instance->editDocument();
|
||||
if(doc) {
|
||||
auto editVp = doc->getInEdit(&vpParent,&editSub);
|
||||
if(editVp == vp) {
|
||||
auto obj = vpParent->getObject();
|
||||
editDoc = obj->getDocument()->getName();
|
||||
editObj = obj->getNameInDocument();
|
||||
editSub = Data::ComplexGeoData::noElementName(editSub.c_str());
|
||||
}
|
||||
}
|
||||
if(editDoc.empty()) {
|
||||
vpParent = vp;
|
||||
editDoc = vp->getObject()->getDocument()->getName();
|
||||
editObj = vp->getObject()->getNameInDocument();
|
||||
editSub.clear();
|
||||
}
|
||||
onTopMode = vpParent->OnTopWhenSelected.getValue();
|
||||
busy = false;
|
||||
touched = false;
|
||||
int w = QApplication::style()->standardPixmap(QStyle::SP_DirClosedIcon).width();
|
||||
px = QPixmap(w,w);
|
||||
}
|
||||
|
||||
~Private() {
|
||||
vpParent->OnTopWhenSelected.setValue(onTopMode);
|
||||
}
|
||||
|
||||
bool allow(App::Document *doc, App::DocumentObject *obj, const char *subname) {
|
||||
if(editDoc!=doc->getName() ||
|
||||
editObj!=obj->getNameInDocument() ||
|
||||
!boost::starts_with(subname,editSub))
|
||||
return false;
|
||||
if(editElement.empty())
|
||||
return true;
|
||||
const char *dot = strrchr(subname,'.');
|
||||
if(!dot)
|
||||
dot = subname;
|
||||
else
|
||||
++dot;
|
||||
return *dot==0 || boost::starts_with(dot,editElement);
|
||||
}
|
||||
|
||||
void populate() {
|
||||
int i=0;
|
||||
for(auto &v : vp->getElementColors())
|
||||
addItem(i++,v.first.c_str());
|
||||
apply();
|
||||
}
|
||||
|
||||
void addItem(int i,const char *sub, bool push=false) {
|
||||
auto itE = elements.find(sub);
|
||||
if(i<0 && itE!=elements.end()) {
|
||||
if(push && !ViewProvider::hasHiddenMarker(sub))
|
||||
items.push_back(itE->second);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *marker = ViewProvider::hasHiddenMarker(sub);
|
||||
if(marker) {
|
||||
auto icon = BitmapFactory().pixmap("Invisible");
|
||||
QListWidgetItem* item = new QListWidgetItem(icon,
|
||||
QString::fromLatin1(std::string(sub,marker-sub).c_str()), ui->elementList);
|
||||
item->setData(Qt::UserRole,QColor());
|
||||
item->setData(Qt::UserRole+1,QString::fromLatin1(sub));
|
||||
elements.emplace(sub,item);
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &v : vp->getElementColors(sub)) {
|
||||
auto it = elements.find(v.first.c_str());
|
||||
if(it!=elements.end()) {
|
||||
if(push)
|
||||
items.push_back(it->second);
|
||||
continue;
|
||||
}
|
||||
auto color = v.second;
|
||||
QColor c;
|
||||
c.setRgbF(color.r,color.g,color.b,1.0-color.a);
|
||||
px.fill(c);
|
||||
QListWidgetItem* item = new QListWidgetItem(QIcon(px),
|
||||
QString::fromLatin1(Data::ComplexGeoData::oldElementName(v.first.c_str()).c_str()),
|
||||
ui->elementList);
|
||||
item->setData(Qt::UserRole,c);
|
||||
item->setData(Qt::UserRole+1,QString::fromLatin1(v.first.c_str()));
|
||||
if(push)
|
||||
items.push_back(item);
|
||||
elements.emplace(v.first,item);
|
||||
}
|
||||
}
|
||||
|
||||
void apply() {
|
||||
std::map<std::string,App::Color> info;
|
||||
int count = ui->elementList->count();
|
||||
for(int i=0;i<count;++i) {
|
||||
auto item = ui->elementList->item(i);
|
||||
auto color = item->data(Qt::UserRole).value<QColor>();
|
||||
std::string sub = qPrintable(item->data(Qt::UserRole+1).value<QString>());
|
||||
info.emplace(qPrintable(item->data(Qt::UserRole+1).value<QString>()),
|
||||
App::Color(color.redF(),color.greenF(),color.blueF(),1.0-color.alphaF()));
|
||||
}
|
||||
if(!App::GetApplication().getActiveTransaction())
|
||||
App::GetApplication().setActiveTransaction("Set colors");
|
||||
vp->setElementColors(info);
|
||||
touched = true;
|
||||
Selection().clearSelection();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
touched = false;
|
||||
App::GetApplication().closeActiveTransaction(true);
|
||||
Selection().clearSelection();
|
||||
}
|
||||
|
||||
void accept() {
|
||||
if(touched && ui->recompute->isChecked()) {
|
||||
auto obj = vp->getObject();
|
||||
obj->touch();
|
||||
obj->getDocument()->recompute(obj->getInListRecursive());
|
||||
touched = false;
|
||||
}
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
if(elements.size()) {
|
||||
hiddenSub.clear();
|
||||
ui->elementList->clear();
|
||||
elements.clear();
|
||||
apply();
|
||||
}
|
||||
}
|
||||
|
||||
void removeItems() {
|
||||
for(auto item : ui->elementList->selectedItems()) {
|
||||
std::string sub = qPrintable(item->data(Qt::UserRole+1).value<QString>());
|
||||
if(sub == hiddenSub)
|
||||
hiddenSub.clear();
|
||||
elements.erase(sub);
|
||||
delete item;
|
||||
}
|
||||
apply();
|
||||
}
|
||||
|
||||
void editItem(QWidget *parent, QListWidgetItem *item) {
|
||||
std::string sub = qPrintable(item->data(Qt::UserRole+1).value<QString>());
|
||||
if(ViewProvider::hasHiddenMarker(sub.c_str()))
|
||||
return;
|
||||
auto color = item->data(Qt::UserRole).value<QColor>();
|
||||
QColorDialog cd(color, parent);
|
||||
cd.setOption(QColorDialog::ShowAlphaChannel);
|
||||
if (cd.exec()!=QDialog::Accepted || color==cd.selectedColor())
|
||||
return;
|
||||
color = cd.selectedColor();
|
||||
item->setData(Qt::UserRole,color);
|
||||
px.fill(color);
|
||||
item->setIcon(QIcon(px));
|
||||
apply();
|
||||
}
|
||||
|
||||
void onSelectionChanged(const SelectionChanges &msg) {
|
||||
// no object selected in the combobox or no sub-element was selected
|
||||
if (busy)
|
||||
return;
|
||||
busy = true;
|
||||
switch(msg.Type) {
|
||||
case SelectionChanges::ClrSelection:
|
||||
ui->elementList->clearSelection();
|
||||
break;
|
||||
case SelectionChanges::AddSelection:
|
||||
case SelectionChanges::RmvSelection:
|
||||
if(msg.pDocName && msg.pObjectName && msg.pSubName && msg.pSubName[0]) {
|
||||
if(editDoc == msg.pDocName &&
|
||||
editObj == msg.pObjectName &&
|
||||
boost::starts_with(msg.pSubName,editSub))
|
||||
{
|
||||
for(auto item : ui->elementList->findItems(
|
||||
QString::fromLatin1(msg.pSubName-editSub.size()),0))
|
||||
item->setSelected(msg.Type==SelectionChanges::AddSelection);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
busy = false;
|
||||
}
|
||||
|
||||
void onSelectionChanged() {
|
||||
if(busy) return;
|
||||
busy = true;
|
||||
std::map<std::string,int> sels;
|
||||
for(auto &sel : Selection().getSelectionEx(
|
||||
editDoc.c_str(),App::DocumentObject::getClassTypeId(),0))
|
||||
{
|
||||
if(sel.getFeatName()!=editObj) continue;
|
||||
for(auto &sub : sel.getSubNames()) {
|
||||
if(boost::starts_with(sub,editSub))
|
||||
sels[sub.c_str()+editSub.size()] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for(auto item : ui->elementList->selectedItems()) {
|
||||
std::string name(qPrintable(item->data(Qt::UserRole+1).value<QString>()));
|
||||
if(ViewProvider::hasHiddenMarker(name.c_str()))
|
||||
continue;
|
||||
auto &v = sels[name];
|
||||
if(!v)
|
||||
Selection().addSelection(editDoc.c_str(),
|
||||
editObj.c_str(), (editSub+name).c_str());
|
||||
v = 2;
|
||||
}
|
||||
for(auto &v : sels) {
|
||||
if(v.second!=2) {
|
||||
Selection().rmvSelection(editDoc.c_str(),
|
||||
editObj.c_str(), (editSub+v.first).c_str());
|
||||
}
|
||||
}
|
||||
busy = false;
|
||||
}
|
||||
};
|
||||
|
||||
/* TRANSLATOR Gui::TaskElementColors */
|
||||
|
||||
ElementColors::ElementColors(ViewProviderDocumentObject* vp, bool noHide)
|
||||
:d(new Private(vp))
|
||||
{
|
||||
d->ui->setupUi(this);
|
||||
d->ui->objectLabel->setText(QString::fromUtf8(vp->getObject()->Label.getValue()));
|
||||
d->ui->elementList->setMouseTracking(true); // needed for itemEntered() to work
|
||||
|
||||
if(noHide)
|
||||
d->ui->hideSelection->setVisible(false);
|
||||
|
||||
ParameterGrp::handle hPart = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/View");
|
||||
d->ui->recompute->setChecked(hPart->GetBool("ColorRecompute",true));
|
||||
d->ui->onTop->setChecked(hPart->GetBool("ColorOnTop",true));
|
||||
if(d->ui->onTop->isChecked())
|
||||
d->vpParent->OnTopWhenSelected.setValue(3);
|
||||
|
||||
Selection().addSelectionGate(d,0);
|
||||
|
||||
d->connectDelDoc = Application::Instance->signalDeleteDocument.connect(boost::bind
|
||||
(&ElementColors::slotDeleteDocument, this, _1));
|
||||
d->connectDelObj = Application::Instance->signalDeletedObject.connect(boost::bind
|
||||
(&ElementColors::slotDeleteObject, this, _1));
|
||||
|
||||
d->populate();
|
||||
}
|
||||
|
||||
ElementColors::~ElementColors()
|
||||
{
|
||||
d->connectDelDoc.disconnect();
|
||||
d->connectDelObj.disconnect();
|
||||
Selection().rmvSelectionGate();
|
||||
}
|
||||
|
||||
void ElementColors::on_recompute_clicked(bool checked) {
|
||||
ParameterGrp::handle hPart = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/View");
|
||||
hPart->SetBool("ColorRecompute",checked);
|
||||
}
|
||||
|
||||
void ElementColors::on_onTop_clicked(bool checked) {
|
||||
ParameterGrp::handle hPart = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/View");
|
||||
hPart->SetBool("ColorOnTop",checked);
|
||||
d->vpParent->OnTopWhenSelected.setValue(checked?3:d->onTopMode);
|
||||
}
|
||||
|
||||
void ElementColors::slotDeleteDocument(const Document& Doc)
|
||||
{
|
||||
if (d->vpDoc==&Doc || d->editDoc==Doc.getDocument()->getName())
|
||||
Control().closeDialog();
|
||||
}
|
||||
|
||||
void ElementColors::slotDeleteObject(const ViewProvider& obj)
|
||||
{
|
||||
if (d->vp==&obj)
|
||||
Control().closeDialog();
|
||||
}
|
||||
|
||||
void ElementColors::on_removeSelection_clicked()
|
||||
{
|
||||
d->removeItems();
|
||||
}
|
||||
|
||||
void ElementColors::on_boxSelect_clicked()
|
||||
{
|
||||
auto cmd = Application::Instance->commandManager().getCommandByName("Std_BoxElementSelection");
|
||||
if(cmd)
|
||||
cmd->invoke(0);
|
||||
}
|
||||
|
||||
void ElementColors::on_hideSelection_clicked() {
|
||||
auto sels = Selection().getSelectionEx(d->editDoc.c_str(),App::DocumentObject::getClassTypeId(),0);
|
||||
for(auto &sel : sels) {
|
||||
if(d->editObj!=sel.getFeatName())
|
||||
continue;
|
||||
const auto &subs = sel.getSubNames();
|
||||
if(subs.size()) {
|
||||
for(auto &sub : subs) {
|
||||
if(boost::starts_with(sub,d->editSub)) {
|
||||
auto name = Data::ComplexGeoData::noElementName(sub.c_str()+d->editSub.size());
|
||||
name += ViewProvider::hiddenMarker();
|
||||
d->addItem(-1,name.c_str());
|
||||
}
|
||||
}
|
||||
d->apply();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ElementColors::on_addSelection_clicked()
|
||||
{
|
||||
auto sels = Selection().getSelectionEx(d->editDoc.c_str(),App::DocumentObject::getClassTypeId(),0);
|
||||
d->items.clear();
|
||||
if(sels.empty())
|
||||
d->addItem(-1,"Face",true);
|
||||
else {
|
||||
for(auto &sel : sels) {
|
||||
if(d->editObj!=sel.getFeatName())
|
||||
continue;
|
||||
const auto &subs = sel.getSubNames();
|
||||
if(subs.empty()) {
|
||||
d->addItem(-1,"Face",true);
|
||||
break;
|
||||
}
|
||||
for(auto &sub : subs) {
|
||||
if(boost::starts_with(sub,d->editSub))
|
||||
d->addItem(-1,sub.c_str()+d->editSub.size(),true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(d->items.size()) {
|
||||
auto color = d->items.front()->data(Qt::UserRole).value<QColor>();
|
||||
QColorDialog cd(color, this);
|
||||
cd.setOption(QColorDialog::ShowAlphaChannel);
|
||||
if (cd.exec()!=QDialog::Accepted)
|
||||
return;
|
||||
color = cd.selectedColor();
|
||||
for(auto item : d->items) {
|
||||
item->setData(Qt::UserRole,color);
|
||||
d->px.fill(color);
|
||||
item->setIcon(QIcon(d->px));
|
||||
}
|
||||
d->apply();
|
||||
}
|
||||
}
|
||||
|
||||
void ElementColors::on_removeAll_clicked()
|
||||
{
|
||||
d->removeAll();
|
||||
}
|
||||
|
||||
bool ElementColors::accept()
|
||||
{
|
||||
d->accept();
|
||||
Application::Instance->setEditDocument(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElementColors::reject()
|
||||
{
|
||||
d->reset();
|
||||
Application::Instance->setEditDocument(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ElementColors::changeEvent(QEvent *e)
|
||||
{
|
||||
QWidget::changeEvent(e);
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
d->ui->retranslateUi(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ElementColors::leaveEvent(QEvent *e) {
|
||||
QWidget::leaveEvent(e);
|
||||
Selection().rmvPreselect();
|
||||
if(d->hiddenSub.size()) {
|
||||
d->vp->partialRender({d->hiddenSub},false);
|
||||
d->hiddenSub.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ElementColors::on_elementList_itemEntered(QListWidgetItem *item) {
|
||||
std::string name(qPrintable(item->data(Qt::UserRole+1).value<QString>()));
|
||||
if(d->hiddenSub.size()) {
|
||||
d->vp->partialRender({d->hiddenSub},false);
|
||||
d->hiddenSub.clear();
|
||||
}
|
||||
if(ViewProvider::hasHiddenMarker(name.c_str())) {
|
||||
d->hiddenSub = name;
|
||||
d->vp->partialRender({name},true);
|
||||
name.resize(name.size()-ViewProvider::hiddenMarker().size());
|
||||
}
|
||||
Selection().setPreselect(d->editDoc.c_str(),
|
||||
d->editObj.c_str(), (d->editSub+name).c_str(),0,0,0,
|
||||
d->ui->onTop->isChecked()?2:1);
|
||||
}
|
||||
|
||||
void ElementColors::on_elementList_itemSelectionChanged() {
|
||||
d->onSelectionChanged();
|
||||
}
|
||||
|
||||
void ElementColors::onSelectionChanged(const SelectionChanges& msg)
|
||||
{
|
||||
d->onSelectionChanged(msg);
|
||||
}
|
||||
|
||||
void ElementColors::on_elementList_itemDoubleClicked(QListWidgetItem *item) {
|
||||
d->editItem(this,item);
|
||||
}
|
||||
|
||||
/* TRANSLATOR Gui::TaskElementColors */
|
||||
|
||||
TaskElementColors::TaskElementColors(ViewProviderDocumentObject* vp, bool noHide)
|
||||
{
|
||||
widget = new ElementColors(vp,noHide);
|
||||
taskbox = new TaskView::TaskBox(
|
||||
QPixmap(), widget->windowTitle(), true, 0);
|
||||
taskbox->groupLayout()->addWidget(widget);
|
||||
Content.push_back(taskbox);
|
||||
}
|
||||
|
||||
TaskElementColors::~TaskElementColors()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskElementColors::open()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskElementColors::clicked(int)
|
||||
{
|
||||
}
|
||||
|
||||
bool TaskElementColors::accept()
|
||||
{
|
||||
return widget->accept();
|
||||
}
|
||||
|
||||
bool TaskElementColors::reject()
|
||||
{
|
||||
return widget->reject();
|
||||
}
|
||||
|
||||
#include "moc_TaskElementColors.cpp"
|
||||
93
src/Gui/TaskElementColors.h
Normal file
93
src/Gui/TaskElementColors.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2018 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef GUI_TASKELEMENTCOLORS_H
|
||||
#define GUI_TASKELEMENTCOLORS_H
|
||||
|
||||
#include <QListWidgetItem>
|
||||
#include "TaskView/TaskView.h"
|
||||
#include "TaskView/TaskDialog.h"
|
||||
|
||||
namespace Gui {
|
||||
class Document;
|
||||
class ViewProvider;
|
||||
class ViewProviderDocumentObject;
|
||||
|
||||
class GuiExport ElementColors : public QWidget, public SelectionObserver
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ElementColors(ViewProviderDocumentObject* vp, bool noHide=false);
|
||||
~ElementColors();
|
||||
|
||||
bool accept();
|
||||
bool reject();
|
||||
|
||||
private Q_SLOTS:
|
||||
void on_removeSelection_clicked();
|
||||
void on_addSelection_clicked();
|
||||
void on_removeAll_clicked();
|
||||
void on_elementList_itemDoubleClicked(QListWidgetItem *item);
|
||||
void on_elementList_itemSelectionChanged();
|
||||
void on_elementList_itemEntered(QListWidgetItem *item);
|
||||
void on_recompute_clicked(bool checked);
|
||||
void on_onTop_clicked(bool checked);
|
||||
void on_hideSelection_clicked();
|
||||
void on_boxSelect_clicked();
|
||||
|
||||
protected:
|
||||
void onSelectionChanged(const SelectionChanges& msg);
|
||||
void changeEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *);
|
||||
void slotDeleteDocument(const Document&);
|
||||
void slotDeleteObject(const ViewProvider&);
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
class GuiExport TaskElementColors : public TaskView::TaskDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskElementColors(ViewProviderDocumentObject* vp, bool noHide=false);
|
||||
~TaskElementColors();
|
||||
|
||||
public:
|
||||
void open();
|
||||
bool accept();
|
||||
bool reject();
|
||||
void clicked(int);
|
||||
|
||||
QDialogButtonBox::StandardButtons getStandardButtons() const
|
||||
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
|
||||
|
||||
private:
|
||||
ElementColors* widget;
|
||||
TaskView::TaskBox* taskbox;
|
||||
};
|
||||
|
||||
} //namespace Gui
|
||||
|
||||
#endif // GUI_TASKELEMENTCOLORS_H
|
||||
92
src/Gui/TaskElementColors.ui
Normal file
92
src/Gui/TaskElementColors.ui
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Gui::TaskElementColors</class>
|
||||
<widget class="QWidget" name="Gui::TaskElementColors">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>483</width>
|
||||
<height>406</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Set element color</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="objectLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="elementList">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="recompute">
|
||||
<property name="text">
|
||||
<string>Recompute after commit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="removeSelection">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="addSelection">
|
||||
<property name="text">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="removeAll">
|
||||
<property name="text">
|
||||
<string>Remove all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="hideSelection">
|
||||
<property name="text">
|
||||
<string>Hide</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="boxSelect">
|
||||
<property name="text">
|
||||
<string>Box select</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="onTop">
|
||||
<property name="text">
|
||||
<string>On-top when selected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
2976
src/Gui/ViewProviderLink.cpp
Normal file
2976
src/Gui/ViewProviderLink.cpp
Normal file
File diff suppressed because it is too large
Load Diff
339
src/Gui/ViewProviderLink.h
Normal file
339
src/Gui/ViewProviderLink.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef GUI_VIEWPROVIDER_LINK_H
|
||||
#define GUI_VIEWPROVIDER_LINK_H
|
||||
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/Link.h>
|
||||
#include "SoFCUnifiedSelection.h"
|
||||
#include "ViewProviderPythonFeature.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "ViewProviderExtension.h"
|
||||
|
||||
class SoBase;
|
||||
class SoDragger;
|
||||
class SoMaterialBinding;
|
||||
|
||||
namespace Gui {
|
||||
|
||||
class LinkInfo;
|
||||
typedef boost::intrusive_ptr<LinkInfo> LinkInfoPtr;
|
||||
|
||||
class GuiExport ViewProviderLinkObserver: public ViewProviderExtension {
|
||||
EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
public:
|
||||
ViewProviderLinkObserver();
|
||||
virtual ~ViewProviderLinkObserver();
|
||||
void extensionReattach(App::DocumentObject *) override;
|
||||
void extensionBeforeDelete() override;
|
||||
void extensionOnChanged(const App::Property *) override;
|
||||
void extensionUpdateData(const App::Property*) override;
|
||||
void extensionFinishRestoring() override;
|
||||
bool extensionCanDragObject(App::DocumentObject*) const override { return false; }
|
||||
bool extensionCanDropObject(App::DocumentObject*) const override { return false; }
|
||||
void extensionModeSwitchChange(void) override;
|
||||
|
||||
bool isLinkVisible() const;
|
||||
void setLinkVisible(bool);
|
||||
|
||||
LinkInfoPtr linkInfo;
|
||||
};
|
||||
|
||||
class GuiExport LinkOwner {
|
||||
public:
|
||||
virtual void unlink(LinkInfoPtr) {}
|
||||
virtual void onLinkedIconChange(LinkInfoPtr) {}
|
||||
virtual void onLinkedUpdateData(LinkInfoPtr,const App::Property *) {}
|
||||
protected:
|
||||
virtual ~LinkOwner() {}
|
||||
};
|
||||
|
||||
class GuiExport LinkView : public Base::BaseClass, public LinkOwner {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
|
||||
LinkView();
|
||||
~LinkView();
|
||||
LinkView &operator=(const LinkView&) = delete;
|
||||
LinkView(const LinkView&) = delete;
|
||||
|
||||
virtual PyObject *getPyObject(void);
|
||||
|
||||
virtual void unlink(LinkInfoPtr) override;
|
||||
virtual void onLinkedIconChange(LinkInfoPtr) override;
|
||||
virtual void onLinkedUpdateData(LinkInfoPtr, const App::Property *) override;
|
||||
|
||||
bool isLinked() const;
|
||||
|
||||
SoFCSelectionRoot *getLinkRoot() const {return pcLinkRoot;}
|
||||
|
||||
QIcon getLinkedIcon(QPixmap overlay) const;
|
||||
|
||||
void updateLink();
|
||||
|
||||
void setLink(App::DocumentObject *obj,
|
||||
const std::vector<std::string> &subs = std::vector<std::string>());
|
||||
|
||||
void setLinkViewObject(ViewProviderDocumentObject *vpd,
|
||||
const std::vector<std::string> &subs = std::vector<std::string>());
|
||||
|
||||
std::vector<ViewProviderDocumentObject*> getChildren() const;
|
||||
|
||||
void setMaterial(int index, const App::Material *material);
|
||||
void setDrawStyle(int linePattern, double lineWidth=0, double pointSize=0);
|
||||
void setTransform(int index, const Base::Matrix4D &mat);
|
||||
void renderDoubleSide(bool);
|
||||
void setSize(int size);
|
||||
|
||||
int getSize() const { return nodeArray.size(); }
|
||||
|
||||
static void setTransform(SoTransform *pcTransform, const Base::Matrix4D &mat);
|
||||
|
||||
enum SnapshotType {
|
||||
//three type of snapshot to override linked root node:
|
||||
|
||||
//override transform and visibility
|
||||
SnapshotTransform = 0,
|
||||
//override visibility
|
||||
SnapshotVisible = 1,
|
||||
//override none (for child objects of a container)
|
||||
SnapshotChild = 2,
|
||||
|
||||
SnapshotMax,
|
||||
|
||||
//special type for sub object linking
|
||||
SnapshotContainer = -1,
|
||||
// sub object linking with transform override
|
||||
SnapshotContainerTransform = -2,
|
||||
};
|
||||
void setNodeType(SnapshotType type, bool sublink=true);
|
||||
|
||||
void setChildren(const std::vector<App::DocumentObject*> &children,
|
||||
const boost::dynamic_bitset<> &vis, SnapshotType type=SnapshotVisible);
|
||||
|
||||
bool linkGetDetailPath(const char *, SoFullPath *, SoDetail *&) const;
|
||||
bool linkGetElementPicked(const SoPickedPoint *, std::string &) const;
|
||||
|
||||
void setElementVisible(int index, bool visible);
|
||||
bool isElementVisible(int index) const;
|
||||
|
||||
ViewProviderDocumentObject *getOwner() const;
|
||||
void setOwner(ViewProviderDocumentObject *vpd);
|
||||
|
||||
bool hasSubs() const;
|
||||
|
||||
std::vector<std::string> getSubNames() const;
|
||||
ViewProviderDocumentObject *getLinkedView() const;
|
||||
|
||||
Base::BoundBox3d getBoundBox(ViewProviderDocumentObject *vpd=0) const;
|
||||
|
||||
void setInvalid();
|
||||
|
||||
protected:
|
||||
void replaceLinkedRoot(SoSeparator *);
|
||||
void resetRoot();
|
||||
bool getGroupHierarchy(int index, SoFullPath *path) const;
|
||||
|
||||
protected:
|
||||
LinkInfoPtr linkOwner;
|
||||
LinkInfoPtr linkInfo;
|
||||
CoinPtr<SoFCSelectionRoot> pcLinkRoot;
|
||||
CoinPtr<SoTransform> pcTransform;
|
||||
CoinPtr<SoSeparator> pcLinkedRoot;
|
||||
CoinPtr<SoDrawStyle> pcDrawStyle; // for override line width and point size
|
||||
CoinPtr<SoShapeHints> pcShapeHints; // for override double side rendering for mirror
|
||||
SnapshotType nodeType;
|
||||
SnapshotType childType;
|
||||
bool autoSubLink; //auto delegate to linked sub object if there is only one sub object
|
||||
|
||||
class SubInfo;
|
||||
friend class SubInfo;
|
||||
std::map<std::string, std::unique_ptr<SubInfo> > subInfo;
|
||||
|
||||
class Element;
|
||||
std::vector<std::unique_ptr<Element> > nodeArray;
|
||||
std::unordered_map<SoNode*,int> nodeMap;
|
||||
|
||||
Py::Object PythonObject;
|
||||
};
|
||||
|
||||
class GuiExport ViewProviderLink : public ViewProviderDocumentObject
|
||||
{
|
||||
PROPERTY_HEADER(Gui::ViewProviderLink);
|
||||
typedef ViewProviderDocumentObject inherited;
|
||||
|
||||
public:
|
||||
App::PropertyBool OverrideMaterial;
|
||||
App::PropertyMaterial ShapeMaterial;
|
||||
App::PropertyEnumeration DrawStyle;
|
||||
App::PropertyFloatConstraint LineWidth;
|
||||
App::PropertyFloatConstraint PointSize;
|
||||
App::PropertyMaterialList MaterialList;
|
||||
App::PropertyBoolList OverrideMaterialList;
|
||||
App::PropertyBool Selectable;
|
||||
App::PropertyColorList OverrideColorList;
|
||||
App::PropertyPersistentObject ChildViewProvider;
|
||||
|
||||
ViewProviderLink();
|
||||
virtual ~ViewProviderLink();
|
||||
|
||||
void attach(App::DocumentObject *pcObj) override;
|
||||
void reattach(App::DocumentObject *pcObj) override;
|
||||
|
||||
bool isSelectable(void) const override;
|
||||
|
||||
bool useNewSelectionModel(void) const override {return true;}
|
||||
|
||||
void updateData(const App::Property*) override;
|
||||
void onChanged(const App::Property* prop) override;
|
||||
std::vector<App::DocumentObject*> claimChildren(void) const override;
|
||||
bool getElementPicked(const SoPickedPoint *, std::string &) const override;
|
||||
bool getDetailPath(const char *, SoFullPath *, bool, SoDetail *&) const override;
|
||||
|
||||
void finishRestoring() override;
|
||||
|
||||
QIcon getIcon(void) const override;
|
||||
|
||||
bool canDragObjects() const override;
|
||||
bool canDragObject(App::DocumentObject*) const override;
|
||||
void dragObject(App::DocumentObject*) override;
|
||||
bool canDropObjects() const override;
|
||||
bool canDragAndDropObject(App::DocumentObject*) const override;
|
||||
bool canDropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner,
|
||||
const char *subname, const std::vector<std::string> &elements) const override;
|
||||
std::string dropObjectEx(App::DocumentObject*, App::DocumentObject*,
|
||||
const char *subname, const std::vector<std::string> &elements) override;
|
||||
|
||||
bool onDelete(const std::vector<std::string> &) override;
|
||||
bool canDelete(App::DocumentObject* obj) const override;
|
||||
|
||||
std::vector<std::string> getDisplayModes(void) const override;
|
||||
|
||||
void setupContextMenu(QMenu*, QObject*, const char*) override;
|
||||
|
||||
virtual QPixmap getOverlayPixmap() const;
|
||||
|
||||
ViewProvider *startEditing(int ModNum) override;
|
||||
bool doubleClicked() override;
|
||||
|
||||
PyObject *getPyObject() override;
|
||||
PyObject *getPyLinkView();
|
||||
|
||||
static void updateLinks(ViewProvider *vp);
|
||||
|
||||
void updateDraggingPlacement(const Base::Placement &pla, bool force=false);
|
||||
Base::Placement currentDraggingPlacement() const;
|
||||
void enableCenterballDragger(bool enable);
|
||||
bool isUsingCenterballDragger() const { return useCenterballDragger; }
|
||||
|
||||
std::map<std::string, App::Color> getElementColors(const char *subname=0) const override;
|
||||
void setElementColors(const std::map<std::string, App::Color> &colors) override;
|
||||
|
||||
void setOverrideMode(const std::string &mode) override;
|
||||
|
||||
virtual void onBeforeChange(const App::Property*) override;
|
||||
ViewProviderDocumentObject *getChildViewProvider() const {
|
||||
return childVp;
|
||||
}
|
||||
|
||||
virtual App::Property *getPropertyByName(const char* name) const override;
|
||||
virtual void getPropertyMap(std::map<std::string,App::Property*> &Map) const override;
|
||||
virtual void getPropertyList(std::vector<App::Property*> &List) const override;
|
||||
|
||||
virtual ViewProviderDocumentObject *getLinkedViewProvider(
|
||||
std::string *subname=0, bool recursive=false) const override;
|
||||
|
||||
protected:
|
||||
bool setEdit(int ModNum) override;
|
||||
void setEditViewer(View3DInventorViewer*, int ModNum) override;
|
||||
void unsetEditViewer(View3DInventorViewer*) override;
|
||||
bool linkEdit(const App::LinkBaseExtension *ext=0) const;
|
||||
|
||||
enum LinkType {
|
||||
LinkTypeNone,
|
||||
LinkTypeNormal,
|
||||
LinkTypeSubs,
|
||||
};
|
||||
|
||||
bool hasElements(const App::LinkBaseExtension *ext = 0) const;
|
||||
bool isGroup(const App::LinkBaseExtension *ext=0, bool plainGroup=false) const;
|
||||
const App::LinkBaseExtension *getLinkExtension() const;
|
||||
App::LinkBaseExtension *getLinkExtension();
|
||||
|
||||
void updateDataPrivate(App::LinkBaseExtension *ext, const App::Property*);
|
||||
void updateElementList(App::LinkBaseExtension *ext);
|
||||
|
||||
bool setLinkType(App::LinkBaseExtension *ext);
|
||||
|
||||
void onChangeIcon() const;
|
||||
std::vector<App::DocumentObject*> claimChildrenPrivate() const;
|
||||
|
||||
void applyMaterial();
|
||||
void applyColors();
|
||||
|
||||
void checkIcon(const App::LinkBaseExtension *ext=0);
|
||||
|
||||
ViewProvider *getLinkedView(bool real,const App::LinkBaseExtension *ext=0) const;
|
||||
|
||||
bool initDraggingPlacement();
|
||||
bool callDraggerProxy(const char *fname, bool update);
|
||||
|
||||
private:
|
||||
static void dragStartCallback(void * data, SoDragger * d);
|
||||
static void dragFinishCallback(void * data, SoDragger * d);
|
||||
static void dragMotionCallback(void * data, SoDragger * d);
|
||||
|
||||
protected:
|
||||
LinkView *linkView;
|
||||
LinkType linkType;
|
||||
bool hasSubName;
|
||||
bool hasSubElement;
|
||||
bool useCenterballDragger;
|
||||
|
||||
struct DraggerContext{
|
||||
Base::Matrix4D preTransform;
|
||||
Base::Placement initialPlacement;
|
||||
Base::Matrix4D mat;
|
||||
Base::BoundBox3d bbox;
|
||||
bool cmdPending;
|
||||
};
|
||||
std::unique_ptr<DraggerContext> dragCtx;
|
||||
CoinPtr<SoDragger> pcDragger;
|
||||
ViewProviderDocumentObject *childVp;
|
||||
LinkInfoPtr childVpLink;
|
||||
mutable qint64 overlayCacheKey;
|
||||
};
|
||||
|
||||
typedef ViewProviderPythonFeatureT<ViewProviderLink> ViewProviderLinkPython;
|
||||
|
||||
} //namespace Gui
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// forward decleration to please VC 2013
|
||||
void intrusive_ptr_add_ref(Gui::LinkInfo *px);
|
||||
void intrusive_ptr_release(Gui::LinkInfo *px);
|
||||
#endif
|
||||
|
||||
#endif // GUI_VIEWPROVIDER_LINK_H
|
||||
35
src/Gui/ViewProviderLinkPy.xml
Normal file
35
src/Gui/ViewProviderLinkPy.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="ViewProviderDocumentObjectPy"
|
||||
Name="ViewProviderLinkPy"
|
||||
Twin="ViewProviderLink"
|
||||
TwinPointer="ViewProviderLink"
|
||||
Include="Gui/ViewProviderLink.h"
|
||||
Namespace="Gui"
|
||||
FatherInclude="Gui/ViewProviderDocumentObjectPy.h"
|
||||
FatherNamespace="Gui">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>This is the ViewProviderLink class</UserDocu>
|
||||
</Documentation>
|
||||
<Attribute Name="DraggingPlacement">
|
||||
<Documentation>
|
||||
<UserDocu>Get/set dragger placement during dragging</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="DraggingPlacement" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="UseCenterballDragger">
|
||||
<Documentation>
|
||||
<UserDocu>Get/set dragger type</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="UseCenterballDragger" Type="Boolean" />
|
||||
</Attribute>
|
||||
<Attribute Name="LinkView" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the associated LinkView object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LinkView" Type="Object" />
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
83
src/Gui/ViewProviderLinkPyImp.cpp
Normal file
83
src/Gui/ViewProviderLinkPyImp.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#endif
|
||||
|
||||
#include "Gui/ViewProviderLink.h"
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/PlacementPy.h>
|
||||
// inclusion of the generated files (generated out of ViewProviderLinkPy.xml)
|
||||
#include "ViewProviderLinkPy.h"
|
||||
#include "ViewProviderLinkPy.cpp"
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string ViewProviderLinkPy::representation(void) const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<ViewProviderLink at " << getViewProviderLinkPtr() << ">";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
Py::Object ViewProviderLinkPy::getDraggingPlacement() const {
|
||||
return Py::Object(new Base::PlacementPy(new Base::Placement(
|
||||
getViewProviderLinkPtr()->currentDraggingPlacement())));
|
||||
}
|
||||
|
||||
void ViewProviderLinkPy::setDraggingPlacement(Py::Object arg) {
|
||||
if(!PyObject_TypeCheck(arg.ptr(),&Base::PlacementPy::Type))
|
||||
throw Py::TypeError("expects a placement");
|
||||
getViewProviderLinkPtr()->updateDraggingPlacement(
|
||||
*static_cast<Base::PlacementPy*>(arg.ptr())->getPlacementPtr());
|
||||
}
|
||||
|
||||
Py::Boolean ViewProviderLinkPy::getUseCenterballDragger() const {
|
||||
return Py::Boolean(getViewProviderLinkPtr()->isUsingCenterballDragger());
|
||||
}
|
||||
|
||||
void ViewProviderLinkPy::setUseCenterballDragger(Py::Boolean arg) {
|
||||
try {
|
||||
getViewProviderLinkPtr()->enableCenterballDragger(arg);
|
||||
}catch(const Base::Exception &e){
|
||||
throw Py::Exception(Base::BaseExceptionFreeCADError,e.what());
|
||||
}
|
||||
}
|
||||
|
||||
Py::Object ViewProviderLinkPy::getLinkView() const {
|
||||
return Py::Object(getViewProviderLinkPtr()->getPyLinkView(),true);
|
||||
}
|
||||
|
||||
PyObject *ViewProviderLinkPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ViewProviderLinkPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user