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 <GeomAPI_Pnt2d.h>
13 #include <GeomDataAPI_Point2D.h>
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>
21 #include <ModuleBase_ISelection.h>
22 #include <ModuleBase_Operation.h>
24 #include <XGUI_ModuleConnector.h>
25 #include <XGUI_Workshop.h>
26 #include <XGUI_Displayer.h>
28 #include <Events_Loop.h>
29 #include <ModelAPI_Events.h>
30 #include <ModelAPI_Session.h>
36 #include <BRep_Tool.hxx>
38 PartSet_MenuMgr::PartSet_MenuMgr(PartSet_Module* theModule)
39 : QObject(theModule), myModule(theModule), myPrevId(-1)
45 QAction* PartSet_MenuMgr::action(const QString& theId) const
47 if (myActions.contains(theId))
48 return myActions[theId];
52 void PartSet_MenuMgr::addAction(const QString& theId, QAction* theAction)
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;
61 void PartSet_MenuMgr::createActions()
65 anAction = new QAction(tr("Auxiliary"), this);
66 anAction->setCheckable(true);
67 addAction("AUXILIARY_CMD", anAction);
71 void PartSet_MenuMgr::onAction(bool isChecked)
73 QAction* aAction = static_cast<QAction*>(sender());
74 QString anId = aAction->data().toString();
76 if (anId == "AUXILIARY_CMD") {
77 setAuxiliary(isChecked);
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)
87 std::shared_ptr<GeomDataAPI_Point2D> aPointAttr;
89 if (!theFeature->data())
90 return std::shared_ptr<GeomAPI_Pnt2d>();
93 std::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = std::dynamic_pointer_cast<
94 ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute));
96 aFeature = ModelAPI_Feature::feature(anAttr->object());
98 if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
99 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
100 aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()));
102 else if (anAttr->attr()) {
103 aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
105 if (aPointAttr.get() != NULL)
106 return aPointAttr->pnt();
107 return std::shared_ptr<GeomAPI_Pnt2d>();
110 /// Returns list of features connected in a councedence feature point
111 /// \param theStartCoin the coincidence feature
112 /// \param theList a list which collects lines features
113 /// \param theAttr the attribute name
114 void findCoincidences(FeaturePtr theStartCoin, QList<FeaturePtr>& theList, std::string theAttr)
116 AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
117 FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
118 if (!theList.contains(aObj)) {
119 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(theStartCoin, theAttr);
120 if (aOrig.get() == NULL)
122 theList.append(aObj);
123 const std::set<AttributePtr>& aRefsList = aObj->data()->refsToMe();
124 std::set<AttributePtr>::const_iterator aIt;
125 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
126 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
127 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
128 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
129 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, theAttr);
130 if (aPnt.get() && aOrig->isEqual(aPnt)) {
131 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_A());
132 findCoincidences(aConstrFeature, theList, SketchPlugin_ConstraintCoincidence::ENTITY_B());
140 bool PartSet_MenuMgr::addViewerItems(QMenu* theMenu, const QMap<QString, QAction*>& theStdActions) const
142 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
143 if (!PartSet_SketcherMgr::isSketchOperation(anOperation) &&
144 !PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
147 myCoinsideLines.clear();
148 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
150 bool aIsDetach = false;
151 bool hasAttribute = false;
152 bool hasFeature = false;
154 QList<ModuleBase_ViewerPrs> aPrsList = aSelection->getSelected();
158 foreach(ModuleBase_ViewerPrs aPrs, aPrsList) {
159 aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs.object());
160 if (aResult.get() != NULL) {
161 aShape = aPrs.shape();
162 if (aShape.IsEqual(aResult->shape()->impl<TopoDS_Shape>()))
167 aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs.object());
168 hasFeature = (aFeature.get() != NULL);
172 if (aPrsList.size() == 1) {
173 TopoDS_Shape aShape = aPrsList.first().shape();
174 if ((!aShape.IsNull()) && aShape.ShapeType() == TopAbs_VERTEX) {
175 // Find 2d coordinates
176 FeaturePtr aSketchFea = myModule->sketchMgr()->activeSketch();
177 if (aSketchFea->getKind() == SketchPlugin_Sketch::ID()) {
178 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
179 std::shared_ptr<GeomAPI_Pnt> aPnt3d(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
180 std::shared_ptr<GeomAPI_Pnt2d> aSelPnt = PartSet_Tools::convertTo2D(aSketchFea, aPnt3d);
182 // Find coincident in these coordinates
183 ObjectPtr aObj = aPrsList.first().object();
184 FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
185 const std::set<AttributePtr>& aRefsList = aFeature->data()->refsToMe();
186 std::set<AttributePtr>::const_iterator aIt;
187 FeaturePtr aCoincident;
188 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
189 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
190 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
191 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
192 std::shared_ptr<GeomAPI_Pnt2d> a2dPnt =
193 getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
194 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
195 aCoincident = aConstrFeature;
198 a2dPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
199 if (a2dPnt.get() && aSelPnt->isEqual(a2dPnt)) {
200 aCoincident = aConstrFeature;
206 // If we have coincidence then add Detach menu
207 if (aCoincident.get() != NULL) {
208 mySelectedFeature = aCoincident;
209 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_A());
210 findCoincidences(mySelectedFeature, myCoinsideLines, SketchPlugin_ConstraintCoincidence::ENTITY_B());
211 if (myCoinsideLines.size() > 0) {
213 QMenu* aSubMenu = theMenu->addMenu(tr("Detach"));
216 foreach (FeaturePtr aCoins, myCoinsideLines) {
217 aAction = aSubMenu->addAction(aCoins->data()->name().c_str());
218 aAction->setData(QVariant(i));
221 connect(aSubMenu, SIGNAL(hovered(QAction*)), SLOT(onLineHighlighted(QAction*)));
222 connect(aSubMenu, SIGNAL(aboutToHide()), SLOT(onDetachMenuHide()));
223 connect(aSubMenu, SIGNAL(triggered(QAction*)), SLOT(onLineDetach(QAction*)));
229 if ((!aIsDetach) && hasFeature) {
230 theMenu->addAction(theStdActions["DELETE_CMD"]);
235 if (canSetAuxiliary(isAuxiliary)) {
236 QAction* anAction = action("AUXILIARY_CMD");
237 theMenu->addAction(anAction);
238 anAction->setChecked(isAuxiliary);
243 void PartSet_MenuMgr::onLineHighlighted(QAction* theAction)
245 if (myPrevId != -1) {
246 // Restore color for previous object
247 setLineColor(myPrevId, myColor, false);
249 myPrevId = theAction->data().toInt();
250 myColor = setLineColor(myPrevId, Qt::white, true);
253 QColor PartSet_MenuMgr::setLineColor(int theId, const QColor theColor, bool theUpdate)
255 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
256 XGUI_Workshop* aWorkshop = aConnector->workshop();
257 XGUI_Displayer* aDisplayer = aWorkshop->displayer();
259 FeaturePtr aLine = myCoinsideLines.at(myPrevId);
260 std::list<ResultPtr>::const_iterator aIt;
261 const std::list<ResultPtr>& aResults = aLine->results();
263 for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) {
264 aColor = aDisplayer->setObjectColor((*aIt), theColor, false);
267 aDisplayer->updateViewer();
272 void PartSet_MenuMgr::onLineDetach(QAction* theAction)
274 int aId = theAction->data().toInt();
275 FeaturePtr aLine = myCoinsideLines.at(aId);
276 std::shared_ptr<GeomAPI_Pnt2d> aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
277 if (aOrig.get() == NULL)
278 aOrig = getPoint(mySelectedFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
280 gp_Pnt aOr = aOrig->impl<gp_Pnt>();
281 const std::set<AttributePtr>& aRefsList = aLine->data()->refsToMe();
283 QObjectPtrList aToDelFeatures;
284 std::set<AttributePtr>::const_iterator aIt;
285 // Find all coincedences corresponded to the selected line in the selected point
286 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
287 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
288 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
289 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
290 std::shared_ptr<GeomAPI_Pnt2d> aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A());
291 if (aPnt.get() == NULL)
292 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
293 if (aPnt.get() == NULL)
295 gp_Pnt aP = aPnt->impl<gp_Pnt>();
296 if (aOrig->isEqual(aPnt)) {
297 aToDelFeatures.append(aConstrFeature);
299 aPnt = getPoint(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B());
300 aP = aPnt->impl<gp_Pnt>();
301 if (aOrig->isEqual(aPnt)) {
302 aToDelFeatures.append(aConstrFeature);
308 if (aToDelFeatures.size() > 0) {
309 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
310 XGUI_Workshop* aWorkshop = aConnector->workshop();
311 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
312 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
313 anOperation->abort();
315 SessionPtr aMgr = ModelAPI_Session::get();
316 std::set<FeaturePtr> anIgnoredFeatures;
317 anIgnoredFeatures.insert(myModule->sketchMgr()->activeSketch());
319 QString aName = tr("Detach %1").arg(aLine->data()->name().c_str());
320 aMgr->startOperation(aName.toStdString());
321 aWorkshop->deleteFeatures(aToDelFeatures, anIgnoredFeatures);
322 aMgr->finishOperation();
324 myCoinsideLines.clear();
328 void PartSet_MenuMgr::onDetachMenuHide()
330 if (myPrevId != -1) {
331 // Restore color for previous object
332 setLineColor(myPrevId, myColor, false);
334 // Clear previous definitions
339 void PartSet_MenuMgr::setAuxiliary(const bool isChecked)
341 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
343 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
344 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
348 QObjectPtrList anObjects;
349 bool isUseTransaction = false;
350 // 1. change auxiliary type of a created feature
351 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
352 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
353 anObjects.append(anOperation->feature());
356 isUseTransaction = true;
357 // 2. change auxiliary type of selected sketch entities
358 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
359 anObjects = aSelection->selectedPresentations();
362 QAction* anAction = action("AUXILIARY_CMD");
363 SessionPtr aMgr = ModelAPI_Session::get();
364 if (isUseTransaction) {
365 if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
366 anOperation->abort();
367 aMgr->startOperation(anAction->text().toStdString());
369 myModule->sketchMgr()->storeSelection();
371 if (anObjects.size() > 0) {
372 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
373 for (; anIt != aLast; anIt++) {
374 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
375 if (aFeature.get() != NULL) {
376 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
377 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
378 if (aSketchFeature.get() != NULL) {
379 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
381 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
382 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
384 anAuxiliaryAttr->setValue(isChecked);
389 if (isUseTransaction) {
390 aMgr->finishOperation();
391 XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
392 XGUI_Workshop* aWorkshop = aConnector->workshop();
393 aWorkshop->updateCommandStatus();
396 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
397 myModule->sketchMgr()->restoreSelection();
400 bool PartSet_MenuMgr::canSetAuxiliary(bool& theValue) const
402 bool anEnabled = false;
403 ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
405 bool isActiveSketch = PartSet_SketcherMgr::isSketchOperation(anOperation) ||
406 PartSet_SketcherMgr::isNestedSketchOperation(anOperation);
410 QObjectPtrList anObjects;
411 // 1. change auxiliary type of a created feature
412 if (PartSet_SketcherMgr::isNestedCreateOperation(anOperation) &&
413 PartSet_SketcherMgr::isEntity(anOperation->id().toStdString()) ) {
414 anObjects.append(anOperation->feature());
417 /// The operation should not be aborted here, because the method does not changed
418 /// the auxilliary state, but checks the possibility to perform this
419 ///if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation))
420 /// anOperation->abort();
421 // 2. change auxiliary type of selected sketch entities
422 ModuleBase_ISelection* aSelection = myModule->workshop()->selection();
423 anObjects = aSelection->selectedPresentations();
426 bool isNotAuxiliaryFound = false;
427 if (anObjects.size() > 0) {
428 QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end();
429 for (; anIt != aLast && !isNotAuxiliaryFound; anIt++) {
430 FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
431 if ((aFeature.get() != NULL) && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
433 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
434 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
435 if (aSketchFeature.get() != NULL) {
436 std::string anAttribute = SketchPlugin_SketchEntity::AUXILIARY_ID();
438 std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
439 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(aSketchFeature->data()->attribute(anAttribute));
441 isNotAuxiliaryFound = !anAuxiliaryAttr->value();
446 theValue = anObjects.size() && !isNotAuxiliaryFound;