]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_MenuMgr.cpp
Salome HOME
Optimize Delete command item
[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
32 #include <QAction>
33 #include <QMenu>
34
35 #include <TopoDS.hxx>
36 #include <BRep_Tool.hxx>
37
38 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
39   : QObject(theModule), myModule(theModule), myPrevId(-1)
40 {
41   createActions();
42 }
43
44
45 QAction* PartSet_MenuMgr::action(const QString& theId) const
46 {
47   if (myActions.contains(theId))
48     return myActions[theId];
49   return 0;
50 }
51
52 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
53 {
54   if (myActions.contains(theId))
55     qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
56   theAction->setData(theId);
57   connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
58   myActions[theId] = theAction;
59 }
60
61 void PartSet_MenuMgr::createActions()
62 {
63   QAction* anAction;
64
65   anAction = new QAction(tr("Auxiliary"), this);
66   anAction->setCheckable(true);
67   addAction("AUXILIARY_CMD", anAction);
68 }
69
70
71 void PartSet_MenuMgr::onAction(bool isChecked)
72 {
73   QAction* aAction = static_cast<QAction*>(sender());
74   QString anId = aAction->data().toString();
75
76   if (anId == "AUXILIARY_CMD") {
77     setAuxiliary(isChecked);
78   }
79 }
80
81 /// Returns point of coincidence feature
82 /// \param theFeature the coincidence feature
83 /// \param theAttribute the attribute name
84 std::shared_ptr<GeomAPI_Pnt2d> getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
85                                         const std::string& theAttribute)
86 {
87   std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
88
89   if (!theFeature->data())
90     return std::shared_ptr<GeomAPI_Pnt2d>();
91
92   FeaturePtr aFeature;
93   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
94       ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
95   if (anAttr)
96     aFeature = ModelAPI_Feature::feature(anAttr->object());
97
98   if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
99     aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
100         aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
101
102   else if (aFeature &&  aFeature->getKind() == SketchPlugin_Circle::ID())
103     aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
104         aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()));
105
106   else if (anAttr->attr()) {
107     aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
108   }
109   if (aPointAttr.get() != NULL)
110     return aPointAttr->pnt();
111   return std::shared_ptr<GeomAPI_Pnt2d>();
112 }
113
114 /// Returns list of features connected in a councedence feature point
115 /// \param theStartCoin the coincidence feature
116 /// \param theList a list which collects lines features
117 /// \param theAttr the attribute name
118 void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
119 {
120   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
121   FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
122   if (!theList.contains(aObj)) {
123     std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
124     theList.append(aObj);
125     const std::set<AttributePtr>& aRefsList = aObj->data()->refsToMe();
126     std::set<AttributePtr>::const_iterator aIt;
127     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
128       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
129       FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
130       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { 
131         std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
132         if (aOrig->isEqual(aPnt)) {
133           findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
134           findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
135         }
136       }
137     }
138   }
139 }
140
141
142 bool PartSet_MenuMgr::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
143 {
144   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
145   if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
146       !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
147     return false;
148
149   myCoinsideLines.clear();
150   ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
151
152   bool aIsDetach = false;
153   bool hasAttribute = false;
154   bool hasFeature = false;
155
156   QList<ModuleBase_ViewerPrs> aPrsList = aSelection->getSelected();
157   TopoDS_Shape aShape;
158   ResultPtr aResult;
159   foreach(ModuleBase_ViewerPrs aPrs, aPrsList) {
160     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs.object());
161     if (aResult.get() != NULL) {
162       aShape = aPrs.shape();
163       if (aShape.IsEqual(aResult->shape()->impl<TopoDS_Shape>()))
164         hasFeature = true;
165       else
166         hasAttribute = true;
167     }
168   }
169
170   if (aPrsList.size() == 1) {
171     TopoDS_Shape aShape = aPrsList.first().shape();
172     if (aShape.ShapeType() == TopAbs_VERTEX) {
173       // Find 2d coordinates
174       FeaturePtr aSketchFea = myModule->sketchMgr()->activeSketch();
175       if (aSketchFea->getKind() == SketchPlugin_Sketch::ID()) {
176         gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
177         std::shared_ptr<GeomAPI_Pnt> aPnt3d(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
178         std::shared_ptr<GeomAPI_Pnt2d> aSelPnt = PartSet_Tools::convertTo2D(aSketchFea, aPnt3d);
179
180         // Find coincident in these coordinates
181         ObjectPtr aObj = aPrsList.first().object();
182         FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
183         const std::set<AttributePtr>& aRefsList = aFeature->data()->refsToMe();
184         std::set<AttributePtr>::const_iterator aIt;
185         FeaturePtr aCoincident;
186         for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
187           std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
188           FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
189           if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { 
190             std::shared_ptr<GeomAPI_Pnt2d> a2dPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
191             if (aSelPnt->isEqual(a2dPnt)) { 
192               aCoincident = aConstrFeature;
193               break;
194             } 
195           }
196         }
197         // If we have coincidence then add Detach menu
198         if (aCoincident.get() != NULL) {
199           mySelectedFeature = aCoincident;
200           findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
201           findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
202           if (myCoinsideLines.size() > 0) {
203             aIsDetach = true;
204             QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
205             QAction* aAction;
206             int i = 0;
207             foreach (FeaturePtr aCoins, myCoinsideLines) {
208               aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
209               aAction->setData(QVariant(i));
210               i++;
211             }
212             connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
213             connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
214             connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
215           } 
216         }
217       }
218     }
219   }
220   if ((!aIsDetach) && hasFeature) {
221     theMenu->addAction(theStdActions["DELETE_CMD"]);
222   }
223   if (hasAttribute)
224     return true;
225   bool isAuxiliary;
226   if (canSetAuxiliary(isAuxiliary)) {
227     QAction* anAction = action("AUXILIARY_CMD");
228     theMenu->addAction(anAction);
229     anAction->setChecked(isAuxiliary);
230   }
231   return true;
232 }
233
234 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
235 {
236   if (myPrevId != -1) {
237     // Restore color for previous object
238     setLineColor(myPrevId, myColor, false);
239   }
240   myPrevId = theAction->data().toInt();
241   myColor = setLineColor(myPrevId, Qt::white, true);
242 }
243
244 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
245 {
246   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
247   XGUI_Workshop* aWorkshop = aConnector->workshop();
248   XGUI_Displayer* aDisplayer = aWorkshop->displayer();
249
250   FeaturePtr aLine = myCoinsideLines.at(myPrevId);
251   std::list<ResultPtr>::const_iterator aIt;
252   const std::list<ResultPtr>& aResults = aLine->results();
253   QColor aColor;
254   for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
255     aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
256   }
257   if (theUpdate)
258     aDisplayer->updateViewer();
259   return aColor;
260 }
261
262
263 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
264 {
265   int aId = theAction->data().toInt();
266   FeaturePtr aLine = myCoinsideLines.at(aId);
267   std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
268   gp_Pnt aOr = aOrig->impl<gp_Pnt>();
269   const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
270
271   QObjectPtrList aToDelFeatures;
272   std::set<AttributePtr>::const_iterator aIt;
273   // Find all coincedences corresponded to the selected line in the selected point
274   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
275     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
276     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
277     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { 
278       std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
279       gp_Pnt aP = aPnt->impl<gp_Pnt>();
280       if (aOrig->isEqual(aPnt)) {
281         aToDelFeatures.append(aConstrFeature);
282       } else {
283         aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
284         aP = aPnt->impl<gp_Pnt>();
285         if (aOrig->isEqual(aPnt)) {
286           aToDelFeatures.append(aConstrFeature);
287           break;
288         }
289       }
290     }
291   }
292   if (aToDelFeatures.size() > 0) {
293     XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
294     XGUI_Workshop* aWorkshop = aConnector->workshop();
295     ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
296     if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
297       anOperation->abort();
298
299     SessionPtr aMgr = ModelAPI_Session::get();
300     std::set<FeaturePtr> anIgnoredFeatures;
301     anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
302
303     QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
304     aMgr->startOperation(aName.toStdString());
305     aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
306     aMgr->finishOperation();
307   }
308   myCoinsideLines.clear();
309 }
310
311
312 void PartSet_MenuMgr::onDetachMenuHide()
313 {
314   if (myPrevId != -1) {
315     // Restore color for previous object
316     setLineColor(myPrevId, myColor, false);
317   }
318   // Clear previous definitions
319   myPrevId = -1;
320 }
321
322   
323 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
324 {
325   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
326
327   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
328                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
329   if (!isActiveSketch)
330     return;
331
332   QObjectPtrList anObjects;
333   bool isUseTransaction = false;
334   // 1. change auxiliary type of a created feature
335   if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
336     PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
337     anObjects.append(anOperation->feature());
338   }
339   else {
340     isUseTransaction = true;
341     // 2. change auxiliary type of selected sketch entities
342     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
343     anObjects = aSelection->selectedPresentations();
344   }
345
346   QAction* anAction = action("AUXILIARY_CMD");
347   SessionPtr aMgr = ModelAPI_Session::get();
348   if (isUseTransaction) {
349     if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
350       anOperation->abort();
351     aMgr->startOperation(anAction->text().toStdString());
352   }
353   myModule->sketchMgr()->storeSelection();
354
355   if (anObjects.size() > 0) {
356     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
357     for (; anIt != aLast; anIt++) {
358       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
359       if (aFeature.get() != NULL) {
360         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
361                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
362         if (aSketchFeature.get() != NULL) {
363           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
364
365           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
366             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
367           if (anAuxiliaryAttr)
368             anAuxiliaryAttr->setValue(isChecked);
369         }
370       }
371     }
372   }
373   if (isUseTransaction) {
374     aMgr->finishOperation();
375   }
376   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
377   myModule->sketchMgr()->restoreSelection();
378 }
379
380 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
381 {
382   bool anEnabled = false;
383   ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
384
385   bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
386                         PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
387   if (!isActiveSketch)
388     return anEnabled;
389
390   QObjectPtrList anObjects;
391   // 1. change auxiliary type of a created feature
392   if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
393     PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
394     anObjects.append(anOperation->feature());
395   }
396   else {
397     /// The operation should not be aborted here, because the method does not changed
398     /// the auxilliary state, but checks the possibility to perform this
399     ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
400     ///  anOperation->abort();
401     // 2. change auxiliary type of selected sketch entities
402     ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
403     anObjects = aSelection->selectedPresentations();
404   }
405
406   bool isNotAuxiliaryFound = false;
407   if (anObjects.size() > 0) {
408     QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
409     for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
410       FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
411       if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
412         anEnabled = true;
413         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
414                             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
415         if (aSketchFeature.get() != NULL) {
416           std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
417
418           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr = 
419             std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
420           if (anAuxiliaryAttr)
421             isNotAuxiliaryFound = !anAuxiliaryAttr->value();
422         }
423       }
424     }
425   }
426   theValue = anObjects.size() && !isNotAuxiliaryFound;
427   return anEnabled;
428 }