23
#include "PreCompiled.h"
28
# include <boost/algorithm/string/predicate.hpp>
29
# include <Inventor/SoPickedPoint.h>
30
# include <Inventor/actions/SoGetBoundingBoxAction.h>
31
# include <Inventor/details/SoDetail.h>
32
# include <Inventor/draggers/SoCenterballDragger.h>
33
# include <Inventor/misc/SoChildList.h>
34
# include <Inventor/nodes/SoAnnotation.h>
35
# include <Inventor/nodes/SoCube.h>
36
# include <Inventor/nodes/SoDrawStyle.h>
37
# include <Inventor/nodes/SoPickStyle.h>
38
# include <Inventor/nodes/SoSeparator.h>
39
# include <Inventor/nodes/SoShapeHints.h>
40
# include <Inventor/nodes/SoSurroundScale.h>
41
# include <Inventor/nodes/SoSwitch.h>
42
# include <Inventor/nodes/SoTransform.h>
43
# include <Inventor/sensors/SoNodeSensor.h>
44
# include <Inventor/SoPickedPoint.h>
45
# include <QApplication>
50
#include <boost/range.hpp>
51
#include <App/ElementNamingUtils.h>
52
#include <App/Document.h>
53
#include <Base/BoundBoxPy.h>
54
#include <Base/MatrixPy.h>
55
#include <Base/PlacementPy.h>
56
#include <Base/Tools.h>
59
#include "MainWindow.h"
60
#include "ViewProviderLink.h"
61
#include "ViewProviderLinkPy.h"
62
#include "Application.h"
63
#include "BitmapFactory.h"
65
#include "LinkViewPy.h"
67
#include "SoFCCSysDragger.h"
68
#include "SoFCUnifiedSelection.h"
69
#include "TaskCSysDragger.h"
70
#include "TaskElementColors.h"
71
#include "View3DInventor.h"
72
#include "ViewParams.h"
73
#include "ViewProviderGeometryObject.h"
75
#include "ActionFunction.h"
77
#include "DlgObjectSelection.h"
79
FC_LOG_LEVEL_INIT("App::Link", true, true)
84
using CharRange = boost::iterator_range<const char*>;
87
static inline bool appendPathSafe(SoPath *path, SoNode *node) {
88
if(path->getLength()) {
89
SoNode * tail = path->getTail();
90
const SoChildList * children = tail->getChildren();
91
if(!children || children->find((void *)node)<0)
99
#define appendPath(_path,_node) \
101
if(!appendPathSafe(_path,_node))\
102
FC_ERR("LinkView: coin path error");\
105
#define appendPath(_path, _node) (_path)->append(_node)
112
std::atomic<int> ref;
114
using Connection = boost::signals2::scoped_connection;
115
Connection connChangeIcon;
117
ViewProviderDocumentObject *pcLinked;
118
std::unordered_set<Gui::LinkOwner*> links;
120
using Pointer = LinkInfoPtr;
123
SoNodeSensor switchSensor;
124
SoNodeSensor childSensor;
125
SoNodeSensor transformSensor;
127
std::array<CoinPtr<SoSeparator>,LinkView::SnapshotMax> pcSnapshots;
128
std::array<CoinPtr<SoSwitch>,LinkView::SnapshotMax> pcSwitches;
129
CoinPtr<SoSwitch> pcLinkedSwitch;
132
CoinPtr<SoGroup> pcChildGroup;
133
using NodeMap = std::unordered_map<SoNode *, Pointer>;
136
std::map<qint64, QIcon> iconMap;
138
static ViewProviderDocumentObject *getView(App::DocumentObject *obj) {
139
if(obj && obj->isAttachedToDocument()) {
140
Document *pDoc = Application::Instance->getDocument(obj->getDocument());
142
ViewProvider *vp = pDoc->getViewProvider(obj);
143
if(vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
144
return static_cast<ViewProviderDocumentObject*>(vp);
150
static Pointer get(App::DocumentObject *obj, Gui::LinkOwner *owner) {
151
return get(getView(obj),owner);
154
static Pointer get(ViewProviderDocumentObject *vp, LinkOwner *owner) {
158
auto ext = vp->getExtensionByType<ViewProviderLinkObserver>(true);
160
ext = new ViewProviderLinkObserver();
161
ext->initExtension(vp);
166
ext->linkInfo = Pointer(new LinkInfo(vp));
167
ext->linkInfo->update();
170
ext->linkInfo->links.insert(owner);
171
return ext->linkInfo;
174
static void sensorCB(void *data, SoSensor *) {
175
static_cast<LinkInfo*>(data)->update();
178
static void switchSensorCB(void *data, SoSensor *) {
179
static_cast<LinkInfo*>(data)->updateSwitch();
182
static void childSensorCB(void *data, SoSensor *) {
183
static_cast<LinkInfo*>(data)->updateChildren();
186
static void transformSensorCB(void *data, SoSensor *) {
187
auto self = static_cast<LinkInfo*>(data);
188
for(size_t i=0;i<self->pcSnapshots.size();++i) {
189
if(self->pcSnapshots[i] && i!=LinkView::SnapshotTransform)
190
self->getSnapshot(i,true);
194
LinkInfo(ViewProviderDocumentObject *vp)
197
FC_LOG("new link to " << pcLinked->getObject()->getFullName());
199
connChangeIcon = vp->signalChangeIcon.connect(
200
std::bind(&LinkInfo::slotChangeIcon,this));
202
vp->forceUpdate(true);
203
sensor.setFunction(sensorCB);
204
sensor.setData(this);
205
switchSensor.setFunction(switchSensorCB);
206
switchSensor.setData(this);
207
childSensor.setFunction(childSensorCB);
208
childSensor.setData(this);
209
transformSensor.setFunction(transformSensorCB);
210
transformSensor.setData(this);
213
~LinkInfo() = default;
215
bool checkName(const char *name) const {
216
return isLinked() && strcmp(name,getLinkedName())==0;
219
void remove(LinkOwner *owner) {
223
bool isLinked() const {
224
return pcLinked && pcLinked->getObject() &&
225
pcLinked->getObject()->isAttachedToDocument();
228
const char *getLinkedName() const {
229
return pcLinked->getObject()->getDagKey();
232
const char *getLinkedLabel() const {
233
return pcLinked->getObject()->Label.getValue();
236
const char *getLinkedNameSafe() const {
238
return getLinkedName();
242
const char *getDocName() const {
243
return pcLinked->getDocument()->getDocument()->getName();
246
void detach(bool unlink) {
247
FC_LOG("link detach " << getLinkedNameSafe());
248
auto me = LinkInfoPtr(this);
250
while(!links.empty()) {
251
auto link = *links.begin();
252
links.erase(links.begin());
257
switchSensor.detach();
258
childSensor.detach();
259
transformSensor.detach();
260
for(const auto &node : pcSnapshots) {
262
coinRemoveAllChildren(node);
264
for(const auto &node : pcSwitches) {
266
coinRemoveAllChildren(node);
268
pcLinkedSwitch.reset();
270
coinRemoveAllChildren(pcChildGroup);
271
pcChildGroup.reset();
274
connChangeIcon.disconnect();
277
void updateSwitch(SoSwitch *node=nullptr) {
278
if(!isLinked() || !pcLinkedSwitch)
280
int index = pcLinkedSwitch->whichChild.getValue();
281
for(size_t i=0;i<pcSwitches.size();++i) {
282
if(!pcSwitches[i] || (node && node!=pcSwitches[i]))
284
int count = pcSwitches[i]->getNumChildren();
285
if((index<0 && i==LinkView::SnapshotChild) || !count)
286
pcSwitches[i]->whichChild = -1;
287
else if(count>pcLinked->getDefaultMode())
288
pcSwitches[i]->whichChild = pcLinked->getDefaultMode();
290
pcSwitches[i]->whichChild = 0;
294
inline void addref() {
298
inline void release(){
305
FC_LOG("link release " << getLinkedNameSafe());
306
auto ext = pcLinked->getExtensionByType<ViewProviderLinkObserver>(true);
307
if(ext && ext->linkInfo == this) {
308
pcLinked->forceUpdate(false);
310
ext->linkInfo.reset();
323
friend void Gui::intrusive_ptr_add_ref(LinkInfo *px);
324
friend void Gui::intrusive_ptr_release(LinkInfo *px);
326
friend inline void intrusive_ptr_add_ref(LinkInfo *px) { px->addref(); }
327
friend inline void intrusive_ptr_release(LinkInfo *px) { px->release(); }
330
bool isVisible() const {
333
int indices[] = {LinkView::SnapshotTransform, LinkView::SnapshotVisible};
334
for(int idx : indices) {
337
if(pcSwitches[idx]->whichChild.getValue()==-1)
343
void setVisible(bool visible) {
346
int indices[] = {LinkView::SnapshotTransform, LinkView::SnapshotVisible};
347
for(int idx : indices) {
351
pcSwitches[idx]->whichChild = -1;
352
else if(pcSwitches[idx]->getNumChildren()>pcLinked->getDefaultMode())
353
pcSwitches[idx]->whichChild = pcLinked->getDefaultMode();
357
SoSeparator *getSnapshot(int type, bool update=false) {
358
if(type<0 || type>=LinkView::SnapshotMax)
362
if(!isLinked() || !(root=pcLinked->getRoot()))
365
if(sensor.getAttachedNode()!=root) {
370
auto &pcSnapshot = pcSnapshots[type];
371
auto &pcModeSwitch = pcSwitches[type];
376
if(ViewParams::instance()->getUseSelectionRoot())
377
pcSnapshot = new SoFCSelectionRoot;
379
pcSnapshot = new SoSeparator;
380
pcSnapshot->boundingBoxCaching = SoSeparator::OFF;
381
pcSnapshot->renderCaching = SoSeparator::OFF;
382
std::ostringstream ss;
383
ss << pcLinked->getObject()->getNameInDocument()
384
<< "(" << type << ')';
385
pcSnapshot->setName(ss.str().c_str());
386
pcModeSwitch = new SoSwitch;
389
pcLinkedSwitch.reset();
391
coinRemoveAllChildren(pcSnapshot);
392
pcModeSwitch->whichChild = -1;
393
coinRemoveAllChildren(pcModeSwitch);
395
SoSwitch *pcUpdateSwitch = pcModeSwitch;
397
auto childRoot = pcLinked->getChildRoot();
399
for(int i=0,count=root->getNumChildren();i<count;++i) {
400
SoNode *node = root->getChild(i);
401
if(node==pcLinked->getTransformNode()) {
402
if(type!=LinkView::SnapshotTransform)
403
pcSnapshot->addChild(node);
405
auto transform = pcLinked->getTransformNode();
406
const auto &scale = transform->scaleFactor.getValue();
407
if(scale[0]!=1.0 || scale[1]!=1.0 || scale[2]!=1.0) {
408
auto trans = new SoTransform;
409
pcSnapshot->addChild(trans);
410
trans->scaleFactor.setValue(scale);
411
trans->scaleOrientation = transform->scaleOrientation;
412
if(transformSensor.getAttachedNode()!=transform) {
413
transformSensor.detach();
414
transformSensor.attach(transform);
419
} else if(node!=pcLinked->getModeSwitch()) {
420
pcSnapshot->addChild(node);
424
pcLinkedSwitch = static_cast<SoSwitch*>(node);
425
if(switchSensor.getAttachedNode() != pcLinkedSwitch) {
426
switchSensor.detach();
427
switchSensor.attach(pcLinkedSwitch);
428
pcUpdateSwitch = nullptr;
431
pcSnapshot->addChild(pcModeSwitch);
432
for(int i=0,count=pcLinkedSwitch->getNumChildren();i<count;++i) {
433
auto child = pcLinkedSwitch->getChild(i);
434
if(pcChildGroup && child==childRoot)
435
pcModeSwitch->addChild(pcChildGroup);
437
pcModeSwitch->addChild(child);
440
updateSwitch(pcUpdateSwitch);
444
void updateData(const App::Property *prop) {
445
LinkInfoPtr me(this);
446
for(auto link : links)
447
link->onLinkedUpdateData(me,prop);
452
if(!isLinked() || pcLinked->isRestoring())
457
for(size_t i=0;i<pcSnapshots.size();++i)
462
void updateChildren() {
466
if(!pcLinked->getChildRoot()) {
467
childSensor.detach();
469
coinRemoveAllChildren(pcChildGroup);
473
if(childSensor.getAttachedNode() != pcLinked->getChildRoot()) {
474
childSensor.detach();
475
childSensor.attach(pcLinked->getChildRoot());
478
pcChildGroup = new SoGroup;
480
coinRemoveAllChildren(pcChildGroup);
484
for(auto child : pcLinked->claimChildren3D()) {
485
Pointer info = get(child,nullptr);
487
SoNode *node = info->getSnapshot(LinkView::SnapshotChild);
489
nodeMap[node] = info;
490
pcChildGroup->addChild(node);
495
this->nodeMap.swap(nodeMap);
498
bool getElementPicked(bool addname, int type,
499
const SoPickedPoint *pp, std::ostream &str) const
501
if(!pp || !isLinked() || !pcLinked->isSelectable())
505
str << getLinkedName() <<'.';
507
auto pcSwitch = pcSwitches[type];
508
if(pcChildGroup && pcSwitch && pcSwitch->whichChild.getValue()>=0 &&
509
pcSwitch->getChild(pcSwitch->whichChild.getValue())==pcChildGroup)
511
SoPath *path = pp->getPath();
512
int index = path->findNode(pcChildGroup);
515
auto it = nodeMap.find(path->getNode(index+1));
516
if(it==nodeMap.end())
518
return it->second->getElementPicked(true,LinkView::SnapshotChild,pp,str);
521
if(!pcLinked->getElementPicked(pp,subname))
528
static const char *checkSubname(App::DocumentObject *obj, const char *subname) {
529
#define CHECK_NAME(_name,_end) do{\
530
if(!_name) return 0;\
531
const char *_n = _name;\
532
for(;*subname && *_n; ++subname,++_n)\
533
if(*subname != *_n) break;\
534
if(*_n || (*subname!=0 && *subname!=_end))\
536
if(*subname == _end) ++subname;\
543
CHECK_NAME(obj->getNameInDocument(),'.');
547
bool getDetail(bool checkname, int type, const char* subname,
548
SoDetail *&det, SoFullPath *path) const
554
subname = checkSubname(pcLinked->getObject(),subname);
559
if(pcSnapshots[type]->findChild(pcSwitches[type]) < 0) {
561
if(!appendPathSafe(path,pcSnapshots[type]))
570
len = path->getLength();
571
if(!appendPathSafe(path,pcSnapshots[type]))
573
appendPath(path,pcSwitches[type]);
578
auto pcSwitch = pcSwitches[type];
579
if(!pcChildGroup || !pcSwitch || pcSwitch->whichChild.getValue()<0 ||
580
pcSwitch->getChild(pcSwitch->whichChild.getValue())!=pcChildGroup)
582
return pcLinked->getDetailPath(subname,path,false,det);
585
appendPath(path,pcChildGroup);
586
if(pcLinked->getChildRoot())
587
type = LinkView::SnapshotChild;
589
type = LinkView::SnapshotVisible;
608
const char *dot = strchr(subname,'.');
609
const char *nextsub = subname;
612
auto geoGroup = pcLinked->getObject();
613
auto sobj = geoGroup;
615
std::string objname = std::string(nextsub,dot-nextsub+1);
616
if(!geoGroup->getSubObject(objname.c_str())) {
623
auto ssobj = sobj->getSubObject(objname.c_str());
625
FC_ERR("invalid sub name " << nextsub << " of object " << sobj->getFullName());
629
auto vp = Application::Instance->getViewProvider(sobj);
631
FC_ERR("cannot find view provider of " << sobj->getFullName());
634
if(vp->getChildRoot()) {
640
if(Data::isMappedElement(dot+1))
642
auto next = strchr(dot+1,'.');
651
for(const auto& v : nodeMap) {
652
if(v.second->getDetail(true,type,subname,det,path))
660
void slotChangeIcon() {
664
LinkInfoPtr me(this);
665
for(auto link : links)
666
link->onLinkedIconChange(me);
669
QIcon getIcon(QPixmap px) {
670
static int iconSize = -1;
672
iconSize = QApplication::style()->standardPixmap(QStyle::SP_DirClosedIcon).width();
678
return pcLinked->getIcon();
679
QIcon &iconLink = iconMap[px.cacheKey()];
680
if(iconLink.isNull()) {
681
QIcon icon = pcLinked->getIcon();
683
iconLink.addPixmap(BitmapFactory().merge(icon.pixmap(iconSize, iconSize, QIcon::Normal, QIcon::Off),
684
px,BitmapFactoryInst::BottomLeft), QIcon::Normal, QIcon::Off);
685
iconLink.addPixmap(BitmapFactory().merge(icon.pixmap(iconSize, iconSize, QIcon::Normal, QIcon::On ),
686
px,BitmapFactoryInst::BottomLeft), QIcon::Normal, QIcon::On);
695
void intrusive_ptr_add_ref(Gui::LinkInfo* px)
700
void intrusive_ptr_release(Gui::LinkInfo* px)
709
EXTENSION_TYPESYSTEM_SOURCE(Gui::ViewProviderLinkObserver,Gui::ViewProviderExtension)
711
ViewProviderLinkObserver::ViewProviderLinkObserver() {
713
m_isPythonExtension = true;
714
initExtensionType(ViewProviderLinkObserver::getExtensionClassTypeId());
717
ViewProviderLinkObserver::~ViewProviderLinkObserver() {
719
linkInfo->detach(true);
724
bool ViewProviderLinkObserver::isLinkVisible() const {
726
return linkInfo->isVisible();
730
void ViewProviderLinkObserver::setLinkVisible(bool visible) {
732
linkInfo->setVisible(visible);
735
void ViewProviderLinkObserver::extensionBeforeDelete() {
737
linkInfo->detach(false);
740
void ViewProviderLinkObserver::extensionReattach(App::DocumentObject *) {
743
Base::freecad_dynamic_cast<ViewProviderDocumentObject>(getExtendedContainer());
748
void ViewProviderLinkObserver::extensionOnChanged(const App::Property *prop) {
752
void ViewProviderLinkObserver::extensionModeSwitchChange() {
753
auto owner = freecad_dynamic_cast<ViewProviderDocumentObject>(getExtendedContainer());
754
if(owner && linkInfo)
755
linkInfo->updateSwitch();
758
void ViewProviderLinkObserver::extensionUpdateData(const App::Property *prop) {
759
if(linkInfo && linkInfo->pcLinked && linkInfo->pcLinked->getObject() &&
760
prop != &linkInfo->pcLinked->getObject()->Visibility)
761
linkInfo->updateData(prop);
764
void ViewProviderLinkObserver::extensionFinishRestoring() {
766
FC_TRACE("linked finish restoing");
771
class LinkView::SubInfo : public LinkOwner {
773
LinkInfoPtr linkInfo;
775
CoinPtr<SoSeparator> pcNode;
776
CoinPtr<SoTransform> pcTransform;
777
std::set<std::string> subElements;
781
SubInfo(LinkView &handle):handle(handle) {
782
pcNode = new SoFCSelectionRoot(true);
783
pcTransform = new SoTransform;
784
pcNode->addChild(pcTransform);
787
~SubInfo() override {
789
auto root = handle.getLinkRoot();
791
int idx = root->findChild(pcNode);
793
root->removeChild(idx);
797
void onLinkedIconChange(LinkInfoPtr) override {
798
if(handle.autoSubLink && handle.subInfo.size()==1)
799
handle.onLinkedIconChange(handle.linkInfo);
802
void unlink(LinkInfoPtr info=LinkInfoPtr()) override {
805
linkInfo->remove(this);
808
coinRemoveAllChildren(pcNode);
809
pcNode->addChild(pcTransform);
812
void link(App::DocumentObject *obj) {
813
if(isLinked() && linkInfo->pcLinked->getObject()==obj)
816
linkInfo = LinkInfo::get(obj,this);
818
pcNode->addChild(linkInfo->getSnapshot(LinkView::SnapshotTransform));
821
bool isLinked() const{
822
return linkInfo && linkInfo->isLinked();
828
class LinkView::Element : public LinkOwner {
830
LinkInfoPtr linkInfo;
832
CoinPtr<SoSwitch> pcSwitch;
833
CoinPtr<SoFCSelectionRoot> pcRoot;
834
CoinPtr<SoTransform> pcTransform;
836
bool isGroup = false;
840
Element(LinkView &handle):handle(handle) {
841
pcTransform = new SoTransform;
842
pcRoot = new SoFCSelectionRoot(true);
843
pcSwitch = new SoSwitch;
844
pcSwitch->addChild(pcRoot);
845
pcSwitch->whichChild = 0;
848
~Element() override {
850
auto root = handle.getLinkRoot();
852
int idx = root->findChild(pcRoot);
854
root->removeChild(idx);
858
void unlink(LinkInfoPtr info=LinkInfoPtr()) override{
861
linkInfo->remove(this);
864
coinRemoveAllChildren(pcRoot);
867
void link(App::DocumentObject *obj) {
868
if(isLinked() && linkInfo->pcLinked->getObject()==obj)
871
linkInfo = LinkInfo::get(obj,this);
873
pcRoot->addChild(linkInfo->getSnapshot(handle.childType));
876
bool isLinked() const{
877
return linkInfo && linkInfo->isLinked();
883
TYPESYSTEM_SOURCE(Gui::LinkView,Base::BaseClass)
886
:nodeType(SnapshotTransform)
887
,childType((SnapshotType)-1),autoSubLink(true)
889
pcLinkRoot = new SoFCSelectionRoot;
892
LinkView::~LinkView() {
897
PyObject *LinkView::getPyObject()
899
if (PythonObject.is(Py::_None()))
900
PythonObject = Py::Object(new LinkViewPy(this),true);
901
return Py::new_reference_to(PythonObject);
904
void LinkView::setInvalid() {
905
if (!PythonObject.is(Py::_None())){
906
auto obj = static_cast<Base::PyObjectBase*>(PythonObject.ptr());
913
Base::BoundBox3d _getBoundBox(ViewProviderDocumentObject *vpd, SoNode *rootNode) {
914
auto doc = vpd->getDocument();
916
LINK_THROW(Base::RuntimeError,"no document");
917
Gui::MDIView* view = doc->getViewOfViewProvider(vpd);
919
LINK_THROW(Base::RuntimeError,"no view");
921
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
922
SoGetBoundingBoxAction bboxAction(viewer->getSoRenderManager()->getViewportRegion());
923
bboxAction.apply(rootNode);
924
auto bbox = bboxAction.getBoundingBox();
925
float minX,minY,minZ,maxX,maxY,maxZ;
926
bbox.getMax().getValue(maxX,maxY,maxZ);
927
bbox.getMin().getValue(minX,minY,minZ);
928
return Base::BoundBox3d(minX,minY,minZ,maxX,maxY,maxZ);
931
Base::BoundBox3d LinkView::getBoundBox(ViewProviderDocumentObject *vpd) const {
933
if(!linkOwner || !linkOwner->isLinked())
934
LINK_THROW(Base::ValueError,"no ViewProvider");
935
vpd = linkOwner->pcLinked;
937
return _getBoundBox(vpd,pcLinkRoot);
940
ViewProviderDocumentObject *LinkView::getOwner() const {
941
if(linkOwner && linkOwner->isLinked())
942
return linkOwner->pcLinked;
946
void LinkView::setOwner(ViewProviderDocumentObject *vpd) {
948
linkOwner = LinkInfo::get(vpd,this);
951
bool LinkView::isLinked() const{
952
return linkInfo && linkInfo->isLinked();
955
void LinkView::setDrawStyle(int style, double lineWidth, double pointSize) {
959
pcDrawStyle = new SoDrawStyle;
960
pcDrawStyle->style = SoDrawStyle::FILLED;
961
pcLinkRoot->insertChild(pcDrawStyle,0);
964
pcDrawStyle->setOverride(false);
967
pcDrawStyle->lineWidth = lineWidth;
968
pcDrawStyle->pointSize = pointSize;
971
pcDrawStyle->linePattern = 0xf00f;
974
pcDrawStyle->linePattern = 0x0f0f;
977
pcDrawStyle->linePattern = 0xff88;
980
pcDrawStyle->linePattern = 0xffff;
982
pcDrawStyle->setOverride(true);
985
void LinkView::renderDoubleSide(bool enable) {
988
pcShapeHints = new SoShapeHints;
989
pcShapeHints->vertexOrdering = SoShapeHints::CLOCKWISE;
990
pcShapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
991
pcLinkRoot->insertChild(pcShapeHints,0);
993
pcShapeHints->setOverride(true);
994
}else if(pcShapeHints)
995
pcShapeHints->setOverride(false);
998
void LinkView::setMaterial(int index, const App::Material *material) {
1001
pcLinkRoot->removeColorOverride();
1004
App::Color c = material->diffuseColor;
1005
c.a = material->transparency;
1006
pcLinkRoot->setColorOverride(c);
1007
for(int i=0;i<getSize();++i)
1008
setMaterial(i,nullptr);
1009
}else if(index >= (int)nodeArray.size())
1010
LINK_THROW(Base::ValueError,"LinkView: material index out of range");
1012
auto &info = *nodeArray[index];
1014
info.pcRoot->removeColorOverride();
1017
App::Color c = material->diffuseColor;
1018
c.a = material->transparency;
1019
info.pcRoot->setColorOverride(c);
1023
void LinkView::setLink(App::DocumentObject *obj, const std::vector<std::string> &subs) {
1024
setLinkViewObject(Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
1025
Application::Instance->getViewProvider(obj)),subs);
1029
void LinkView::setLinkViewObject(ViewProviderDocumentObject *vpd,
1030
const std::vector<std::string> &subs)
1032
if(!isLinked() || linkInfo->pcLinked != vpd) {
1034
linkInfo = LinkInfo::get(vpd,this);
1039
for(const auto &sub : subs) {
1040
if(sub.empty()) continue;
1041
const char *subelement = Data::findElementName(sub.c_str());
1042
std::string subname = sub.substr(0,subelement-sub.c_str());
1043
auto it = subInfo.find(subname);
1044
if(it == subInfo.end()) {
1045
it = subInfo.insert(std::make_pair(subname,std::unique_ptr<SubInfo>())).first;
1046
it->second = std::make_unique<SubInfo>(*this);
1049
it->second->subElements.insert(subelement);
1054
void LinkView::setTransform(SoTransform *pcTransform, const Base::Matrix4D &mat) {
1056
mat.getGLMatrix(dMtrx);
1057
pcTransform->setMatrix(SbMatrix(dMtrx[0], dMtrx[1], dMtrx[2], dMtrx[3],
1058
dMtrx[4], dMtrx[5], dMtrx[6], dMtrx[7],
1059
dMtrx[8], dMtrx[9], dMtrx[10], dMtrx[11],
1060
dMtrx[12],dMtrx[13],dMtrx[14], dMtrx[15]));
1063
void LinkView::setSize(int _size) {
1064
size_t size = _size<0?0:(size_t)_size;
1065
if(childType<0 && size==nodeArray.size())
1068
if(!size || childType>=0) {
1071
if(!size && childType<0) {
1073
pcLinkRoot->addChild(pcLinkedRoot);
1076
childType = SnapshotContainer;
1078
if(size<nodeArray.size()) {
1079
for(size_t i=size;i<nodeArray.size();++i)
1080
nodeMap.erase(nodeArray[i]->pcSwitch);
1081
nodeArray.resize(size);
1083
for(const auto &info : nodeArray)
1084
pcLinkRoot->addChild(info->pcSwitch);
1086
while(nodeArray.size()<size) {
1087
nodeArray.push_back(std::make_unique<Element>(*this));
1088
auto &info = *nodeArray.back();
1089
info.pcRoot->addChild(info.pcTransform);
1091
info.pcRoot->addChild(pcLinkedRoot);
1092
pcLinkRoot->addChild(info.pcSwitch);
1093
nodeMap.emplace(info.pcSwitch,(int)nodeArray.size()-1);
1097
void LinkView::resetRoot() {
1098
coinRemoveAllChildren(pcLinkRoot);
1100
pcLinkRoot->addChild(pcTransform);
1102
pcLinkRoot->addChild(pcShapeHints);
1104
pcLinkRoot->addChild(pcDrawStyle);
1107
void LinkView::setChildren(const std::vector<App::DocumentObject*> &children,
1108
const boost::dynamic_bitset<> &vis, SnapshotType type)
1110
if(children.empty()) {
1111
if(!nodeArray.empty()) {
1114
childType = SnapshotContainer;
1117
pcLinkRoot->addChild(pcLinkedRoot);
1122
if(type<0 || type>=SnapshotMax)
1123
LINK_THROW(Base::ValueError,"invalid children type");
1131
if(nodeArray.size() > children.size())
1132
nodeArray.resize(children.size());
1134
nodeArray.reserve(children.size());
1136
std::map<App::DocumentObject*, size_t> groups;
1137
for(size_t i=0;i<children.size();++i) {
1138
auto obj = children[i];
1139
if(nodeArray.size()<=i) {
1140
nodeArray.push_back(std::make_unique<Element>(*this));
1142
auto &info = *nodeArray[i];
1143
info.isGroup = false;
1144
info.groupIndex = -1;
1145
info.pcSwitch->whichChild = (vis.size()<=i||vis[i])?0:-1;
1147
if(obj->hasExtension(App::GroupExtension::getExtensionClassTypeId(),false)) {
1148
info.isGroup = true;
1149
coinRemoveAllChildren(info.pcRoot);
1150
groups.emplace(obj,i);
1154
for(size_t i=0;i<nodeArray.size();++i) {
1155
auto &info = *nodeArray[i];
1156
nodeMap.emplace(info.pcSwitch,i);
1157
if(info.isLinked() && !groups.empty()) {
1158
auto iter = groups.find(App::GroupExtension::getGroupOfObject(
1159
info.linkInfo->pcLinked->getObject()));
1160
if(iter != groups.end()) {
1161
info.groupIndex = iter->second;
1162
auto &groupInfo = *nodeArray[iter->second];
1163
groupInfo.pcRoot->addChild(info.pcSwitch);
1167
pcLinkRoot->addChild(info.pcSwitch);
1171
std::vector<ViewProviderDocumentObject*> LinkView::getChildren() const {
1172
std::vector<ViewProviderDocumentObject*> ret;
1173
for(const auto &info : nodeArray) {
1174
if(info->isLinked())
1175
ret.push_back(info->linkInfo->pcLinked);
1180
void LinkView::setTransform(int index, const Base::Matrix4D &mat) {
1183
pcTransform = new SoTransform;
1184
pcLinkRoot->insertChild(pcTransform,0);
1186
setTransform(pcTransform,mat);
1189
if(index<0 || index>=(int)nodeArray.size())
1190
LINK_THROW(Base::ValueError,"LinkView: index out of range");
1191
setTransform(nodeArray[index]->pcTransform,mat);
1194
void LinkView::setElementVisible(int idx, bool visible) {
1195
if(idx>=0 && idx<(int)nodeArray.size())
1196
nodeArray[idx]->pcSwitch->whichChild = visible?0:-1;
1199
bool LinkView::isElementVisible(int idx) const {
1200
if(idx>=0 && idx<(int)nodeArray.size())
1201
return nodeArray[idx]->pcSwitch->whichChild.getValue()>=0;
1205
ViewProviderDocumentObject *LinkView::getLinkedView() const {
1206
auto link = linkInfo;
1207
if(autoSubLink && subInfo.size()==1)
1208
link = subInfo.begin()->second->linkInfo;
1209
return link?link->pcLinked:nullptr;
1212
std::vector<std::string> LinkView::getSubNames() const {
1213
std::vector<std::string> ret;
1214
for(const auto &v : subInfo) {
1215
if(v.second->subElements.empty()) {
1216
ret.push_back(v.first);
1219
for(const auto &s : v.second->subElements)
1220
ret.push_back(v.first+s);
1225
void LinkView::setNodeType(SnapshotType type, bool sublink) {
1226
autoSubLink = sublink;
1229
if(type>=SnapshotMax ||
1230
(type<0 && type!=SnapshotContainer && type!=SnapshotContainerTransform))
1231
LINK_THROW(Base::ValueError,"LinkView: invalid node type");
1233
if(nodeType>=0 && type<0) {
1235
SoSelectionElementAction action(SoSelectionElementAction::None,true);
1236
action.apply(pcLinkedRoot);
1238
replaceLinkedRoot(CoinPtr<SoSeparator>(new SoFCSelectionRoot));
1239
}else if(nodeType<0 && type>=0) {
1241
replaceLinkedRoot(linkInfo->getSnapshot(type));
1243
replaceLinkedRoot(nullptr);
1249
void LinkView::replaceLinkedRoot(SoSeparator *root) {
1250
if(root==pcLinkedRoot)
1252
if(nodeArray.empty()) {
1253
if(pcLinkedRoot && root)
1254
pcLinkRoot->replaceChild(pcLinkedRoot,root);
1256
pcLinkRoot->addChild(root);
1259
}else if(childType<0) {
1260
if(pcLinkedRoot && root) {
1261
for(const auto &info : nodeArray)
1262
info->pcRoot->replaceChild(pcLinkedRoot,root);
1264
for(const auto &info : nodeArray)
1265
info->pcRoot->addChild(root);
1267
for(const auto &info : nodeArray)
1268
info->pcRoot->removeChild(pcLinkedRoot);
1271
pcLinkedRoot = root;
1274
void LinkView::onLinkedIconChange(LinkInfoPtr info) {
1275
if(info==linkInfo && info!=linkOwner && linkOwner && linkOwner->isLinked())
1276
linkOwner->pcLinked->signalChangeIcon();
1279
void LinkView::onLinkedUpdateData(LinkInfoPtr info, const App::Property *prop) {
1280
if(info!=linkInfo || !linkOwner || !linkOwner->isLinked() || info==linkOwner)
1282
auto ext = linkOwner->pcLinked->getObject()->getExtensionByType<App::LinkBaseExtension>(true);
1283
if (ext && !(prop->getType() & App::Prop_Output) &&
1284
!prop->testStatus(App::Property::Output))
1290
ext->_LinkTouched.touch();
1295
linkOwner->pcLinked->getDocument()->signalChangedObject(
1296
*linkOwner->pcLinked,linkOwner->pcLinked->getObject()->Label);
1300
void LinkView::updateLink() {
1304
if(linkOwner && linkOwner->isLinked() && linkOwner->pcLinked->isRestoring()) {
1305
FC_TRACE("restoring '" << linkOwner->pcLinked->getObject()->getFullName() << "'");
1310
pcLinkRoot->resetContext();
1313
replaceLinkedRoot(linkInfo->getSnapshot(nodeType));
1318
CoinPtr<SoSeparator> linkedRoot = pcLinkedRoot;
1320
linkedRoot = new SoFCSelectionRoot;
1322
SoSelectionElementAction action(SoSelectionElementAction::None,true);
1323
action.apply(linkedRoot);
1324
coinRemoveAllChildren(linkedRoot);
1327
SoTempPath path(10);
1329
appendPath(&path,linkedRoot);
1330
auto obj = linkInfo->pcLinked->getObject();
1331
for(const auto &v : subInfo) {
1332
auto &sub = *v.second;
1334
App::DocumentObject *sobj = obj->getSubObject(
1335
v.first.c_str(), nullptr, &mat, nodeType==SnapshotContainer);
1341
linkedRoot->addChild(sub.pcNode);
1342
setTransform(sub.pcTransform,mat);
1344
if(!sub.subElements.empty()) {
1346
appendPath(&path,sub.pcNode);
1347
SoSelectionElementAction action(SoSelectionElementAction::Append,true);
1348
for(const auto &subelement : sub.subElements) {
1350
SoDetail *det = nullptr;
1351
if(!sub.linkInfo->getDetail(false,SnapshotTransform,subelement.c_str(),det,&path))
1353
action.setElement(det);
1354
action.apply(&path);
1359
path.unrefNoDelete();
1360
replaceLinkedRoot(linkedRoot);
1363
bool LinkView::linkGetElementPicked(const SoPickedPoint *pp, std::string &subname) const
1365
std::ostringstream ss;
1366
CoinPtr<SoPath> path = pp->getPath();
1367
if(!nodeArray.empty()) {
1368
auto idx = path->findNode(pcLinkRoot);
1369
if (idx < 0 || idx + 2 >= path->getLength()) {
1372
auto node = path->getNode(idx+1);
1373
auto it = nodeMap.find(node);
1374
if(it == nodeMap.end() || !isElementVisible(it->second)) {
1377
int nodeIdx = it->second;
1379
while(nodeArray[nodeIdx]->isGroup) {
1380
auto &info = *nodeArray[nodeIdx];
1381
if(!info.isLinked()) {
1384
ss << info.linkInfo->getLinkedName() << '.';
1386
if(idx>=path->getLength()) {
1389
auto iter = nodeMap.find(path->getNode(idx));
1390
if(iter == nodeMap.end() || !isElementVisible(iter->second)) {
1393
nodeIdx = iter->second;
1396
auto &info = *nodeArray[nodeIdx];
1397
if (!info.linkInfo) {
1398
ss << it->second << '.';
1401
ss << info.linkInfo->getLinkedName() << '.';
1404
if(info.isLinked()) {
1405
if (!info.linkInfo->getElementPicked(false, childType, pp, ss)) {
1418
if(linkInfo->getElementPicked(false,nodeType,pp,ss)) {
1424
auto idx = path->findNode(pcLinkedRoot);
1425
if(idx<0 || idx+1>=path->getLength()) {
1428
auto node = path->getNode(idx+1);
1429
for(const auto &v : subInfo) {
1430
auto &sub = *v.second;
1431
if (node != sub.pcNode) {
1435
std::ostringstream ss2;
1436
if(!sub.linkInfo->getElementPicked(false,SnapshotTransform,pp,ss2)) {
1439
const std::string &element = ss2.str();
1440
if(!sub.subElements.empty()) {
1441
if(sub.subElements.find(element)==sub.subElements.end()) {
1442
auto pos = element.find('.');
1443
if (pos == std::string::npos ||
1444
sub.subElements.find(element.c_str() + pos + 1) == sub.subElements.end()) {
1449
if (!autoSubLink || subInfo.size() > 1) {
1459
bool LinkView::getGroupHierarchy(int index, SoFullPath *path) const {
1460
if(index > (int)nodeArray.size())
1462
auto &info = *nodeArray[index];
1463
if(info.groupIndex>=0 && !getGroupHierarchy(info.groupIndex,path))
1465
appendPath(path,info.pcSwitch);
1466
appendPath(path,info.pcRoot);
1470
bool LinkView::linkGetDetailPath(const char *subname, SoFullPath *path, SoDetail *&det) const
1472
if(!subname || *subname==0)
1474
auto len = path->getLength();
1475
if(nodeArray.empty()) {
1476
if(!appendPathSafe(path,pcLinkRoot))
1480
if (subname[0]>='0' && subname[0]<='9') {
1481
idx = App::LinkBaseExtension::getArrayIndex(subname,&subname);
1484
const char *dot = strchr(subname,'.');
1488
if (subname[0] == '$') {
1489
CharRange name(subname+1,dot);
1490
for(const auto &info : nodeArray) {
1491
if(info->isLinked() && boost::equals(name,info->linkInfo->getLinkedLabel())) {
1498
CharRange name(subname,dot);
1499
for(const auto &info : nodeArray) {
1500
if(info->isLinked() && boost::equals(name,info->linkInfo->getLinkedName())) {
1512
if(!subname[0] || nodeArray[idx]->isGroup==0)
1518
if(idx<0 || idx>=(int)nodeArray.size())
1520
auto &info = *nodeArray[idx];
1521
if(!appendPathSafe(path,pcLinkRoot))
1523
if(info.groupIndex>=0 && !getGroupHierarchy(info.groupIndex,path))
1525
appendPath(path,info.pcSwitch);
1526
appendPath(path,info.pcRoot);
1531
if(info.isLinked()) {
1532
info.linkInfo->getDetail(false,childType,subname,det,path);
1538
if(linkInfo->getDetail(false,nodeType,subname,det,path))
1541
appendPath(path,pcLinkedRoot);
1542
for(const auto &v : subInfo) {
1543
auto &sub = *v.second;
1546
const char *nextsub;
1547
if(autoSubLink && subInfo.size()==1)
1550
if(!boost::algorithm::starts_with(subname,v.first))
1552
nextsub = subname+v.first.size();
1557
if(*nextsub && !sub.subElements.empty() &&
1558
sub.subElements.find(nextsub)==sub.subElements.end())
1560
appendPath(path,sub.pcNode);
1561
len = path->getLength();
1562
if(sub.linkInfo->getDetail(false,SnapshotTransform,nextsub,det,path))
1568
path->truncate(len);
1572
void LinkView::unlink(LinkInfoPtr info) {
1575
if(info == linkOwner) {
1576
linkOwner->remove(this);
1579
if(info != linkInfo)
1582
linkInfo->remove(this);
1585
pcLinkRoot->resetContext();
1587
if(nodeArray.empty())
1590
for(const auto &info : nodeArray) {
1592
if(info->isLinked() &&
1593
(idx=info->pcRoot->findChild(pcLinkedRoot))>=0)
1594
info->pcRoot->removeChild(idx);
1597
pcLinkedRoot.reset();
1603
QIcon LinkView::getLinkedIcon(QPixmap px) const {
1604
auto link = linkInfo;
1605
if(autoSubLink && subInfo.size()==1)
1606
link = subInfo.begin()->second->linkInfo;
1607
if(!link || !link->isLinked())
1609
return link->getIcon(px);
1612
bool LinkView::hasSubs() const {
1613
return isLinked() && !subInfo.empty();
1618
PROPERTY_SOURCE(Gui::ViewProviderLink, Gui::ViewProviderDocumentObject)
1620
static const char *_LinkIcon = "Link";
1622
static const char *_LinkGroupIcon = "LinkGroup";
1623
static const char *_LinkElementIcon = "LinkElement";
1625
ViewProviderLink::ViewProviderLink()
1626
:linkType(LinkTypeNone),hasSubName(false),hasSubElement(false)
1627
,useCenterballDragger(false),childVp(nullptr),overlayCacheKey(0)
1629
sPixmap = _LinkIcon;
1631
ADD_PROPERTY_TYPE(Selectable, (true), " Link", App::Prop_None, 0);
1633
ADD_PROPERTY_TYPE(OverrideMaterial, (false), " Link", App::Prop_None, "Override linked object's material");
1635
App::Material mat(App::Material::DEFAULT);
1636
mat.diffuseColor.setPackedValue(ViewParams::instance()->getDefaultLinkColor());
1637
ADD_PROPERTY_TYPE(ShapeMaterial, (mat), " Link", App::Prop_None, 0);
1638
ShapeMaterial.setStatus(App::Property::MaterialEdit, true);
1640
ADD_PROPERTY_TYPE(DrawStyle,((long int)0), " Link", App::Prop_None, "");
1641
static const char* DrawStyleEnums[]= {"None","Solid","Dashed","Dotted","Dashdot",nullptr};
1642
DrawStyle.setEnums(DrawStyleEnums);
1644
int lwidth = ViewParams::instance()->getDefaultShapeLineWidth();
1645
ADD_PROPERTY_TYPE(LineWidth,(lwidth), " Link", App::Prop_None, "");
1647
static App::PropertyFloatConstraint::Constraints sizeRange = {1.0,64.0,1.0};
1648
LineWidth.setConstraints(&sizeRange);
1650
ADD_PROPERTY_TYPE(PointSize,(lwidth), " Link", App::Prop_None, "");
1651
PointSize.setConstraints(&sizeRange);
1653
ADD_PROPERTY(MaterialList,());
1654
MaterialList.setStatus(App::Property::NoMaterialListEdit, true);
1656
ADD_PROPERTY(OverrideMaterialList,());
1657
ADD_PROPERTY(OverrideColorList,());
1659
ADD_PROPERTY(ChildViewProvider, (""));
1660
ChildViewProvider.setStatus(App::Property::Hidden,true);
1662
DisplayMode.setStatus(App::Property::Status::Hidden, true);
1664
linkView = new LinkView;
1667
ViewProviderLink::~ViewProviderLink()
1669
linkView->setInvalid();
1672
bool ViewProviderLink::isSelectable() const {
1673
return !pcDragger && Selectable.getValue();
1676
void ViewProviderLink::attach(App::DocumentObject *pcObj) {
1677
SoNode *node = linkView->getLinkRoot();
1678
node->setName(pcObj->getFullName().c_str());
1679
addDisplayMaskMode(node,"Link");
1681
childVpLink = LinkInfo::get(childVp,nullptr);
1682
node = childVpLink->getSnapshot(LinkView::SnapshotTransform);
1684
addDisplayMaskMode(node,"ChildView");
1685
setDisplayMaskMode("Link");
1686
inherited::attach(pcObj);
1688
if(pcObj->isDerivedFrom(App::LinkElement::getClassTypeId()))
1690
linkView->setOwner(this);
1694
void ViewProviderLink::reattach(App::DocumentObject *obj) {
1695
linkView->setOwner(this);
1697
childVp->reattach(obj);
1698
ViewProviderDocumentObject::reattach(obj);
1701
std::vector<std::string> ViewProviderLink::getDisplayModes() const
1703
std::vector<std::string> StrList = inherited::getDisplayModes();
1704
StrList.emplace_back("Link");
1705
StrList.emplace_back("ChildView");
1709
QIcon ViewProviderLink::getIcon() const {
1710
auto ext = getLinkExtension();
1712
auto link = ext->getLinkedObjectValue();
1713
if(link && link!=getObject()) {
1714
QPixmap overlay = getOverlayPixmap();
1715
overlayCacheKey = overlay.cacheKey();
1716
QIcon icon = linkView->getLinkedIcon(overlay);
1721
overlayCacheKey = 0;
1722
return Gui::BitmapFactory().pixmap(sPixmap);
1725
QPixmap ViewProviderLink::getOverlayPixmap() const {
1726
auto ext = getLinkExtension();
1727
int px = 12 * getMainWindow()->devicePixelRatioF();
1728
if(ext && ext->getLinkedObjectProperty() && ext->_getElementCountValue())
1729
return BitmapFactory().pixmapFromSvg("LinkArrayOverlay", QSizeF(px,px));
1730
else if(hasSubElement)
1731
return BitmapFactory().pixmapFromSvg("LinkSubElement", QSizeF(px,px));
1733
return BitmapFactory().pixmapFromSvg("LinkSubOverlay", QSizeF(px,px));
1735
return BitmapFactory().pixmapFromSvg("LinkOverlay", QSizeF(px,px));
1738
void ViewProviderLink::onChanged(const App::Property* prop) {
1739
if(prop==&ChildViewProvider) {
1740
childVp = freecad_dynamic_cast<ViewProviderDocumentObject>(ChildViewProvider.getObject().get());
1741
if(childVp && getObject()) {
1742
if(strcmp(childVp->getTypeId().getName(),getObject()->getViewProviderName())!=0
1743
&& !childVp->allowOverride(*getObject()))
1745
FC_ERR("Child view provider type '" << childVp->getTypeId().getName()
1746
<< "' does not support " << getObject()->getFullName());
1748
childVp->setPropertyPrefix("ChildViewProvider.");
1749
childVp->Visibility.setValue(getObject()->Visibility.getValue());
1750
childVp->attach(getObject());
1751
childVp->updateView();
1752
childVp->setActiveMode();
1753
if(pcModeSwitch->getNumChildren()>1){
1754
childVpLink = LinkInfo::get(childVp,nullptr);
1755
pcModeSwitch->replaceChild(1,childVpLink->getSnapshot(LinkView::SnapshotTransform));
1759
}else if(!isRestoring()) {
1760
if (prop == &OverrideMaterial || prop == &ShapeMaterial ||
1761
prop == &MaterialList || prop == &OverrideMaterialList)
1764
}else if(prop == &OverrideColorList) {
1766
}else if(prop==&DrawStyle || prop==&PointSize || prop==&LineWidth) {
1767
if(!DrawStyle.getValue())
1768
linkView->setDrawStyle(0);
1770
linkView->setDrawStyle(DrawStyle.getValue(),LineWidth.getValue(),PointSize.getValue());
1774
inherited::onChanged(prop);
1777
bool ViewProviderLink::setLinkType(App::LinkBaseExtension *ext) {
1778
auto propLink = ext->getLinkedObjectProperty();
1783
type = LinkTypeSubs;
1785
type = LinkTypeNormal;
1786
if(linkType != type)
1790
linkView->setNodeType(ext->linkTransform()?LinkView::SnapshotContainer:
1791
LinkView::SnapshotContainerTransform);
1793
case LinkTypeNormal:
1794
linkView->setNodeType(ext->linkTransform()?LinkView::SnapshotVisible:
1795
LinkView::SnapshotTransform);
1803
App::LinkBaseExtension *ViewProviderLink::getLinkExtension() {
1804
if(!pcObject || !pcObject->isAttachedToDocument())
1806
return pcObject->getExtensionByType<App::LinkBaseExtension>(true);
1809
const App::LinkBaseExtension *ViewProviderLink::getLinkExtension() const{
1810
if(!pcObject || !pcObject->isAttachedToDocument())
1812
return const_cast<App::DocumentObject*>(pcObject)->getExtensionByType<App::LinkBaseExtension>(true);
1815
void ViewProviderLink::updateData(const App::Property *prop) {
1817
childVp->updateData(prop);
1818
if(!isRestoring() && !pcObject->isRestoring()) {
1819
auto ext = getLinkExtension();
1820
if(ext) updateDataPrivate(getLinkExtension(),prop);
1822
return inherited::updateData(prop);
1825
static inline bool canScale(const Base::Vector3d &v) {
1826
return fabs(v.x)>1e-7 && fabs(v.y)>1e-7 && fabs(v.z)>1e-7;
1829
void ViewProviderLink::updateDataPrivate(App::LinkBaseExtension *ext, const App::Property *prop) {
1832
if(prop == &ext->_ChildCache) {
1833
updateElementList(ext);
1834
} else if(prop == &ext->_LinkTouched) {
1835
if(linkView->hasSubs())
1836
linkView->updateLink();
1839
}else if(prop==ext->getColoredElementsProperty()) {
1840
if(!prop->testStatus(App::Property::User3))
1842
}else if(prop==ext->getScaleProperty() || prop==ext->getScaleVectorProperty()) {
1843
if(!prop->testStatus(App::Property::User3)) {
1844
const auto &v = ext->getScaleVector();
1846
pcTransform->scaleFactor.setValue(v.x,v.y,v.z);
1847
SbMatrix matrix = convert(ext->getTransform(false));
1848
linkView->renderDoubleSide(matrix.det3() < 1e-7);
1850
}else if(prop == ext->getPlacementProperty() || prop == ext->getLinkPlacementProperty()) {
1851
auto propLinkPlacement = ext->getLinkPlacementProperty();
1852
if(!propLinkPlacement || propLinkPlacement == prop) {
1853
const auto &pla = static_cast<const App::PropertyPlacement*>(prop)->getValue();
1854
ViewProviderGeometryObject::updateTransform(pla, pcTransform);
1855
const auto &v = ext->getScaleVector();
1857
pcTransform->scaleFactor.setValue(v.x,v.y,v.z);
1858
SbMatrix matrix = convert(ext->getTransform(false));
1859
linkView->renderDoubleSide(matrix.det3() < 1e-7);
1861
}else if(prop == ext->getLinkCopyOnChangeGroupProperty()) {
1862
if (auto group = ext->getLinkCopyOnChangeGroupValue()) {
1863
auto vp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
1864
Application::Instance->getViewProvider(group));
1867
vp->ShowInTree.setValue(false);
1870
}else if(prop == ext->getLinkedObjectProperty()) {
1872
if(!prop->testStatus(App::Property::User3)) {
1873
std::vector<std::string> subs;
1874
const char *subname = ext->getSubName();
1878
hasSubElement = false;
1879
for(const auto &s : ext->getSubElements()) {
1880
if(s.empty()) continue;
1881
hasSubElement = true;
1882
subs.push_back(sub+s);
1885
if(subs.empty() && !sub.empty())
1886
subs.push_back(sub);
1888
hasSubName = !subs.empty();
1891
auto obj = ext->getLinkedObjectValue();
1892
linkView->setLink(obj,subs);
1894
if(ext->_getShowElementValue())
1895
updateElementList(ext);
1897
updateDataPrivate(ext,ext->_getElementCountProperty());
1902
}else if(prop == ext->getLinkTransformProperty()) {
1905
}else if(prop==ext->_getElementCountProperty()) {
1906
if(!ext->_getShowElementValue()) {
1907
linkView->setSize(ext->_getElementCountValue());
1908
updateDataPrivate(ext,ext->getVisibilityListProperty());
1909
updateDataPrivate(ext,ext->getPlacementListProperty());
1911
}else if(prop == ext->_getShowElementProperty()) {
1912
if(!ext->_getShowElementValue()) {
1914
auto linked = freecad_dynamic_cast<ViewProviderDocumentObject>(getLinkedView(true,ext));
1915
if(linked && linked->getDocument()==getDocument())
1918
const auto &elements = ext->_getElementListValue();
1920
if(!elements.empty()) {
1921
std::vector<App::Material> materials;
1922
boost::dynamic_bitset<> overrideMaterials;
1923
overrideMaterials.resize(elements.size(),false);
1924
bool overrideMaterial = false;
1925
bool hasMaterial = false;
1926
materials.reserve(elements.size());
1927
for(size_t i=0;i<elements.size();++i) {
1928
auto element = freecad_dynamic_cast<App::LinkElement>(elements[i]);
1929
if(!element) continue;
1930
auto vp = freecad_dynamic_cast<ViewProviderLink>(
1931
Application::Instance->getViewProvider(element));
1933
overrideMaterial = overrideMaterial || vp->OverrideMaterial.getValue();
1934
hasMaterial = overrideMaterial || hasMaterial
1935
|| vp->ShapeMaterial.getValue()!=ShapeMaterial.getValue();
1936
materials.push_back(vp->ShapeMaterial.getValue());
1937
overrideMaterials[i] = vp->OverrideMaterial.getValue();
1939
if(!overrideMaterial)
1940
overrideMaterials.clear();
1941
OverrideMaterialList.setStatus(App::Property::User3,true);
1942
OverrideMaterialList.setValue(overrideMaterials);
1943
OverrideMaterialList.setStatus(App::Property::User3,false);
1946
MaterialList.setStatus(App::Property::User3,true);
1947
MaterialList.setValue(materials);
1948
MaterialList.setStatus(App::Property::User3,false);
1950
linkView->setSize(ext->_getElementCountValue());
1951
updateDataPrivate(ext,ext->getVisibilityListProperty());
1956
}else if(prop==ext->getScaleListProperty() || prop==ext->getPlacementListProperty()) {
1957
if(!prop->testStatus(App::Property::User3) &&
1958
linkView->getSize() &&
1959
!ext->_getShowElementValue())
1961
auto propPlacements = ext->getPlacementListProperty();
1962
auto propScales = ext->getScaleListProperty();
1963
if(propPlacements && linkView->getSize()) {
1964
const auto &touched =
1965
prop==propScales?propScales->getTouchList():propPlacements->getTouchList();
1966
if(touched.empty()) {
1967
for(int i=0;i<linkView->getSize();++i) {
1969
if(propPlacements && propPlacements->getSize()>i)
1970
mat = (*propPlacements)[i].toMatrix();
1971
if(propScales && propScales->getSize()>i && canScale((*propScales)[i])) {
1973
s.scale((*propScales)[i]);
1976
linkView->setTransform(i,mat);
1979
for(int i : touched) {
1980
if(i<0 || i>=linkView->getSize())
1983
if(propPlacements && propPlacements->getSize()>i)
1984
mat = (*propPlacements)[i].toMatrix();
1985
if(propScales && propScales->getSize()>i && canScale((*propScales)[i])) {
1987
s.scale((*propScales)[i]);
1990
linkView->setTransform(i,mat);
1995
}else if(prop == ext->getVisibilityListProperty()) {
1996
const auto &vis = ext->getVisibilityListValue();
1997
for(size_t i=0;i<(size_t)linkView->getSize();++i) {
1999
linkView->setElementVisible(i,vis[i]);
2001
linkView->setElementVisible(i,true);
2003
}else if(prop == ext->_getElementListProperty()) {
2004
if(ext->_getShowElementValue())
2005
updateElementList(ext);
2009
void ViewProviderLink::updateElementList(App::LinkBaseExtension *ext) {
2010
const auto &elements = ext->_getElementListValue();
2011
if(OverrideMaterialList.getSize() || MaterialList.getSize()) {
2013
for(auto obj : elements) {
2015
auto vp = freecad_dynamic_cast<ViewProviderLink>(
2016
Application::Instance->getViewProvider(obj));
2018
if(OverrideMaterialList.getSize()>i)
2019
vp->OverrideMaterial.setValue(OverrideMaterialList[i]);
2020
if(MaterialList.getSize()>i)
2021
vp->ShapeMaterial.setValue(MaterialList[i]);
2023
OverrideMaterialList.setSize(0);
2024
MaterialList.setSize(0);
2026
linkView->setChildren(elements, ext->getVisibilityListValue());
2030
void ViewProviderLink::checkIcon(const App::LinkBaseExtension *ext) {
2032
ext = getLinkExtension();
2037
auto element = freecad_dynamic_cast<App::LinkElement>(getObject());
2039
icon = _LinkElementIcon;
2040
else if(!ext->getLinkedObjectProperty() && ext->getElementListProperty())
2041
icon = _LinkGroupIcon;
2046
qint64 cacheKey = 0;
2047
if(getObject()->getLinkedObject(false)!=getObject())
2048
cacheKey = getOverlayPixmap().cacheKey();
2049
if(icon!=sPixmap || cacheKey!=overlayCacheKey) {
2055
void ViewProviderLink::applyMaterial() {
2056
if(OverrideMaterial.getValue())
2057
linkView->setMaterial(-1,&ShapeMaterial.getValue());
2059
for(int i=0;i<linkView->getSize();++i) {
2060
if(MaterialList.getSize()>i &&
2061
OverrideMaterialList.getSize()>i && OverrideMaterialList[i])
2062
linkView->setMaterial(i,&MaterialList[i]);
2064
linkView->setMaterial(i,nullptr);
2066
linkView->setMaterial(-1,nullptr);
2070
void ViewProviderLink::finishRestoring() {
2071
FC_TRACE("finish restoring");
2072
auto ext = getLinkExtension();
2075
linkView->setDrawStyle(DrawStyle.getValue(),LineWidth.getValue(),PointSize.getValue());
2076
updateDataPrivate(ext,ext->getLinkedObjectProperty());
2077
if(ext->getLinkPlacementProperty())
2078
updateDataPrivate(ext,ext->getLinkPlacementProperty());
2080
updateDataPrivate(ext,ext->getPlacementProperty());
2081
updateDataPrivate(ext,ext->_getElementCountProperty());
2082
if(ext->getPlacementListProperty())
2083
updateDataPrivate(ext,ext->getPlacementListProperty());
2085
updateDataPrivate(ext,ext->getScaleListProperty());
2086
updateDataPrivate(ext,ext->_getElementListProperty());
2091
getDocument()->signalChangedObject(*this,ext->_LinkTouched);
2094
childVp->finishRestoring();
2097
bool ViewProviderLink::hasElements(const App::LinkBaseExtension *ext) const {
2099
ext = getLinkExtension();
2103
const auto &elements = ext->getElementListValue();
2104
return !elements.empty() && (int)elements.size()==ext->_getElementCountValue();
2107
bool ViewProviderLink::isGroup(const App::LinkBaseExtension *ext, bool plainGroup) const {
2109
ext = getLinkExtension();
2113
return (plainGroup && ext->linkedPlainGroup())
2114
|| (ext->getElementListProperty() && !ext->getLinkedObjectProperty());
2117
ViewProvider *ViewProviderLink::getLinkedView(
2118
bool real,const App::LinkBaseExtension *ext) const
2121
ext = getLinkExtension();
2122
auto obj = ext&&real?ext->getTrueLinkedObject(true):
2123
getObject()->getLinkedObject(true);
2124
if(obj && obj!=getObject())
2125
return Application::Instance->getViewProvider(obj);
2129
std::vector<App::DocumentObject*> ViewProviderLink::claimChildren() const {
2130
auto ext = getLinkExtension();
2131
std::vector<App::DocumentObject*> ret;
2133
if(ext && !ext->_getShowElementValue() && ext->_getElementCountValue()) {
2138
auto obj = ext->getLinkedObjectValue();
2139
if(obj) ret.push_back(obj);
2141
} else if(hasElements(ext) || isGroup(ext)) {
2142
ret = ext->getElementListValue();
2143
if (ext->_getElementCountValue()
2144
&& ext->getLinkClaimChildValue()
2145
&& ext->getLinkedObjectValue())
2146
ret.insert(ret.begin(), ext->getLinkedObjectValue());
2147
} else if(!hasSubName) {
2148
auto linked = getLinkedView(true);
2150
ret = linked->claimChildren();
2151
if (ext->getLinkClaimChildValue() && ext->getLinkedObjectValue())
2152
ret.insert(ret.begin(), ext->getLinkedObjectValue());
2155
if (ext && ext->getLinkCopyOnChangeGroupValue())
2156
ret.insert(ret.begin(), ext->getLinkCopyOnChangeGroupValue());
2160
bool ViewProviderLink::canDragObject(App::DocumentObject* obj) const {
2161
auto ext = getLinkExtension();
2164
if(hasElements(ext))
2166
auto linked = getLinkedView(false,ext);
2168
return linked->canDragObject(obj);
2172
bool ViewProviderLink::canDragObjects() const {
2173
auto ext = getLinkExtension();
2176
if(hasElements(ext))
2178
auto linked = getLinkedView(false,ext);
2180
return linked->canDragObjects();
2184
void ViewProviderLink::dragObject(App::DocumentObject* obj) {
2185
auto ext = getLinkExtension();
2187
const auto &objs = ext->getElementListValue();
2188
for(size_t i=0;i<objs.size();++i) {
2190
ext->setLink(i,nullptr);
2196
if(hasElements(ext))
2198
auto linked = getLinkedView(false);
2200
linked->dragObject(obj);
2203
bool ViewProviderLink::canDropObjects() const {
2204
auto ext = getLinkExtension();
2207
if(hasElements(ext))
2213
auto linked = getLinkedView(false,ext);
2215
return linked->canDropObjects();
2219
bool ViewProviderLink::canDropObjectEx(App::DocumentObject *obj,
2220
App::DocumentObject *owner, const char *subname,
2221
const std::vector<std::string> &subElements) const
2223
if(pcObject == obj || pcObject == owner)
2225
auto ext = getLinkExtension();
2228
if(!ext || !ext->getLinkedObjectProperty() || hasElements(ext))
2230
if(!hasSubName && linkView->isLinked()) {
2231
auto linked = getLinkedView(false,ext);
2233
auto linkedVdp = freecad_dynamic_cast<ViewProviderDocumentObject>(linked);
2235
if(linkedVdp->getObject()==obj || linkedVdp->getObject()==owner)
2238
return linked->canDropObjectEx(obj,owner,subname,subElements);
2241
if(obj->getDocument() != getObject()->getDocument() &&
2242
!freecad_dynamic_cast<App::PropertyXLink>(ext->getLinkedObjectProperty()))
2248
std::string ViewProviderLink::dropObjectEx(App::DocumentObject* obj,
2249
App::DocumentObject *owner, const char *subname,
2250
const std::vector<std::string> &subElements)
2252
auto ext = getLinkExtension();
2254
return std::string();
2257
size_t size = ext->getElementListValue().size();
2258
ext->setLink(size,obj);
2259
return std::to_string(size)+".";
2262
if(!ext->getLinkedObjectProperty() || hasElements(ext))
2263
return std::string();
2266
auto linked = getLinkedView(false,ext);
2268
return linked->dropObjectEx(obj,owner,subname,subElements);
2271
if(!ext->getSubElements().empty())
2272
ext->setLink(-1,owner,subname,subElements);
2274
ext->setLink(-1,owner,subname);
2275
} else if(!ext->getSubElements().empty())
2276
ext->setLink(-1,obj,nullptr,subElements);
2278
ext->setLink(-1,obj,nullptr);
2279
return std::string();
2282
bool ViewProviderLink::canDragAndDropObject(App::DocumentObject* obj) const {
2283
auto ext = getLinkExtension();
2287
return ext->getLinkModeValue()<App::LinkBaseExtension::LinkModeAutoLink &&
2288
obj->getDocument()==getObject()->getDocument();
2290
if(!ext->getLinkedObjectProperty() || hasElements(ext))
2293
auto linked = getLinkedView(false,ext);
2295
return linked->canDragAndDropObject(obj);
2300
bool ViewProviderLink::getElementPicked(const SoPickedPoint *pp, std::string &subname) const {
2301
if(!isSelectable()) {
2304
auto ext = getLinkExtension();
2308
if(childVpLink && childVp) {
2309
auto path = pp->getPath();
2310
int idx = path->findNode(childVpLink->getSnapshot(LinkView::SnapshotTransform));
2312
return childVp->getElementPicked(pp, subname);
2315
bool ret = linkView->linkGetElementPicked(pp,subname);
2319
if(isGroup(ext,true)) {
2320
const char *sub = nullptr;
2321
int idx = App::LinkBaseExtension::getArrayIndex(subname.c_str(),&sub);
2324
assert(*sub == '.');
2325
const auto &elements = ext->_getElementListValue();
2326
subname.replace(0,sub-subname.c_str(),elements[idx]->getNameInDocument());
2332
bool ViewProviderLink::getDetailPath(
2333
const char *subname, SoFullPath *pPath, bool append, SoDetail *&det) const
2335
auto ext = getLinkExtension();
2339
auto len = pPath->getLength();
2341
appendPath(pPath,pcRoot);
2342
appendPath(pPath,pcModeSwitch);
2344
if(childVpLink && getDefaultMode()==1) {
2345
if(childVpLink->getDetail(false,LinkView::SnapshotTransform,subname,det,pPath))
2347
pPath->truncate(len);
2350
std::string _subname;
2351
if(subname && subname[0]) {
2352
if (auto linked = ext->getLinkedObjectValue()) {
2353
if (const char *dot = strchr(subname,'.')) {
2354
if(subname[0]=='$') {
2355
CharRange sub(subname+1, dot);
2356
if (!boost::equals(sub, linked->Label.getValue()))
2359
CharRange sub(subname, dot);
2360
if (!boost::equals(sub, linked->getNameInDocument()))
2363
if (dot && linked->getSubObject(dot+1))
2368
if (isGroup(ext,true) || hasElements(ext) || ext->getElementCountValue()) {
2369
int index = ext->getElementIndex(subname,&subname);
2371
_subname = std::to_string(index)+'.'+subname;
2372
subname = _subname.c_str();
2376
if(linkView->linkGetDetailPath(subname,pPath,det))
2378
pPath->truncate(len);
2382
bool ViewProviderLink::onDelete(const std::vector<std::string> &) {
2383
auto element = freecad_dynamic_cast<App::LinkElement>(getObject());
2384
if (element && !element->canDelete())
2386
auto ext = getLinkExtension();
2387
if (ext->isLinkMutated()) {
2388
auto linked = ext->getLinkedObjectValue();
2389
auto doc = ext->getContainer()->getDocument();
2390
if (linked->getDocument() == doc) {
2391
std::deque<std::string> objs;
2392
for (auto obj : ext->getOnChangeCopyObjects(nullptr, linked)) {
2393
if (obj->getDocument() == doc) {
2397
objs.emplace_front(obj->getNameInDocument());
2400
for (const auto &name : objs)
2401
doc->removeObject(name.c_str());
2407
bool ViewProviderLink::canDelete(App::DocumentObject *obj) const {
2408
auto ext = getLinkExtension();
2409
if(isGroup(ext) || hasElements(ext) || hasSubElement)
2411
auto linked = getLinkedView(false,ext);
2413
return linked->canDelete(obj);
2417
bool ViewProviderLink::linkEdit(const App::LinkBaseExtension *ext) const {
2419
ext = getLinkExtension();
2421
(!ext->_getShowElementValue() && ext->_getElementCountValue()) ||
2428
return linkView->isLinked();
2431
bool ViewProviderLink::doubleClicked() {
2433
return linkView->getLinkedView()->doubleClicked();
2434
return getDocument()->setEdit(this,ViewProvider::Transform);
2437
void ViewProviderLink::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
2439
auto ext = getLinkExtension();
2443
_setupContextMenu(ext, menu, receiver, member);
2444
Gui::ActionFunction* func = nullptr;
2446
if (ext->isLinkedToConfigurableObject()) {
2447
auto src = ext->getLinkCopyOnChangeSourceValue();
2448
if (!src) src = ext->getLinkedObjectValue();
2449
if (src && !ext->getOnChangeCopyObjects(nullptr, src).empty()) {
2450
QAction *act = menu->addAction(
2451
QObject::tr("Setup configurable object"));
2452
act->setToolTip(QObject::tr(
2453
"Select which object to copy or exclude when configuration changes. "
2454
"All external linked objects are excluded by default."));
2456
if (!func) func = new Gui::ActionFunction(menu);
2457
func->trigger(act, [ext](){
2459
std::vector<App::DocumentObject*> excludes;
2460
auto src = ext->getLinkCopyOnChangeSourceValue();
2462
src = ext->getLinkedObjectValue();
2463
auto objs = ext->getOnChangeCopyObjects(&excludes, src);
2466
DlgObjectSelection dlg({src}, excludes, getMainWindow());
2467
dlg.setMessage(QObject::tr(
2468
"Please select which objects to copy when the configuration is changed"));
2469
auto box = new QCheckBox(QObject::tr("Apply to all"), &dlg);
2470
box->setToolTip(QObject::tr("Apply the setting to all links. Or, uncheck this\n"
2471
"option to apply only to this link."));
2472
box->setChecked(App::LinkParams::getCopyOnChangeApplyToAll());
2473
dlg.addCheckBox(box);
2474
if(dlg.exec()!=QDialog::Accepted)
2477
bool applyAll = box->isChecked();
2478
App::LinkParams::setCopyOnChangeApplyToAll(applyAll);
2480
App::Link::OnChangeCopyOptions options {App::Link::OnChangeCopyOptions::None};
2482
options |= App::Link::OnChangeCopyOptions::ApplyAll;
2484
App::AutoTransaction guard("Setup configurable object");
2485
auto sels = dlg.getSelections(DlgObjectSelection::SelectionOptions::InvertSort);
2486
for (const auto & exclude : excludes) {
2487
auto iter = std::lower_bound(sels.begin(), sels.end(), exclude);
2488
if (iter == sels.end() || *iter != exclude) {
2489
ext->setOnChangeCopyObject(exclude, options);
2493
options |= App::Link::OnChangeCopyOptions::Exclude;
2494
for (auto obj : sels)
2495
ext->setOnChangeCopyObject(obj, options);
2497
ext->monitorOnChangeCopyObjects(ext->getOnChangeCopyObjects());
2499
std::set<App::LinkBaseExtension*> exts;
2500
for (auto o : App::Document::getDependencyList(objs)) {
2501
if (auto ext = o->getExtensionByType<App::LinkBaseExtension>(true))
2504
for (auto ext : exts)
2505
ext->monitorOnChangeCopyObjects(ext->getOnChangeCopyObjects());
2507
Command::updateActive();
2508
} catch (Base::Exception &e) {
2509
e.ReportException();
2514
if (ext->getLinkCopyOnChangeValue() == 0) {
2515
auto submenu = menu->addMenu(QObject::tr("Copy on change"));
2516
auto act = submenu->addAction(QObject::tr("Enable"));
2517
act->setToolTip(QObject::tr(
2518
"Enable auto copy of linked object when its configuration is changed"));
2520
if (!func) func = new Gui::ActionFunction(menu);
2521
func->trigger(act, [ext](){
2523
App::AutoTransaction guard("Enable Link copy on change");
2524
ext->getLinkCopyOnChangeProperty()->setValue(1);
2525
Command::updateActive();
2526
} catch (Base::Exception &e) {
2527
e.ReportException();
2530
act = submenu->addAction(QObject::tr("Tracking"));
2531
act->setToolTip(QObject::tr(
2532
"Copy the linked object when its configuration is changed.\n"
2533
"Also auto redo the copy if the original linked object is changed.\n"));
2535
func->trigger(act, [ext](){
2537
App::AutoTransaction guard("Enable Link tracking");
2538
ext->getLinkCopyOnChangeProperty()->setValue(3);
2539
Command::updateActive();
2540
} catch (Base::Exception &e) {
2541
e.ReportException();
2547
if (ext->getLinkCopyOnChangeValue() != 2
2548
&& ext->getLinkCopyOnChangeValue() != 0) {
2549
QAction *act = menu->addAction(
2550
QObject::tr("Disable copy on change"));
2552
if (!func) func = new Gui::ActionFunction(menu);
2553
func->trigger(act, [ext](){
2555
App::AutoTransaction guard("Disable copy on change");
2556
ext->getLinkCopyOnChangeProperty()->setValue((long)0);
2557
Command::updateActive();
2558
} catch (Base::Exception &e) {
2559
e.ReportException();
2564
if (ext->isLinkMutated()) {
2565
QAction* act = menu->addAction(QObject::tr("Refresh configurable object"));
2566
act->setToolTip(QObject::tr(
2567
"Synchronize the original configurable source object by\n"
2568
"creating a new deep copy. Note that any changes made to\n"
2569
"the current copy will be lost.\n"));
2571
if (!func) func = new Gui::ActionFunction(menu);
2572
func->trigger(act, [ext](){
2574
App::AutoTransaction guard("Link refresh");
2575
ext->syncCopyOnChange();
2576
Command::updateActive();
2577
} catch (Base::Exception &e) {
2578
e.ReportException();
2584
void ViewProviderLink::_setupContextMenu(
2585
App::LinkBaseExtension *ext, QMenu* menu, QObject* receiver, const char* member)
2588
if (auto linkvp = Base::freecad_dynamic_cast<ViewProviderLink>(linkView->getLinkedView()))
2589
linkvp->_setupContextMenu(ext, menu, receiver, member);
2591
linkView->getLinkedView()->setupContextMenu(menu,receiver,member);
2594
if(ext->getLinkedObjectProperty()
2595
&& ext->_getShowElementProperty()
2596
&& ext->_getElementCountValue() > 1)
2598
auto action = menu->addAction(QObject::tr("Toggle array elements"), [ext] {
2600
App::AutoTransaction guard(QT_TRANSLATE_NOOP("Command", "Toggle array elements"));
2601
ext->getShowElementProperty()->setValue(!ext->getShowElementValue());
2602
Command::updateActive();
2603
} catch (Base::Exception &e) {
2604
e.ReportException();
2607
action->setToolTip(QObject::tr(
2608
"Change whether show each link array element as individual objects"));
2611
if((ext->getPlacementProperty() && !ext->getPlacementProperty()->isReadOnly())
2612
|| (ext->getLinkPlacementProperty() && !ext->getLinkPlacementProperty()->isReadOnly()))
2615
const auto actions = menu->actions();
2616
for(auto action : actions) {
2617
if(action->data().toInt() == ViewProvider::Transform) {
2623
QIcon iconObject = mergeGreyableOverlayIcons(Gui::BitmapFactory().pixmap("Std_TransformManip.svg"));
2624
QAction* act = menu->addAction(iconObject, QObject::tr("Transform"), receiver, member);
2625
act->setToolTip(QObject::tr("Transform at the origin of the placement"));
2626
act->setData(QVariant((int)ViewProvider::Transform));
2630
if(ext->getColoredElementsProperty()) {
2632
const auto actions = menu->actions();
2633
for(auto action : actions) {
2634
if(action->data().toInt() == ViewProvider::Color) {
2635
action->setText(QObject::tr("Override colors..."));
2641
QAction* act = menu->addAction(QObject::tr("Override colors..."), receiver, member);
2642
act->setData(QVariant((int)ViewProvider::Color));
2646
auto cmd = Application::Instance->commandManager().getCommandByName("Std_LinkSelectLinked");
2647
menu->addAction(cmd->getAction()->action());
2650
bool ViewProviderLink::initDraggingPlacement() {
2651
Base::PyGILStateLocker lock;
2653
auto* proxy = getPropertyByName("Proxy");
2654
if (proxy && proxy->is<App::PropertyPythonObject>()) {
2655
Py::Object feature = static_cast<App::PropertyPythonObject*>(proxy)->getValue();
2656
const char *fname = "initDraggingPlacement";
2657
if (feature.hasAttr(fname)) {
2658
Py::Callable method(feature.getAttr(fname));
2660
Py::Object ret(method.apply(arg));
2662
PyObject *pymat,*pypla,*pybbox;
2663
if(!PyArg_ParseTuple(ret.ptr(),"O!O!O!",&Base::MatrixPy::Type, &pymat,
2664
&Base::PlacementPy::Type, &pypla,
2665
&Base::BoundBoxPy::Type, &pybbox)) {
2666
FC_ERR("initDraggingPlacement() expects return of type tuple(matrix,placement,boundbox)");
2669
dragCtx = std::make_unique<DraggerContext>();
2670
dragCtx->initialPlacement = *static_cast<Base::PlacementPy*>(pypla)->getPlacementPtr();
2671
dragCtx->preTransform = *static_cast<Base::MatrixPy*>(pymat)->getMatrixPtr();
2672
dragCtx->bbox = *static_cast<Base::BoundBoxPy*>(pybbox)->getBoundBoxPtr();
2674
}else if(!ret.isTrue())
2678
} catch (Py::Exception&) {
2679
Base::PyException e;
2680
e.ReportException();
2684
auto ext = getLinkExtension();
2686
FC_ERR("no link extension");
2689
if(!ext->hasPlacement()) {
2690
FC_ERR("no placement");
2693
auto doc = Application::Instance->editDocument();
2695
FC_ERR("no editing document");
2699
dragCtx = std::make_unique<DraggerContext>();
2701
dragCtx->preTransform = doc->getEditingTransform();
2702
doc->setEditingTransform(dragCtx->preTransform);
2704
const auto &pla = ext->getPlacementProperty()?
2705
ext->getPlacementValue():ext->getLinkPlacementValue();
2709
dragCtx->preTransform *= pla.inverse().toMatrix();
2711
dragCtx->bbox = getBoundingBox(nullptr,false);
2714
auto scale = ext->getScaleVector();
2715
dragCtx->bbox.ScaleX(scale.x);
2716
dragCtx->bbox.ScaleY(scale.y);
2717
dragCtx->bbox.ScaleZ(scale.z);
2719
auto modifier = QApplication::queryKeyboardModifiers();
2725
if(modifier != Qt::ShiftModifier
2726
&& ((ext->getLinkedObjectValue() && !linkView->hasSubs())
2727
|| modifier == Qt::ControlModifier))
2729
App::PropertyPlacement *propPla = nullptr;
2730
if(ext->getLinkTransformValue() && ext->getLinkedObjectValue()) {
2731
propPla = Base::freecad_dynamic_cast<App::PropertyPlacement>(
2732
ext->getLinkedObjectValue()->getPropertyByName("Placement"));
2735
dragCtx->initialPlacement = pla * propPla->getValue();
2736
dragCtx->mat *= propPla->getValue().inverse().toMatrix();
2738
dragCtx->initialPlacement = pla;
2741
auto offset = dragCtx->bbox.GetCenter();
2745
dragCtx->initialPlacement = pla * Base::Placement(offset, Base::Rotation());
2750
dragCtx->mat.move(Vector3d() - offset);
2756
ViewProvider *ViewProviderLink::startEditing(int mode) {
2757
if(mode==ViewProvider::Color) {
2758
auto ext = getLinkExtension();
2759
if(!ext || !ext->getColoredElementsProperty()) {
2761
return linkView->getLinkedView()->startEditing(mode);
2763
return inherited::startEditing(mode);
2766
static thread_local bool _pendingTransform;
2767
static thread_local Base::Matrix4D _editingTransform;
2769
auto doc = Application::Instance->editDocument();
2771
if(mode==ViewProvider::Transform) {
2772
if(_pendingTransform && doc)
2773
doc->setEditingTransform(_editingTransform);
2775
if(!initDraggingPlacement())
2777
if(useCenterballDragger)
2778
pcDragger = CoinPtr<SoCenterballDragger>(new SoCenterballDragger);
2780
pcDragger = CoinPtr<SoFCCSysDragger>(new SoFCCSysDragger);
2781
updateDraggingPlacement(dragCtx->initialPlacement,true);
2782
pcDragger->addStartCallback(dragStartCallback, this);
2783
pcDragger->addFinishCallback(dragFinishCallback, this);
2784
pcDragger->addMotionCallback(dragMotionCallback, this);
2785
return inherited::startEditing(mode);
2789
FC_ERR("unsupported edit mode " << mode);
2801
FC_ERR("no editing document");
2808
auto linked = getObject()->getLinkedObject(true,&mat,false);
2809
if(!linked || linked==getObject()) {
2810
FC_ERR("no linked object");
2813
auto vpd = freecad_dynamic_cast<ViewProviderDocumentObject>(
2814
Application::Instance->getViewProvider(linked));
2816
FC_ERR("no linked viewprovider");
2822
_editingTransform = doc->getEditingTransform();
2823
doc->setEditingTransform(doc->getEditingTransform()*mat);
2824
Base::FlagToggler<> guard(_pendingTransform);
2825
return vpd->startEditing(mode);
2828
bool ViewProviderLink::setEdit(int ModNum)
2830
if (ModNum == ViewProvider::Color) {
2831
auto ext = getLinkExtension();
2832
if(!ext || !ext->getColoredElementsProperty())
2834
TaskView::TaskDialog *dlg = Control().activeDialog();
2836
Control().showDialog(dlg);
2839
Selection().clearSelection();
2842
return inherited::setEdit(ModNum);
2845
void ViewProviderLink::setEditViewer(Gui::View3DInventorViewer* viewer, int ModNum)
2847
if (ModNum == ViewProvider::Color) {
2848
Gui::Control().showDialog(new TaskElementColors(this));
2852
if (pcDragger && viewer)
2854
auto rootPickStyle = new SoPickStyle();
2855
rootPickStyle->style = SoPickStyle::UNPICKABLE;
2856
static_cast<SoFCUnifiedSelection*>(
2857
viewer->getSceneGraph())->insertChild(rootPickStyle, 0);
2859
if(useCenterballDragger) {
2860
auto dragger = static_cast<SoCenterballDragger*>(pcDragger.get());
2861
auto group = new SoAnnotation;
2862
auto pickStyle = new SoPickStyle;
2863
pickStyle->setOverride(true);
2864
group->addChild(pickStyle);
2865
group->addChild(pcDragger);
2871
auto * ss = static_cast<SoSurroundScale*>(dragger->getPart("surroundScale", TRUE));
2872
ss->numNodesUpToContainer = 3;
2873
ss->numNodesUpToReset = 2;
2875
auto *geoGroup = new SoGroup;
2876
group->addChild(geoGroup);
2877
auto *style = new SoDrawStyle;
2878
style->style.setValue(SoDrawStyle::INVISIBLE);
2879
style->setOverride(TRUE);
2880
geoGroup->addChild(style);
2881
auto *cube = new SoCube;
2882
geoGroup->addChild(cube);
2883
auto length = std::max(std::max(dragCtx->bbox.LengthX(),
2884
dragCtx->bbox.LengthY()), dragCtx->bbox.LengthZ());
2885
cube->width = length;
2886
cube->height = length;
2887
cube->depth = length;
2889
viewer->setupEditingRoot(group,&dragCtx->preTransform);
2891
auto dragger = static_cast<SoFCCSysDragger*>(pcDragger.get());
2892
dragger->draggerSize.setValue(ViewParams::instance()->getDraggerScale());
2893
dragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera());
2894
viewer->setupEditingRoot(pcDragger,&dragCtx->preTransform);
2896
auto task = new TaskCSysDragger(this, dragger);
2897
Gui::Control().showDialog(task);
2902
void ViewProviderLink::unsetEditViewer(Gui::View3DInventorViewer* viewer)
2904
SoNode *child = static_cast<SoFCUnifiedSelection*>(viewer->getSceneGraph())->getChild(0);
2905
if (child && child->isOfType(SoPickStyle::getClassTypeId()))
2906
static_cast<SoFCUnifiedSelection*>(viewer->getSceneGraph())->removeChild(child);
2909
Gui::Control().closeDialog();
2912
Base::Placement ViewProviderLink::currentDraggingPlacement() const
2916
return Base::Placement();
2920
if (useCenterballDragger) {
2921
auto dragger = static_cast<SoCenterballDragger*>(pcDragger.get());
2922
v = dragger->center.getValue();
2923
r = dragger->rotation.getValue();
2926
auto dragger = static_cast<SoFCCSysDragger*>(pcDragger.get());
2927
v = dragger->translation.getValue();
2928
r = dragger->rotation.getValue();
2932
r.getValue(q1,q2,q3,q4);
2933
return Base::Placement(Base::Vector3d(v[0],v[1],v[2]),Base::Rotation(q1,q2,q3,q4));
2936
void ViewProviderLink::enableCenterballDragger(bool enable) {
2937
if(enable == useCenterballDragger)
2940
LINK_THROW(Base::RuntimeError,"Cannot change dragger during dragging");
2941
useCenterballDragger = enable;
2944
void ViewProviderLink::updateDraggingPlacement(const Base::Placement &pla, bool force) {
2945
if(pcDragger && (force || currentDraggingPlacement()!=pla)) {
2946
const auto &pos = pla.getPosition();
2947
const auto &rot = pla.getRotation();
2948
FC_LOG("updating dragger placement (" << pos.x << ", " << pos.y << ", " << pos.z << ')');
2949
if(useCenterballDragger) {
2950
auto dragger = static_cast<SoCenterballDragger*>(pcDragger.get());
2951
SbBool wasenabled = dragger->enableValueChangedCallbacks(FALSE);
2953
matrix = convert(pla.toMatrix());
2954
dragger->center.setValue(SbVec3f(0,0,0));
2955
dragger->setMotionMatrix(matrix);
2957
dragger->enableValueChangedCallbacks(TRUE);
2958
dragger->valueChanged();
2961
auto dragger = static_cast<SoFCCSysDragger*>(pcDragger.get());
2962
dragger->translation.setValue(SbVec3f(pos.x,pos.y,pos.z));
2963
dragger->rotation.setValue(rot[0],rot[1],rot[2],rot[3]);
2968
bool ViewProviderLink::callDraggerProxy(const char *fname, bool update) {
2971
Base::PyGILStateLocker lock;
2973
auto* proxy = getPropertyByName("Proxy");
2974
if (proxy && proxy->is<App::PropertyPythonObject>()) {
2975
Py::Object feature = static_cast<App::PropertyPythonObject*>(proxy)->getValue();
2976
if (feature.hasAttr(fname)) {
2977
Py::Callable method(feature.getAttr(fname));
2979
if(method.apply(args).isTrue())
2983
} catch (Py::Exception&) {
2984
Base::PyException e;
2985
e.ReportException();
2990
auto ext = getLinkExtension();
2992
const auto &pla = currentDraggingPlacement();
2993
auto prop = ext->getLinkPlacementProperty();
2995
prop = ext->getPlacementProperty();
2997
auto plaNew = pla * Base::Placement(dragCtx->mat);
2998
if(prop->getValue()!=plaNew)
2999
prop->setValue(plaNew);
3001
updateDraggingPlacement(pla);
3007
void ViewProviderLink::dragStartCallback(void *data, SoDragger *) {
3008
auto me = static_cast<ViewProviderLink*>(data);
3009
me->dragCtx->initialPlacement = me->currentDraggingPlacement();
3010
if(!me->callDraggerProxy("onDragStart",false)) {
3011
me->dragCtx->cmdPending = true;
3012
me->getDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Link Transform"));
3014
me->dragCtx->cmdPending = false;
3017
void ViewProviderLink::dragFinishCallback(void *data, SoDragger *) {
3018
auto me = static_cast<ViewProviderLink*>(data);
3019
me->callDraggerProxy("onDragEnd",true);
3020
if(me->dragCtx->cmdPending) {
3021
if(me->currentDraggingPlacement() == me->dragCtx->initialPlacement)
3022
me->getDocument()->abortCommand();
3024
me->getDocument()->commitCommand();
3028
void ViewProviderLink::dragMotionCallback(void *data, SoDragger *) {
3029
auto me = static_cast<ViewProviderLink*>(data);
3030
me->callDraggerProxy("onDragMotion",true);
3033
void ViewProviderLink::updateLinks(ViewProvider *vp) {
3035
auto ext = vp->getExtensionByType<ViewProviderLinkObserver>(true);
3036
if (ext && ext->linkInfo)
3037
ext->linkInfo->update();
3039
catch (const Base::TypeError &e) {
3040
e.ReportException();
3042
catch (const Base::ValueError &e) {
3043
e.ReportException();
3047
PyObject *ViewProviderLink::getPyObject() {
3049
pyViewObject = new ViewProviderLinkPy(this);
3050
pyViewObject->IncRef();
3051
return pyViewObject;
3054
PyObject *ViewProviderLink::getPyLinkView() {
3055
return linkView->getPyObject();
3058
std::map<std::string, App::Color> ViewProviderLink::getElementColors(const char *subname) const {
3059
bool isPrefix = true;
3063
auto len = strlen(subname);
3064
isPrefix = !len || subname[len-1]=='.';
3066
std::map<std::string, App::Color> colors;
3067
auto ext = getLinkExtension();
3068
if(!ext || ! ext->getColoredElementsProperty())
3070
const auto &subs = ext->getColoredElementsProperty()->getShadowSubs();
3071
int size = OverrideColorList.getSize();
3073
std::string wildcard(subname);
3074
if(wildcard == "Face" || wildcard == "Face*" || wildcard.empty()) {
3075
if(wildcard.size()==4 || OverrideMaterial.getValue()) {
3076
App::Color c = ShapeMaterial.getValue().diffuseColor;
3077
c.a = ShapeMaterial.getValue().transparency;
3079
if(wildcard.size()==4)
3082
if(!wildcard.empty())
3084
}else if(wildcard == "Edge*")
3086
else if(wildcard == "Vertex*")
3088
else if(wildcard == ViewProvider::hiddenMarker()+"*")
3089
wildcard.resize(ViewProvider::hiddenMarker().size());
3094
if(!wildcard.empty()) {
3095
for(const auto &sub : subs) {
3098
auto pos = sub.oldName.rfind('.');
3099
if(pos == std::string::npos)
3103
const char *element = sub.oldName.c_str()+pos;
3104
if(boost::starts_with(element,wildcard))
3105
colors[sub.oldName] = OverrideColorList[i];
3106
else if(!element[0] && wildcard=="Face")
3107
colors[sub.oldName.substr(0,element-sub.oldName.c_str())+wildcard] = OverrideColorList[i];
3114
if(wildcard!=ViewProvider::hiddenMarker() && vp->OverrideMaterial.getValue()) {
3115
auto color = ShapeMaterial.getValue().diffuseColor;
3116
color.a = ShapeMaterial.getValue().transparency;
3117
colors.emplace(wildcard,color);
3119
auto link = vp->getObject()->getLinkedObject(false);
3120
if(!link || link==vp->getObject())
3122
auto next = freecad_dynamic_cast<ViewProviderLink>(
3123
Application::Instance->getViewProvider(link));
3126
for(const auto &v : next->getElementColors(subname))
3130
if(wildcard!=ViewProvider::hiddenMarker()) {
3132
auto ext = vp->getLinkExtension();
3133
if(ext->_getElementCountValue() && !ext->_getShowElementValue()) {
3134
const auto &overrides = vp->OverrideMaterialList.getValues();
3136
for(const auto &mat : vp->MaterialList.getValues()) {
3137
if(++i>=(int)overrides.size())
3141
auto color = mat.diffuseColor;
3142
color.a = mat.transparency;
3143
colors.emplace(std::to_string(i)+"."+wildcard,color);
3150
int element_count = ext->getElementCountValue();
3152
for(const auto &sub : subs) {
3158
if(!sub.oldName.empty() && element_count && !std::isdigit(sub.oldName[0])) {
3161
std::ostringstream ss;
3162
ss << "0." << sub.oldName;
3163
if(getObject()->getSubObject(ss.str().c_str())) {
3164
for(int j=0;j<element_count;++j) {
3166
ss << j << '.' << sub.oldName;
3167
colors.emplace(ss.str(),OverrideColorList[i]);
3171
} else if (std::isdigit(subname[0])) {
3172
const char *dot = strchr(subname,'.');
3174
offset = dot-subname+1;
3179
if(!boost::starts_with(sub.newName,subname+offset)
3180
&& !boost::starts_with(sub.oldName,subname+offset))
3182
}else if(sub.newName!=subname+offset && sub.oldName!=subname+offset)
3186
colors.emplace(std::string(subname,offset)+sub.oldName, OverrideColorList[i]);
3188
colors[sub.oldName] = OverrideColorList[i];
3195
if(colors.empty()) {
3197
colors.emplace(subname,App::Color());
3199
std::map<std::string, App::Color> ret;
3200
for(const auto &v : colors) {
3201
const char *pos = nullptr;
3202
auto sobj = getObject()->resolve(v.first.c_str(),nullptr,nullptr,&pos);
3205
auto link = sobj->getLinkedObject(true);
3206
if(!link || link==getObject())
3208
auto vp = Application::Instance->getViewProvider(sobj->getLinkedObject(true));
3211
for(const auto &v2 : vp->getElementColors(!pos[0]?"Face":pos)) {
3214
name = v.first.substr(0,pos-v.first.c_str())+v2.first;
3217
ret[name] = found?v.second:v2.second;
3223
void ViewProviderLink::setElementColors(const std::map<std::string, App::Color> &colorMap) {
3224
auto ext = getLinkExtension();
3225
if(!ext || ! ext->getColoredElementsProperty())
3229
std::map<std::string,std::map<int,App::Color> > subMap;
3230
int element_count = ext->getElementCountValue();
3232
std::vector<std::string> subs;
3233
std::vector<App::Color> colors;
3234
App::Color faceColor;
3235
bool hasFaceColor = false;
3236
for(const auto &v : colorMap) {
3237
if(!hasFaceColor && v.first == "Face") {
3238
hasFaceColor = true;
3239
faceColor = v.second;
3243
if(element_count && !v.first.empty() && std::isdigit(v.first[0])) {
3247
const char *dot = strchr(v.first.c_str(),'.');
3249
subMap[dot+1][std::atoi(v.first.c_str())] = v.second;
3253
subs.push_back(v.first);
3254
colors.push_back(v.second);
3256
for(auto &v : subMap) {
3257
if(element_count == (int)v.second.size()) {
3258
App::Color firstColor = v.second.begin()->second;
3259
subs.push_back(v.first);
3260
colors.push_back(firstColor);
3261
for(auto it=v.second.begin();it!=v.second.end();) {
3262
if(it->second==firstColor)
3263
it = v.second.erase(it);
3268
std::ostringstream ss;
3269
for(const auto &colorInfo : v.second) {
3271
ss << colorInfo.first << '.' << v.first;
3272
subs.push_back(ss.str());
3273
colors.push_back(colorInfo.second);
3277
auto prop = ext->getColoredElementsProperty();
3278
if(subs!=prop->getSubValues() || colors!=OverrideColorList.getValues()) {
3279
prop->setStatus(App::Property::User3,true);
3280
prop->setValue(getObject(),subs);
3281
prop->setStatus(App::Property::User3,false);
3282
OverrideColorList.setValues(colors);
3285
auto mat = ShapeMaterial.getValue();
3286
mat.diffuseColor = faceColor;
3287
mat.transparency = faceColor.a;
3288
ShapeMaterial.setStatus(App::Property::User3,true);
3289
ShapeMaterial.setValue(mat);
3290
ShapeMaterial.setStatus(App::Property::User3,false);
3292
OverrideMaterial.setValue(hasFaceColor);
3295
void ViewProviderLink::applyColors() {
3296
auto ext = getLinkExtension();
3297
if(!ext || ! ext->getColoredElementsProperty())
3300
SoSelectionElementAction action(SoSelectionElementAction::Color,true);
3302
action.apply(linkView->getLinkRoot());
3304
std::map<std::string, std::map<std::string,App::Color> > colorMap;
3305
std::set<std::string> hideList;
3306
auto colors = getElementColors();
3307
colors.erase("Face");
3308
for(const auto &v : colors) {
3309
const char *subname = v.first.c_str();
3310
const char *element = nullptr;
3311
auto sobj = getObject()->resolve(subname,nullptr,nullptr,&element);
3312
if(!sobj || !element)
3314
if(ViewProvider::hiddenMarker() == element)
3315
hideList.emplace(subname,element-subname);
3317
colorMap[std::string(subname,element-subname)][element] = v.second;
3320
SoTempPath path(10);
3322
for(auto &v : colorMap) {
3323
action.swapColors(v.second);
3324
if(v.first.empty()) {
3325
action.apply(linkView->getLinkRoot());
3328
SoDetail *det=nullptr;
3330
if(getDetailPath(v.first.c_str(), &path, false, det))
3331
action.apply(&path);
3335
action.setType(SoSelectionElementAction::Hide);
3336
for(const auto &sub : hideList) {
3337
SoDetail *det=nullptr;
3339
if(!sub.empty() && getDetailPath(sub.c_str(), &path, false, det))
3340
action.apply(&path);
3343
path.unrefNoDelete();
3346
void ViewProviderLink::setOverrideMode(const std::string &mode) {
3347
auto ext = getLinkExtension();
3350
auto obj = ext->getTrueLinkedObject(false);
3351
if(obj && obj!=getObject()) {
3352
auto vp = Application::Instance->getViewProvider(obj);
3353
vp->setOverrideMode(mode);
3356
childVp->setOverrideMode(mode);
3359
void ViewProviderLink::onBeforeChange(const App::Property *prop) {
3360
if(prop == &ChildViewProvider) {
3362
childVp->beforeDelete();
3363
pcModeSwitch->replaceChild(1,linkView->getLinkRoot());
3364
childVpLink.reset();
3368
inherited::onBeforeChange(prop);
3371
static bool isExcludedProperties(const char *name) {
3372
#define CHECK_EXCLUDE_PROP(_name) if(strcmp(name,#_name)==0) return true;
3373
CHECK_EXCLUDE_PROP(Proxy);
3377
App::Property *ViewProviderLink::getPropertyByName(const char *name) const {
3378
auto prop = inherited::getPropertyByName(name);
3379
if(prop || isExcludedProperties(name))
3382
prop = childVp->getPropertyByName(name);
3383
if(prop && !prop->testStatus(App::Property::Hidden))
3387
if(pcObject && pcObject->canLinkProperties()) {
3388
auto linked = getLinkedViewProvider(nullptr,true);
3389
if(linked && linked!=this)
3390
prop = linked->getPropertyByName(name);
3395
void ViewProviderLink::getPropertyMap(std::map<std::string,App::Property*> &Map) const {
3396
inherited::getPropertyMap(Map);
3399
std::map<std::string,App::Property*> childMap;
3400
childVp->getPropertyMap(childMap);
3401
for(const auto &v : childMap) {
3402
auto ret = Map.insert(v);
3404
auto myProp = ret.first->second;
3405
if(myProp->testStatus(App::Property::Hidden))
3406
ret.first->second = v.second;
3411
void ViewProviderLink::getPropertyList(std::vector<App::Property*> &List) const {
3412
std::map<std::string,App::Property*> Map;
3413
getPropertyMap(Map);
3414
List.reserve(List.size()+Map.size());
3415
for(const auto &v:Map)
3416
List.push_back(v.second);
3419
ViewProviderDocumentObject *ViewProviderLink::getLinkedViewProvider(
3420
std::string *subname, bool recursive) const
3422
auto self = const_cast<ViewProviderLink*>(this);
3423
auto ext = getLinkExtension();
3426
App::DocumentObject *linked = nullptr;
3428
linked = ext->getLink();
3429
const char *s = ext->getSubName();
3433
linked = ext->getTrueLinkedObject(recursive);
3436
auto res = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
3437
Application::Instance->getViewProvider(linked));
3443
void ViewProviderLink::setTransformation(const Base::Matrix4D &rcMatrix)
3445
inherited::setTransformation(rcMatrix);
3446
auto ext = getLinkExtension();
3448
if (ext->getScaleVectorProperty())
3449
updateDataPrivate(getLinkExtension(),ext->getScaleVectorProperty());
3451
updateDataPrivate(getLinkExtension(),ext->getScaleProperty());
3455
void ViewProviderLink::setTransformation(const SbMatrix &rcMatrix)
3457
inherited::setTransformation(rcMatrix);
3458
auto ext = getLinkExtension();
3460
if (ext->getScaleVectorProperty())
3461
updateDataPrivate(getLinkExtension(),ext->getScaleVectorProperty());
3463
updateDataPrivate(getLinkExtension(),ext->getScaleProperty());
3470
PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderLinkPython, Gui::ViewProviderLink)
3471
template class GuiExport ViewProviderFeaturePythonT<ViewProviderLink>;