1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: PartSet_MenuMgr.cpp
4 // Created: 03 April 2015
5 // Author: Vitaly SMETANNIKOV
7 #include "PartSet_MenuMgr.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_SketcherMgr.h"
10 #include "PartSet_Tools.h"
12 #include <GeomAPI_Pnt2d.h>
13 #include <GeomDataAPI_Point2D.h>
15 #include <SketchPlugin_ConstraintCoincidence.h>
16 #include <SketchPlugin_Line.h>
17 #include <SketchPlugin_Circle.h>
18 #include <SketchPlugin_Point.h>
19 #include <SketchPlugin_Sketch.h>
21 #include <ModuleBase_ISelection.h>
22 #include <ModuleBase_Operation.h>
24 #include <XGUI_ModuleConnector.h>
25 #include <XGUI_Workshop.h>
26 #include <XGUI_Displayer.h>
28 #include <Events_Loop.h>
29 #include <ModelAPI_Events.h>
30 #include <ModelAPI_Session.h>
31 #include <ModelAPI_ResultPart.h>
32 #include <ModelAPI_ResultParameter.h>
38 #include <BRep_Tool.hxx>
40 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
41 : QObject(theModule), myModule(theModule), myPrevId(-1)
47 QAction* PartSet_MenuMgr::action(const QString& theId) const
49 if (myActions.contains(theId))
50 return myActions[theId];
54 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
56 if (myActions.contains(theId))
57 qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
58 theAction->setData(theId);
59 connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
60 myActions[theId] = theAction;
63 void PartSet_MenuMgr::createActions()
67 aAction = new QAction(tr("Auxiliary"), this);
68 aAction->setCheckable(true);
69 addAction("AUXILIARY_CMD", aAction);
71 aAction = new QAction(QIcon(":icons/activate.png"), tr("Activate"), this);
72 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePart(bool)));
73 myActions["ACTIVATE_PART_CMD"] = aAction;
75 aAction = new QAction(QIcon(":icons/deactivate.png"), tr("Deactivate"), this);
76 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePartSet(bool)));
77 myActions["DEACTIVATE_PART_CMD"] = aAction;
80 aAction = new QAction(QIcon(":icons/activate.png"), tr("Activate"), this);
81 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePartSet(bool)));
82 myActions["ACTIVATE_PARTSET_CMD"] = aAction;
84 aAction = new QAction(QIcon(":icons/edit.png"), tr("Edit..."), this);
85 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onEdit(bool)));
86 myActions["EDIT_CMD"] = aAction;
90 void PartSet_MenuMgr::onAction(bool isChecked)
92 QAction* aAction = static_cast<QAction*>(sender());
93 QString anId = aAction->data().toString();
95 if (anId == "AUXILIARY_CMD") {
96 setAuxiliary(isChecked);
100 /// Returns point of coincidence feature
101 /// \param theFeature the coincidence feature
102 /// \param theAttribute the attribute name
103 std::shared_ptr<GeomAPI_Pnt2d> getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
104 const std::string& theAttribute)
106 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
108 if (!theFeature->data())
109 return std::shared_ptr<GeomAPI_Pnt2d>();
112 std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
113 ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
115 aFeature = ModelAPI_Feature::feature(anAttr->object());
117 if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
118 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
119 aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
121 else if (anAttr->attr()) {
122 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
124 if (aPointAttr.get() != NULL)
125 return aPointAttr->pnt();
126 return std::shared_ptr<GeomAPI_Pnt2d>();
129 /// Returns list of features connected in a councedence feature point
130 /// \param theStartCoin the coincidence feature
131 /// \param theList a list which collects lines features
132 /// \param theAttr the attribute name
133 void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
135 AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
136 FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
137 if (!theList.contains(aObj)) {
138 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
139 if (aOrig.get() == NULL)
141 theList.append(aObj);
142 const std::set<AttributePtr>& aRefsList = aObj->data()->refsToMe();
143 std::set<AttributePtr>::const_iterator aIt;
144 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
145 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
146 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
147 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
148 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
149 if (aPnt.get() && aOrig->isEqual(aPnt)) {
150 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
151 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
159 bool PartSet_MenuMgr::addViewerMenu(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
161 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
162 if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
163 !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
166 myCoinsideLines.clear();
167 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
169 bool aIsDetach = false;
170 bool hasAttribute = false;
171 bool hasFeature = false;
173 QList<ModuleBase_ViewerPrs> aPrsList = aSelection->getSelected();
177 foreach(ModuleBase_ViewerPrs aPrs, aPrsList) {
178 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs.object());
179 if (aResult.get() != NULL) {
180 aShape = aPrs.shape();
181 if (aShape.IsEqual(aResult->shape()->impl<TopoDS_Shape>()))
186 aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs.object());
187 hasFeature = (aFeature.get() != NULL);
191 if (aPrsList.size() == 1) {
192 TopoDS_Shape aShape = aPrsList.first().shape();
193 if ((!aShape.IsNull()) && aShape.ShapeType() == TopAbs_VERTEX) {
194 // Find 2d coordinates
195 FeaturePtr aSketchFea = myModule->sketchMgr()->activeSketch();
196 if (aSketchFea->getKind() == SketchPlugin_Sketch::ID()) {
197 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
198 std::shared_ptr<GeomAPI_Pnt> aPnt3d(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
199 std::shared_ptr<GeomAPI_Pnt2d> aSelPnt = PartSet_Tools::convertTo2D(aSketchFea, aPnt3d);
201 // Find coincident in these coordinates
202 ObjectPtr aObj = aPrsList.first().object();
203 FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
204 const std::set<AttributePtr>& aRefsList = aFeature->data()->refsToMe();
205 std::set<AttributePtr>::const_iterator aIt;
206 FeaturePtr aCoincident;
207 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
208 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
209 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
210 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
211 std::shared_ptr<GeomAPI_Pnt2d> a2dPnt =
212 getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
213 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
214 aCoincident = aConstrFeature;
217 a2dPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
218 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
219 aCoincident = aConstrFeature;
225 // If we have coincidence then add Detach menu
226 if (aCoincident.get() != NULL) {
227 mySelectedFeature = aCoincident;
228 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
229 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
230 if (myCoinsideLines.size() > 0) {
232 QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
235 foreach (FeaturePtr aCoins, myCoinsideLines) {
236 aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
237 aAction->setData(QVariant(i));
240 connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
241 connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
242 connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
248 if ((!aIsDetach) && hasFeature) {
249 theMenu->addAction(theStdActions["DELETE_CMD"]);
254 if (canSetAuxiliary(isAuxiliary)) {
255 QAction* anAction = action("AUXILIARY_CMD");
256 theMenu->addAction(anAction);
257 anAction->setChecked(isAuxiliary);
262 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
264 if (myPrevId != -1) {
265 // Restore color for previous object
266 setLineColor(myPrevId, myColor, false);
268 myPrevId = theAction->data().toInt();
269 myColor = setLineColor(myPrevId, Qt::white, true);
272 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
274 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
275 XGUI_Workshop* aWorkshop = aConnector->workshop();
276 XGUI_Displayer* aDisplayer = aWorkshop->displayer();
278 FeaturePtr aLine = myCoinsideLines.at(myPrevId);
279 std::list<ResultPtr>::const_iterator aIt;
280 const std::list<ResultPtr>& aResults = aLine->results();
282 for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
283 aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
286 aDisplayer->updateViewer();
291 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
293 int aId = theAction->data().toInt();
294 FeaturePtr aLine = myCoinsideLines.at(aId);
295 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
296 if (aOrig.get() == NULL)
297 aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
299 gp_Pnt aOr = aOrig->impl<gp_Pnt>();
300 const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
302 QObjectPtrList aToDelFeatures;
303 std::set<AttributePtr>::const_iterator aIt;
304 // Find all coincedences corresponded to the selected line in the selected point
305 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
306 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
307 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
308 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
309 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
310 if (aPnt.get() == NULL)
311 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
312 if (aPnt.get() == NULL)
314 gp_Pnt aP = aPnt->impl<gp_Pnt>();
315 if (aOrig->isEqual(aPnt)) {
316 aToDelFeatures.append(aConstrFeature);
318 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
319 aP = aPnt->impl<gp_Pnt>();
320 if (aOrig->isEqual(aPnt)) {
321 aToDelFeatures.append(aConstrFeature);
327 if (aToDelFeatures.size() > 0) {
328 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
329 XGUI_Workshop* aWorkshop = aConnector->workshop();
330 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
331 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
332 anOperation->abort();
334 SessionPtr aMgr = ModelAPI_Session::get();
335 std::set<FeaturePtr> anIgnoredFeatures;
336 anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
338 QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
339 aMgr->startOperation(aName.toStdString());
340 aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
341 aMgr->finishOperation();
343 myCoinsideLines.clear();
347 void PartSet_MenuMgr::onDetachMenuHide()
349 if (myPrevId != -1) {
350 // Restore color for previous object
351 setLineColor(myPrevId, myColor, false);
353 // Clear previous definitions
358 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
360 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
362 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
363 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
367 QObjectPtrList anObjects;
368 bool isUseTransaction = false;
369 // 1. change auxiliary type of a created feature
370 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
371 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
372 anObjects.append(anOperation->feature());
375 isUseTransaction = true;
376 // 2. change auxiliary type of selected sketch entities
377 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
378 anObjects = aSelection->selectedPresentations();
381 QAction* anAction = action("AUXILIARY_CMD");
382 SessionPtr aMgr = ModelAPI_Session::get();
383 if (isUseTransaction) {
384 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
385 anOperation->abort();
386 aMgr->startOperation(anAction->text().toStdString());
388 myModule->sketchMgr()->storeSelection();
390 if (anObjects.size() > 0) {
391 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
392 for (; anIt != aLast; anIt++) {
393 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
394 if (aFeature.get() != NULL) {
395 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
396 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
397 if (aSketchFeature.get() != NULL) {
398 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
400 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
401 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
403 anAuxiliaryAttr->setValue(isChecked);
408 if (isUseTransaction) {
409 aMgr->finishOperation();
410 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
411 XGUI_Workshop* aWorkshop = aConnector->workshop();
412 aWorkshop->updateCommandStatus();
415 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
416 myModule->sketchMgr()->restoreSelection();
419 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
421 bool anEnabled = false;
422 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
424 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
425 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
429 QObjectPtrList anObjects;
430 // 1. change auxiliary type of a created feature
431 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
432 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
433 anObjects.append(anOperation->feature());
436 /// The operation should not be aborted here, because the method does not changed
437 /// the auxilliary state, but checks the possibility to perform this
438 ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
439 /// anOperation->abort();
440 // 2. change auxiliary type of selected sketch entities
441 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
442 anObjects = aSelection->selectedPresentations();
445 bool isNotAuxiliaryFound = false;
446 if (anObjects.size() > 0) {
447 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
448 for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
449 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
450 if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
452 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
453 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
454 if (aSketchFeature.get() != NULL) {
455 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
457 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
458 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
460 isNotAuxiliaryFound = !anAuxiliaryAttr->value();
465 theValue = anObjects.size() && !isNotAuxiliaryFound;
469 void PartSet_MenuMgr::onActivatePart(bool)
471 QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
472 if (aObjects.size() > 0) {
473 ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObjects.first());
480 void PartSet_MenuMgr::onActivatePartSet(bool)
482 SessionPtr aMgr = ModelAPI_Session::get();
483 aMgr->setActiveDocument(aMgr->moduleDocument());
486 void PartSet_MenuMgr::onEdit(bool)
488 QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
489 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjects.first());
490 if (aFeature == NULL) {
491 ResultParameterPtr aParam =
492 std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObjects.first());
493 if (aParam.get() != NULL) {
494 aFeature = ModelAPI_Feature::feature(aParam);
497 if (aFeature.get() != NULL)
498 myModule->editFeature(aFeature);