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 <PartSetPlugin_Part.h>
14 #include <GeomAPI_Pnt2d.h>
15 #include <GeomDataAPI_Point2D.h>
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>
23 #include <ModuleBase_ISelection.h>
24 #include <ModuleBase_Operation.h>
26 #include <XGUI_ModuleConnector.h>
27 #include <XGUI_Workshop.h>
28 #include <XGUI_Displayer.h>
30 #include <Events_Loop.h>
31 #include <ModelAPI_Events.h>
32 #include <ModelAPI_Session.h>
33 #include <ModelAPI_ResultPart.h>
34 #include <ModelAPI_ResultParameter.h>
40 #include <BRep_Tool.hxx>
42 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
43 : QObject(theModule), myModule(theModule), myPrevId(-1)
49 QAction* PartSet_MenuMgr::action(const QString& theId) const
51 if (myActions.contains(theId))
52 return myActions[theId];
56 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
58 if (myActions.contains(theId))
59 qCritical("A command with Id = '%s' already defined!", qPrintable(theId));
60 theAction->setData(theId);
61 connect(theAction, SIGNAL(triggered(bool)), this, SLOT(onAction(bool)));
62 myActions[theId] = theAction;
65 void PartSet_MenuMgr::createActions()
69 aAction = new QAction(tr("Auxiliary"), this);
70 aAction->setCheckable(true);
71 addAction("AUXILIARY_CMD", aAction);
73 aAction = new QAction(QIcon(":icons/activate.png"), tr("Activate"), this);
74 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePart(bool)));
75 myActions["ACTIVATE_PART_CMD"] = aAction;
77 aAction = new QAction(QIcon(":icons/deactivate.png"), tr("Deactivate"), this);
78 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePartSet(bool)));
79 myActions["DEACTIVATE_PART_CMD"] = aAction;
82 aAction = new QAction(QIcon(":icons/activate.png"), tr("Activate"), this);
83 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onActivatePartSet(bool)));
84 myActions["ACTIVATE_PARTSET_CMD"] = aAction;
86 aAction = new QAction(QIcon(":icons/edit.png"), tr("Edit..."), this);
87 connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onEdit(bool)));
88 myActions["EDIT_CMD"] = aAction;
92 void PartSet_MenuMgr::onAction(bool isChecked)
94 QAction* aAction = static_cast<QAction*>(sender());
95 QString anId = aAction->data().toString();
97 if (anId == "AUXILIARY_CMD") {
98 setAuxiliary(isChecked);
102 /// Returns point of coincidence feature
103 /// \param theFeature the coincidence feature
104 /// \param theAttribute the attribute name
105 std::shared_ptr<GeomAPI_Pnt2d> getPoint(std::shared_ptr<ModelAPI_Feature>& theFeature,
106 const std::string& theAttribute)
108 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
110 if (!theFeature->data())
111 return std::shared_ptr<GeomAPI_Pnt2d>();
114 std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
115 ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
117 aFeature = ModelAPI_Feature::feature(anAttr->object());
119 if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
120 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
121 aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
123 else if (anAttr->attr()) {
124 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
126 if (aPointAttr.get() != NULL)
127 return aPointAttr->pnt();
128 return std::shared_ptr<GeomAPI_Pnt2d>();
131 /// Returns list of features connected in a councedence feature point
132 /// \param theStartCoin the coincidence feature
133 /// \param theList a list which collects lines features
134 /// \param theAttr the attribute name
135 void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
137 AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
138 FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
139 if (!theList.contains(aObj)) {
140 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
141 if (aOrig.get() == NULL)
143 theList.append(aObj);
144 const std::set<AttributePtr>& aRefsList = aObj->data()->refsToMe();
145 std::set<AttributePtr>::const_iterator aIt;
146 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
147 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
148 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
149 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
150 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
151 if (aPnt.get() && aOrig->isEqual(aPnt)) {
152 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
153 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
161 bool PartSet_MenuMgr::addViewerMenu(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
163 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
164 if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
165 !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
168 myCoinsideLines.clear();
169 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
171 bool aIsDetach = false;
172 bool hasAttribute = false;
173 bool hasFeature = false;
175 QList<ModuleBase_ViewerPrs> aPrsList = aSelection->getSelected(ModuleBase_ISelection::AllControls);
179 foreach(ModuleBase_ViewerPrs aPrs, aPrsList) {
180 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs.object());
181 if (aResult.get() != NULL) {
182 aShape = aPrs.shape();
183 if (aShape.IsEqual(aResult->shape()->impl<TopoDS_Shape>()))
188 aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs.object());
189 hasFeature = (aFeature.get() != NULL);
193 if (aPrsList.size() == 1) {
194 TopoDS_Shape aShape = aPrsList.first().shape();
195 if ((!aShape.IsNull()) && aShape.ShapeType() == TopAbs_VERTEX) {
196 // Find 2d coordinates
197 FeaturePtr aSketchFea = myModule->sketchMgr()->activeSketch();
198 if (aSketchFea->getKind() == SketchPlugin_Sketch::ID()) {
199 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
200 std::shared_ptr<GeomAPI_Pnt> aPnt3d(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
201 std::shared_ptr<GeomAPI_Pnt2d> aSelPnt = PartSet_Tools::convertTo2D(aSketchFea, aPnt3d);
203 // Find coincident in these coordinates
204 ObjectPtr aObj = aPrsList.first().object();
205 FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
206 const std::set<AttributePtr>& aRefsList = aFeature->data()->refsToMe();
207 std::set<AttributePtr>::const_iterator aIt;
208 FeaturePtr aCoincident;
209 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
210 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
211 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
212 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
213 std::shared_ptr<GeomAPI_Pnt2d> a2dPnt =
214 getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
215 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
216 aCoincident = aConstrFeature;
219 a2dPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
220 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
221 aCoincident = aConstrFeature;
227 // If we have coincidence then add Detach menu
228 if (aCoincident.get() != NULL) {
229 mySelectedFeature = aCoincident;
230 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
231 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
232 if (myCoinsideLines.size() > 0) {
234 QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
237 foreach (FeaturePtr aCoins, myCoinsideLines) {
238 aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
239 aAction->setData(QVariant(i));
242 connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
243 connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
244 connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
250 if ((!aIsDetach) && hasFeature) {
251 theMenu->addAction(theStdActions["DELETE_CMD"]);
256 if (canSetAuxiliary(isAuxiliary)) {
257 QAction* anAction = action("AUXILIARY_CMD");
258 theMenu->addAction(anAction);
259 anAction->setChecked(isAuxiliary);
264 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
266 if (myPrevId != -1) {
267 // Restore color for previous object
268 setLineColor(myPrevId, myColor, false);
270 myPrevId = theAction->data().toInt();
271 myColor = setLineColor(myPrevId, Qt::white, true);
274 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
276 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
277 XGUI_Workshop* aWorkshop = aConnector->workshop();
278 XGUI_Displayer* aDisplayer = aWorkshop->displayer();
280 FeaturePtr aLine = myCoinsideLines.at(myPrevId);
281 std::list<ResultPtr>::const_iterator aIt;
282 const std::list<ResultPtr>& aResults = aLine->results();
284 for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
285 aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
288 aDisplayer->updateViewer();
293 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
295 int aId = theAction->data().toInt();
296 FeaturePtr aLine = myCoinsideLines.at(aId);
297 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
298 if (aOrig.get() == NULL)
299 aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
301 gp_Pnt aOr = aOrig->impl<gp_Pnt>();
302 const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
304 QObjectPtrList aToDelFeatures;
305 std::set<AttributePtr>::const_iterator aIt;
306 // Find all coincedences corresponded to the selected line in the selected point
307 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
308 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
309 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
310 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
311 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
312 if (aPnt.get() == NULL)
313 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
314 if (aPnt.get() == NULL)
316 gp_Pnt aP = aPnt->impl<gp_Pnt>();
317 if (aOrig->isEqual(aPnt)) {
318 aToDelFeatures.append(aConstrFeature);
320 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
321 aP = aPnt->impl<gp_Pnt>();
322 if (aOrig->isEqual(aPnt)) {
323 aToDelFeatures.append(aConstrFeature);
329 if (aToDelFeatures.size() > 0) {
330 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
331 XGUI_Workshop* aWorkshop = aConnector->workshop();
332 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
333 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
334 anOperation->abort();
336 SessionPtr aMgr = ModelAPI_Session::get();
337 std::set<FeaturePtr> anIgnoredFeatures;
338 anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
340 QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
341 aMgr->startOperation(aName.toStdString());
342 aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
343 aMgr->finishOperation();
345 myCoinsideLines.clear();
349 void PartSet_MenuMgr::onDetachMenuHide()
351 if (myPrevId != -1) {
352 // Restore color for previous object
353 setLineColor(myPrevId, myColor, false);
355 // Clear previous definitions
360 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
362 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
364 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
365 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
369 QObjectPtrList anObjects;
370 bool isUseTransaction = false;
371 // 1. change auxiliary type of a created feature
372 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
373 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
374 anObjects.append(anOperation->feature());
377 isUseTransaction = true;
378 // 2. change auxiliary type of selected sketch entities
379 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
380 anObjects = aSelection->selectedPresentations();
383 QAction* anAction = action("AUXILIARY_CMD");
384 SessionPtr aMgr = ModelAPI_Session::get();
385 if (isUseTransaction) {
386 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
387 anOperation->abort();
388 aMgr->startOperation(anAction->text().toStdString());
390 myModule->sketchMgr()->storeSelection();
392 if (anObjects.size() > 0) {
393 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
394 for (; anIt != aLast; anIt++) {
395 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
396 if (aFeature.get() != NULL) {
397 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
398 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
399 if (aSketchFeature.get() != NULL) {
400 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
402 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
403 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
405 anAuxiliaryAttr->setValue(isChecked);
410 if (isUseTransaction) {
411 aMgr->finishOperation();
412 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
413 XGUI_Workshop* aWorkshop = aConnector->workshop();
414 aWorkshop->updateCommandStatus();
417 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
418 myModule->sketchMgr()->restoreSelection();
421 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
423 bool anEnabled = false;
424 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
426 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
427 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
431 QObjectPtrList anObjects;
432 // 1. change auxiliary type of a created feature
433 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
434 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
435 anObjects.append(anOperation->feature());
438 /// The operation should not be aborted here, because the method does not changed
439 /// the auxilliary state, but checks the possibility to perform this
440 ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
441 /// anOperation->abort();
442 // 2. change auxiliary type of selected sketch entities
443 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
444 anObjects = aSelection->selectedPresentations();
447 bool isNotAuxiliaryFound = false;
448 if (anObjects.size() > 0) {
449 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
450 for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
451 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
452 if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
454 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
455 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
456 if (aSketchFeature.get() != NULL) {
457 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
459 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
460 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
462 isNotAuxiliaryFound = !anAuxiliaryAttr->value();
467 theValue = anObjects.size() && !isNotAuxiliaryFound;
471 void PartSet_MenuMgr::onActivatePart(bool)
473 QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
474 if (aObjects.size() > 0) {
475 ObjectPtr aObj = aObjects.first();
476 ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
478 FeaturePtr aPartFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
479 if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) {
480 aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->firstResult());
488 void PartSet_MenuMgr::onActivatePartSet(bool)
490 SessionPtr aMgr = ModelAPI_Session::get();
491 bool isNewTransaction = !aMgr->isOperation();
492 // activation may cause changes in current features in document, so it must be in transaction
493 if (isNewTransaction) {
494 aMgr->startOperation("Activation");
496 aMgr->setActiveDocument(aMgr->moduleDocument());
497 if (isNewTransaction) {
498 aMgr->finishOperation();
502 void PartSet_MenuMgr::onEdit(bool)
504 QObjectPtrList aObjects = myModule->workshop()->selection()->selectedObjects();
505 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObjects.first());
506 if (aFeature == NULL) {
507 ResultParameterPtr aParam =
508 std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aObjects.first());
509 if (aParam.get() != NULL) {
510 aFeature = ModelAPI_Feature::feature(aParam);
513 if (aFeature.get() != NULL)
514 myModule->editFeature(aFeature);