Salome HOME
2.17. Improved management of overconstraint situation: temporary modification to...
[modules/shaper.git] / src / PartSet / PartSet_OverconstraintListener.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        SketcherPrs_Angle.cpp
4 // Created:     20 August 2015
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_OverconstraintListener.h"
8
9 #include "XGUI_ModuleConnector.h"
10 #include "XGUI_Workshop.h"
11 #include "XGUI_Displayer.h"
12
13 #include "SketcherPrs_SymbolPrs.h"
14 #include "SketchPlugin_SketchEntity.h"
15
16 #include "Events_Loop.h"
17
18 #include <GeomAPI_IPresentable.h>
19 #include <ModelAPI_Events.h>
20 #include <ModuleBase_Tools.h>
21
22 #include <QString>
23
24 #define DEBUG_FEATURE_OVERCONSTRAINT_LISTENER
25
26 PartSet_OverconstraintListener::PartSet_OverconstraintListener(ModuleBase_IWorkshop* theWorkshop)
27 : myWorkshop(theWorkshop)
28 {
29   Events_Loop* aLoop = Events_Loop::loop();
30   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
31   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
32 }
33
34 bool PartSet_OverconstraintListener::isConflictingObject(const ObjectPtr& theObject)
35 {
36   return myConflictingObjects.find(theObject) != myConflictingObjects.end();
37 }
38
39 void PartSet_OverconstraintListener::getConflictingColor(std::vector<int>& theColor)
40 {
41   Quantity_Color aColor = ModuleBase_Tools::color("Visualization", "sketch_overconstraint_color",
42                                                   SKETCH_OVERCONSTRAINT_COLOR);
43
44   theColor.push_back(aColor.Red()*255.);
45   theColor.push_back(aColor.Green()*255.);
46   theColor.push_back(aColor.Blue()*255.);
47 }
48
49 void PartSet_OverconstraintListener::processEvent(
50                                                  const std::shared_ptr<Events_Message>& theMessage)
51 {
52
53 #ifdef DEBUG_FEATURE_OVERCONSTRAINT_LISTENER
54   bool isRepaired = theMessage->eventID() == Events_Loop::eventByName(EVENT_SOLVER_REPAIRED);
55   qDebug(QString("PartSet_OverconstraintListener::processEvent:\n %1").arg(isRepaired ? "REPAIRED" : "FAILED").toStdString().c_str());
56 #endif
57
58   if (theMessage->eventID() == Events_Loop::eventByName(EVENT_SOLVER_FAILED) ||
59              theMessage->eventID() == Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)) {
60     std::shared_ptr<ModelAPI_SolverFailedMessage> anErrorMsg =
61                    std::dynamic_pointer_cast<ModelAPI_SolverFailedMessage>(theMessage);
62     bool anUpdated = false;
63     if (anErrorMsg.get()) {
64       const std::set<ObjectPtr>& aConflictingObjects = anErrorMsg->objects();
65       anUpdated = updateConflictingObjects(aConflictingObjects);
66     }
67     else
68       anUpdated = updateConflictingObjects(std::set<ObjectPtr>());
69   }
70 }
71
72 bool PartSet_OverconstraintListener::updateConflictingObjects(
73                                                   const std::set<ObjectPtr>& theConflictingObjects)
74 {
75   std::set<ObjectPtr>::const_iterator anIt, aLast;
76
77 #ifdef DEBUG_FEATURE_OVERCONSTRAINT_LISTENER
78   anIt = theConflictingObjects.begin();
79   aLast = theConflictingObjects.end();
80
81   QStringList anInfo;
82   for (; anIt != aLast; ++anIt) {
83     anInfo.append(ModuleBase_Tools::objectInfo((*anIt)));
84   }
85   QString anInfoStr = anInfo.join(";\n");
86   qDebug(QString("PartSet_OverconstraintListener::updateConflictingObjects: %1: \n%2").arg(theConflictingObjects.size())
87                                                                                     .arg(anInfoStr).toStdString().c_str());
88 #endif
89
90   bool isUpdated = false;
91   std::set<ObjectPtr> aModifiedObjects;
92   // erase error state of absent current objects in the parameter list
93   for (anIt = myConflictingObjects.begin(), aLast = myConflictingObjects.end() ; anIt != aLast; anIt++) {
94     ObjectPtr anObject = *anIt;
95     if (theConflictingObjects.find(anObject) == theConflictingObjects.end()) { // it is not found
96       setConflictingObject(anObject, false);
97       aModifiedObjects.insert(anObject);
98     }
99   }
100
101   // erase absent objects from the internal container
102   for (anIt = aModifiedObjects.begin(), aLast = aModifiedObjects.end(); anIt != aLast; anIt++) {
103     myConflictingObjects.erase(*anIt);
104   }
105
106   // set error state for new objects and append them in the internal map of objects
107   for (anIt = theConflictingObjects.begin(), aLast = theConflictingObjects.end() ; anIt != aLast; anIt++) {
108     ObjectPtr anObject = *anIt;
109     if (myConflictingObjects.find(anObject) == myConflictingObjects.end()) { // it is not found
110       setConflictingObject(anObject, true);
111       aModifiedObjects.insert(anObject);
112       myConflictingObjects.insert(anObject);
113     }
114   }
115   isUpdated = !aModifiedObjects.empty();
116   if (isUpdated)
117     redisplayObjects(aModifiedObjects);
118
119   return isUpdated;
120 }
121
122 void PartSet_OverconstraintListener::redisplayObjects(
123                                               const std::set<ObjectPtr>& theObjects)
124 {
125 /*static Events_Loop* aLoop = Events_Loop::loop();
126   static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_UPDATED);
127
128   static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
129
130   std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
131   for (; anIt != aLast; anIt++) {
132     aECreator->sendUpdated(*anIt, EVENT_DISP);
133
134     //#ifdef DEBUG_FEATURE_OVERCONSTRAINT_LISTENER
135     //  QString anInfoStr = ModuleBase_Tools::objectInfo(*anIt);
136     //  qDebug(QString("PartSet_OverconstraintListener::SEND UPDATED: %1").arg(anInfoStr).toStdString().c_str());
137     //#endif
138   }
139   aLoop->flush(EVENT_DISP);*/
140
141   XGUI_Displayer* aDisplayer = workshop()->displayer();
142   bool aHidden;
143   std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(), aLast = theObjects.end();
144   for (; anIt != aLast; anIt++) {
145     ObjectPtr anObject = *anIt;
146     aHidden = !anObject->data() || !anObject->data()->isValid() || 
147                anObject->isDisabled() || (!anObject->isDisplayed());
148     if (!aHidden)
149       aDisplayer->redisplay(anObject, false);
150   }
151   aDisplayer->updateViewer();
152 }
153
154 void PartSet_OverconstraintListener::setConflictingObject(const ObjectPtr& theObject,
155                                                           const bool theConflicting)
156 {
157   AISObjectPtr anAISObject;
158   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(theObject);
159
160   if (aPrs.get() != NULL) {
161     XGUI_Workshop* aWorkshop = workshop();
162     XGUI_Displayer* aDisplayer = aWorkshop->displayer();
163
164     anAISObject = aPrs->getAISObject(aDisplayer->getAISObject(theObject));
165     if (anAISObject.get()) {
166       Handle(AIS_InteractiveObject) anAISIO = anAISObject->impl<Handle(AIS_InteractiveObject)>();
167       if (!anAISIO.IsNull()) {
168         if (!Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO).IsNull()) {
169           Handle(SketcherPrs_SymbolPrs) aPrs = Handle(SketcherPrs_SymbolPrs)::DownCast(anAISIO);
170           if (!aPrs.IsNull())
171             aPrs->SetConflictingConstraint(theConflicting);
172         }
173       }
174     }
175   }
176 }
177
178 XGUI_Workshop* PartSet_OverconstraintListener::workshop() const
179 {
180   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
181   return aConnector->workshop();
182 }
183