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