Salome HOME
Regression during edit operation. Edit sketch, select a line, as a result the propert...
[modules/shaper.git] / src / PartSet / PartSet_OperationFeatureEdit.cpp
1 // File:        PartSet_OperationFeatureEdit.h
2 // Created:     05 May 2014
3 // Author:      Natalia ERMOLAEVA
4
5 #include <PartSet_OperationFeatureEdit.h>
6 #include <PartSet_Tools.h>
7 #include <PartSet_OperationSketch.h>
8 #include <SketchPlugin_Constraint.h>
9
10 #include <ModuleBase_OperationDescription.h>
11 #include <ModuleBase_WidgetEditor.h>
12 #include <ModuleBase_ViewerPrs.h>
13 #include <ModuleBase_IPropertyPanel.h>
14 #include <ModuleBase_ISelection.h>
15 #include <ModuleBase_IViewer.h>
16
17 #include <ModelAPI_Events.h>
18
19 #include <SketchPlugin_Feature.h>
20 #include <GeomDataAPI_Point2D.h>
21
22 #include <ModelAPI_Data.h>
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_Events.h>
25
26 #include <Events_Loop.h>
27
28 #include <SketchPlugin_Line.h>
29
30 #include <V3d_View.hxx>
31 #include <TopoDS_Vertex.hxx>
32 #include <TopoDS.hxx>
33 #include <BRep_Tool.hxx>
34 #include <AIS_DimensionOwner.hxx>
35 #include <AIS_DimensionSelectionMode.hxx>
36
37 #ifdef _DEBUG
38 #include <QDebug>
39 #endif
40
41 #include <QMouseEvent>
42
43 using namespace std;
44
45 PartSet_OperationFeatureEdit::PartSet_OperationFeatureEdit(const QString& theId,
46                                                            QObject* theParent,
47                                                            CompositeFeaturePtr theFeature)
48     : PartSet_OperationFeatureBase(theId, theParent, theFeature),
49       myIsBlockedSelection(false), myIsMultiOperation(false)
50 {
51   myIsEditing = true;
52 }
53
54 PartSet_OperationFeatureEdit::~PartSet_OperationFeatureEdit()
55 {
56 }
57
58 void PartSet_OperationFeatureEdit::initSelection(ModuleBase_ISelection* theSelection,
59                                                       ModuleBase_IViewer* theViewer)
60 {
61   PartSet_OperationFeatureBase::initSelection(theSelection, theViewer);
62   // 1. unite selected and hightlighted objects in order to have an opportunity to drag
63   // by the highlighted object
64   QList<ModuleBase_ViewerPrs> aFeatures = theSelection->getSelected();
65   QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
66   // add highlighted elements if they are not selected
67   foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
68     if (!PartSet_Tools::isContainPresentation(aFeatures, aPrs))
69       aFeatures.append(aPrs);
70   }
71   myIsMultiOperation = aFeatures.size() > 1; 
72
73   // 1. find all features with skipping features with selected vertex shapes
74   myFeature2Attribute.clear();
75   // firstly, collect the features without local selection
76   foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
77     const TopoDS_Shape& aShape = aPrs.shape();
78     if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
79       const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
80       if (!aVertex.IsNull()) {
81         continue;
82       }
83     }
84     else {
85       ObjectPtr aObject = aPrs.object();
86       if (!aObject)
87         continue;
88       FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
89       if (aFeature && myFeature2Attribute.find(aFeature) == myFeature2Attribute.end()) {
90         std::list<std::string> aList;
91         // using an empty list as a sign, that this feature should be moved itself
92         myFeature2Attribute[aFeature] = aList;
93       }
94     }
95   }
96   // 2. collect the features with a local selection on them.
97   // if the list already has this feature, the local selection is skipped
98   // that means that if the selection contains a feature and a feature with local selected point,
99   // the edit is performed for a full feature
100   Handle(V3d_View) aView = theViewer->activeView();
101   foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
102     const TopoDS_Shape& aShape = aPrs.shape();
103     if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
104       const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
105       if (aVertex.IsNull())
106         continue;
107       ObjectPtr aObject = aPrs.object();
108       if (!aObject)
109         continue;
110       FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
111       if (!aFeature)
112         continue;
113       // if the feature is already moved, do nothing for this feature local selection
114       if (myFeature2Attribute.find(aFeature) != myFeature2Attribute.end())
115         continue;
116
117       // append the attribute of the vertex if it is found on the current feature
118       gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
119       double aVX, aVY;
120       PartSet_Tools::convertTo2D(aPoint, sketch(), aView, aVX, aVY);
121       boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = PartSet_Tools::getFeaturePoint(
122                                                                     aFeature, aVX, aVY);
123       std::string anAttribute = aFeature->data()->id(aPoint2D);
124       std::list<std::string> aList;
125       if (myFeature2Attribute.find(aFeature) != myFeature2Attribute.end())
126         aList = myFeature2Attribute[aFeature];
127
128       aList.push_back(anAttribute);
129       myFeature2Attribute[aFeature] = aList;
130     }
131   }
132 }
133
134 void PartSet_OperationFeatureEdit::mousePressed(QMouseEvent* theEvent, ModuleBase_IViewer* theViewer, ModuleBase_ISelection* theSelection)
135 {
136   if (myIsMultiOperation)
137     return;
138
139   ModuleBase_ModelWidget* aActiveWgt = myPropertyPanel->activeWidget();
140   if(aActiveWgt && aActiveWgt->isViewerSelector()) {
141     // Almost do nothing, all stuff in on PartSet_OperationFeatureBase::mouseReleased
142     PartSet_OperationFeatureBase::mousePressed(theEvent, theViewer, theSelection);
143     return;
144   }
145   QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
146   QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
147   bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
148   if (aHasShift && !aHighlighted.empty()) {
149     foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
150       aSelected.append(aPrs);
151     }
152   }
153   ObjectPtr aObject;
154   /*if (!aSelected.empty()) {
155     aObject = aSelected.first().object();
156   } else {   
157     if (!aHighlighted.empty())
158       aObject = aHighlighted.first().object();
159   }*/
160   // the priority to a highlighted object in order to edit it, even if the selected object is
161   // the feature of this operation. Otherwise, the highlighting is ignored and the selected
162   // object is moved
163   if (!aHighlighted.empty()) {
164     aObject = aHighlighted.front().object();
165   }
166   if (!aObject && !aSelected.empty())  // changed for a constrain
167     aObject = aSelected.front().object();
168
169   FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
170   if (!aFeature || aFeature != feature() || (aSelected.size() > 1)) {
171     if (commit()) {
172       theViewer->enableSelection(true);
173       emit featureConstructed(feature(), FM_Deactivation);
174
175       // If we have selection and prehilighting with shift pressed 
176       // Then we have to select all these objects and restart as multi edit operfation
177       //bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
178       //if (aHasShift && !theHighlighted.empty()) {
179       //  QList<ObjectPtr> aSelected;
180       //  std::list<ModuleBase_ViewerPrs>::const_iterator aIt;
181       //  for (aIt = theSelected.cbegin(); aIt != theSelected.cend(); ++aIt)
182       //    aSelected.append((*aIt).object());
183
184       //  for (aIt = theHighlighted.cbegin(); aIt != theHighlighted.cend(); ++aIt) {
185       //    if (!aSelected.contains((*aIt).object()))
186       //      aSelected.append((*aIt).object());
187       //  }
188       //  emit setSelection(aSelected);
189       //} else 
190       if (aFeature) {
191         std::string anOperationType = PartSet_OperationFeatureEdit::Type();
192         restartOperation(anOperationType, aFeature);
193       }
194       //}
195     }
196   }
197 }
198
199 void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_IViewer* theViewer)
200 {
201   if (!(theEvent->buttons() & Qt::LeftButton))
202     return;
203   Handle(V3d_View) aView = theViewer->activeView();
204   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
205
206   theViewer->enableSelection(false);
207
208   //blockSelection(true);
209   if (myCurPoint.myIsInitialized) {
210     double aCurX, aCurY;
211     PartSet_Tools::convertTo2D(myCurPoint.myPoint, sketch(), aView, aCurX, aCurY);
212
213     double aX, anY;
214     PartSet_Tools::convertTo2D(aPoint, sketch(), aView, aX, anY);
215
216     double aDeltaX = aX - aCurX;
217     double aDeltaY = anY - aCurY;
218
219     if (myIsMultiOperation) {
220       std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
221       while (aFeatIter != myFeature2Attribute.end()) {
222         FeaturePtr aFeature = aFeatIter->first;
223         std::list<std::string> anAttributes = aFeatIter->second;
224         // perform edit for the feature
225         if (anAttributes.empty()) {
226           boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
227                                          boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
228           if (aSketchFeature) {
229             aSketchFeature->move(aDeltaX, aDeltaY);
230           }
231         }
232         // perform edit for the feature's attribute
233         else {
234           std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
235                                                  anAttrEnd = anAttributes.end();
236           for (; anAttrIter != anAttrEnd; anAttrIter++) {
237             boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
238                              GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
239             if (aPointAttr) {
240               aPointAttr->move(aDeltaX, aDeltaY);
241             }
242           }      
243         }
244         aFeatIter++;
245       }
246     }
247     else { // multieditoperation
248
249     boost::shared_ptr<SketchPlugin_Feature> aSketchFeature = boost::dynamic_pointer_cast<
250         SketchPlugin_Feature>(feature());
251
252     bool isMoved = false;
253     // the functionality to move the feature attribute if it exists in the internal map
254     std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
255     while (aFeatIter != myFeature2Attribute.end()) {
256       FeaturePtr aFeature = aFeatIter->first;
257       std::list<std::string> anAttributes = aFeatIter->second;
258       // perform edit for the feature
259       /*if (anAttributes.empty()) {
260         boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
261                                        boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
262         if (aSketchFeature) {
263           aSketchFeature->move(aDeltaX, aDeltaY);
264         }
265       }*/
266       // perform edit for the feature's attribute
267       //else {
268       if (!anAttributes.empty()) {
269         std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
270                                                anAttrEnd = anAttributes.end();
271         for (; anAttrIter != anAttrEnd; anAttrIter++) {
272           boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
273                            GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
274           if (aPointAttr) {
275             aPointAttr->move(aDeltaX, aDeltaY);
276             isMoved = true;
277           }
278         }      
279       }
280       aFeatIter++;
281     }
282
283     // the feature is moved only if there is no a local selection on this feature
284     if (!isMoved) {
285       // MPV: added condition because it could be external edge of some object, not sketch
286       if (aSketchFeature && sketch()->isSub(aSketchFeature)) {
287         aSketchFeature->move(aDeltaX, aDeltaY);
288         static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
289         ModelAPI_EventCreator::get()->sendUpdated(feature(), anEvent);
290       }
291     }
292     } // multieditoperation
293   }
294   sendFeatures();
295
296   myCurPoint.setPoint(aPoint);
297 }
298
299 void PartSet_OperationFeatureEdit::mouseReleased(
300     QMouseEvent* theEvent, ModuleBase_IViewer* theViewer,
301     ModuleBase_ISelection* theSelection)
302 {
303   theViewer->enableSelection(true);
304   if (myIsMultiOperation) {
305     if (commit()) {
306       std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
307       while (aFeatIter != myFeature2Attribute.end()) {
308         FeaturePtr aFeature = aFeatIter->first;
309         if (aFeature) {
310           emit featureConstructed(aFeature, FM_Deactivation);
311         }
312         aFeatIter++;
313       }
314     }
315   }
316   else { // multieditoperation
317   ModuleBase_ModelWidget* aActiveWgt = 0;
318   if (myPropertyPanel)
319     aActiveWgt = myPropertyPanel->activeWidget();
320   if(aActiveWgt && aActiveWgt->isViewerSelector()) {
321     // Almost do nothing, all stuff in on PartSet_OperationFeatureBase::mouseReleased
322     PartSet_OperationFeatureBase::mouseReleased(theEvent, theViewer, theSelection);
323   }// else {
324     //blockSelection(false);
325   //}
326   } // multieditoperation
327 }
328
329 void PartSet_OperationFeatureEdit::mouseDoubleClick(
330     QMouseEvent* theEvent, Handle_V3d_View theView,
331     ModuleBase_ISelection* theSelection)
332 {
333   // TODO the functionality is important only for constraint feature. Should be moved in another place
334   QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
335   if (!aSelected.empty()) {
336     ModuleBase_ViewerPrs aFeaturePrs = aSelected.first();
337     if (!aFeaturePrs.owner().IsNull()) {
338       Handle(AIS_DimensionOwner) anOwner = Handle(AIS_DimensionOwner)::DownCast(
339           aFeaturePrs.owner());
340       if (!anOwner.IsNull() && anOwner->SelectionMode() == AIS_DSM_Text) {
341         bool isValid;
342         double aValue = PartSet_Tools::featureValue(feature(), SketchPlugin_Constraint::VALUE(),
343                                                     isValid);
344         if (isValid) {
345           ModuleBase_WidgetEditor::editFeatureValue(feature(), SketchPlugin_Constraint::VALUE());
346           flushUpdated();
347         }
348       }
349     }
350   }
351 }
352
353 void PartSet_OperationFeatureEdit::startOperation()
354 {
355   PartSet_OperationSketchBase::startOperation();
356   //emit multiSelectionEnabled(false);
357
358   myCurPoint.clear();
359 }
360
361 void PartSet_OperationFeatureEdit::stopOperation()
362 {
363   //emit multiSelectionEnabled(true);
364
365   //blockSelection(false, false);
366
367   myFeature2Attribute.clear();
368 }
369
370 //void PartSet_OperationFeatureEdit::blockSelection(bool isBlocked, const bool isRestoreSelection)
371 //{
372 //  if (myIsBlockedSelection == isBlocked)
373 //    return;
374 //
375 //  myIsBlockedSelection = isBlocked;
376 //  QList<ObjectPtr> aFeatureList;
377 //  aFeatureList.append(feature());
378 //
379 //  //if (isBlocked) {
380 //  //  emit setSelection(QList<ObjectPtr>());
381 //  //  emit stopSelection(aFeatureList, true);
382 //  //} else {
383 //  //  emit stopSelection(aFeatureList, false);
384 //  //  if (isRestoreSelection)
385 //  //    emit setSelection(aFeatureList);
386 //  //}
387 //}
388
389 FeaturePtr PartSet_OperationFeatureEdit::createFeature(const bool theFlushMessage,
390   CompositeFeaturePtr theCompositeFeature)
391 {
392   // do nothing in order to do not create a new feature
393   return FeaturePtr();
394 }
395
396 void PartSet_OperationFeatureEdit::sendFeatures()
397 {
398   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
399
400   std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
401   while (aFeatIter != myFeature2Attribute.end()) {
402     FeaturePtr aFeature = aFeatIter->first;
403     if (aFeature) {
404       ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
405     }
406     aFeatIter++;
407   }
408
409   Events_Loop::loop()->flush(anEvent);
410   flushUpdated();
411 }
412