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