]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_MenuMgr.cpp
Salome HOME
Transfer data model for object browser under module responsibility
[modules/shaper.git] / src / PartSet / PartSet_MenuMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_MenuMgr.cpp
4 // Created:     03 April 2015
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_MenuMgr.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_SketcherMgr.h"
10 #include "PartSet_Tools.h"
11
12 #include <GeomAPI_Pnt2d.h>
13 #include <GeomDataAPI_Point2D.h>
14
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>
20
21 #include <ModuleBase_ISelection.h>
22 #include <ModuleBase_Operation.h>
23
24 #include <XGUI_ModuleConnector.h>
25 #include <XGUI_Workshop.h>
26 #include <XGUI_Displayer.h>
27
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>
33
34 #include <QAction>
35 #include <QMenu>
36
37 #include <TopoDS.hxx>
38 #include <BRep_Tool.hxx>
39
40 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
41   : QObject(theModule), myModule(theModule), myPrevId(-1)
42 {
43   createActions();
44 }
45
46
47 QAction* PartSet_MenuMgr::action(const QString& theId) const
48 {
49   if (myActions.contains(theId))
50     return myActions[theId];
51   return 0;
52 }
53
54 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
55 {
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;
61 }
62
63 void PartSet_MenuMgr::createActions()
64 {
65   QAction* aAction;
66
67   aAction = new QAction(tr("Auxiliary"), this);
68   aAction->setCheckable(true);
69   addAction("AUXILIARY_CMD", aAction);
70
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;
74
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;
78
79   // Activate PartSet
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;
83
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;
87 }
88
89
90 void PartSet_MenuMgr::onAction(bool isChecked)
91 {
92   QAction* aAction = static_cast<QAction*>(sender());
93   QString anId = aAction->data().toString();
94
95   if (anId == "AUXILIARY_CMD") {
96     setAuxiliary(isChecked);
97   }
98 }
99
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)
105 {
106   std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
107
108   if (!theFeature->data())
109     return std::shared_ptr<GeomAPI_Pnt2d>();
110
111   FeaturePtr aFeature;
112   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
113       ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
114   if (anAttr)
115     aFeature = ModelAPI_Feature::feature(anAttr->object());
116
117   if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
118     aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
119         aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
120
121   else if (anAttr->attr()) {
122     aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
123   }
124   if (aPointAttr.get() != NULL)
125     return aPointAttr->pnt();
126   return std::shared_ptr<GeomAPI_Pnt2d>();
127 }
128
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)
134 {
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)
140       return;
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());
152         }
153       }
154     }
155   }
156 }
157
158
159 bool PartSet_MenuMgr::addViewerMenu(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
160 {
161   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
162   if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
163       !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
164     return false;
165
166   myCoinsideLines.clear();
167   ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
168
169   bool aIsDetach = false;
170   bool hasAttribute = false;
171   bool hasFeature = false;
172
173   QList<ModuleBase_ViewerPrs> aPrsList = aSelection->getSelected();
174   TopoDS_Shape aShape;
175   ResultPtr aResult;
176   FeaturePtr aFeature;
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>()))
182         hasFeature = true;
183       else
184         hasAttribute = true;
185     } else {
186       aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs.object());
187       hasFeature = (aFeature.get() != NULL);
188     }
189   }
190
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);
200
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;
215               break;
216             } else {
217               a2dPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
218               if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) { 
219                 aCoincident = aConstrFeature;
220                 break;
221               }
222             }
223           }
224         }
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) {
231             aIsDetach = true;
232             QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
233             QAction* aAction;
234             int i = 0;
235             foreach (FeaturePtr aCoins, myCoinsideLines) {
236               aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
237               aAction->setData(QVariant(i));
238               i++;
239             }
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*)));
243           } 
244         }
245       }
246     }
247   }
248   if ((!aIsDetach) && hasFeature) {
249     theMenu->addAction(theStdActions["DELETE_CMD"]);
250   }
251   if (hasAttribute)
252     return true;
253   bool isAuxiliary;
254   if (canSetAuxiliary(isAuxiliary)) {
255     QAction* anAction = action("AUXILIARY_CMD");
256     theMenu->addAction(anAction);
257     anAction->setChecked(isAuxiliary);
258   }
259   return true;
260 }
261
262 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
263 {
264   if (myPrevId != -1) {
265     // Restore color for previous object
266     setLineColor(myPrevId, myColor, false);
267   }
268   myPrevId = theAction->data().toInt();
269   myColor = setLineColor(myPrevId, Qt::white, true);
270 }
271
272 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
273 {
274   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
275   XGUI_Workshop* aWorkshop = aConnector->workshop();
276   XGUI_Displayer* aDisplayer = aWorkshop->displayer();
277
278   FeaturePtr aLine = myCoinsideLines.at(myPrevId);
279   std::list<ResultPtr>::const_iterator aIt;
280   const std::list<ResultPtr>& aResults = aLine->results();
281   QColor aColor;
282   for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
283     aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
284   }
285   if (theUpdate)
286     aDisplayer->updateViewer();
287   return aColor;
288 }
289
290
291 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
292 {
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());
298   
299   gp_Pnt aOr = aOrig->impl<gp_Pnt>();
300   const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
301
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)
313         return;
314       gp_Pnt aP = aPnt->impl<gp_Pnt>();
315       if (aOrig->isEqual(aPnt)) {
316         aToDelFeatures.append(aConstrFeature);
317       } else {
318         aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
319         aP = aPnt->impl<gp_Pnt>();
320         if (aOrig->isEqual(aPnt)) {
321           aToDelFeatures.append(aConstrFeature);
322           break;
323         }
324       }
325     }
326   }
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();
333
334     SessionPtr aMgr = ModelAPI_Session::get();
335     std::set<FeaturePtr> anIgnoredFeatures;
336     anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
337
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();
342   }
343   myCoinsideLines.clear();
344 }
345
346
347 void PartSet_MenuMgr::onDetachMenuHide()
348 {
349   if (myPrevId != -1) {
350     // Restore color for previous object
351     setLineColor(myPrevId, myColor, false);
352   }
353   // Clear previous definitions
354   myPrevId = -1;
355 }
356
357   
358 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
359 {
360   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
361
362   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
363                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
364   if (!isActiveSketch)
365     return;
366
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());
373   }
374   else {
375     isUseTransaction = true;
376     // 2. change auxiliary type of selected sketch entities
377     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
378     anObjects = aSelection->selectedPresentations();
379   }
380
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());
387   }
388   myModule->sketchMgr()->storeSelection();
389
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();
399
400           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
401             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
402           if (anAuxiliaryAttr)
403             anAuxiliaryAttr->setValue(isChecked);
404         }
405       }
406     }
407   }
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();
413   }
414
415   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
416   myModule->sketchMgr()->restoreSelection();
417 }
418
419 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
420 {
421   bool anEnabled = false;
422   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
423
424   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
425                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
426   if (!isActiveSketch)
427     return anEnabled;
428
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());
434   }
435   else {
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();
443   }
444
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())) {
451         anEnabled = true;
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();
456
457           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
458             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
459           if (anAuxiliaryAttr)
460             isNotAuxiliaryFound = !anAuxiliaryAttr->value();
461         }
462       }
463     }
464   }
465   theValue = anObjects.size() && !isNotAuxiliaryFound;
466   return anEnabled;
467 }
468
469 void PartSet_MenuMgr::onActivatePart(bool)
470 {
471   QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
472   if (aObjects.size() > 0) {
473     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObjects.first());
474     if (aPart) {
475       aPart->activate();
476     }
477   }
478 }
479
480 void PartSet_MenuMgr::onActivatePartSet(bool)
481 {
482   SessionPtr aMgr = ModelAPI_Session::get();
483   aMgr->setActiveDocument(aMgr->moduleDocument());
484 }
485
486 void PartSet_MenuMgr::onEdit(bool)
487 {
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);
495     }
496   }
497   if (aFeature.get() != NULL)
498     myModule->editFeature(aFeature);
499 }