1 // File: PartSet_OperationFeatureEdit.h
2 // Created: 05 May 2014
3 // Author: Natalia ERMOLAEVA
5 #include <PartSet_OperationFeatureEdit.h>
6 #include <PartSet_Tools.h>
7 #include <PartSet_OperationSketch.h>
8 #include <SketchPlugin_Constraint.h>
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>
17 #include <ModelAPI_Events.h>
19 #include <SketchPlugin_Feature.h>
20 #include <GeomDataAPI_Point2D.h>
22 #include <ModelAPI_Data.h>
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_Events.h>
26 #include <Events_Loop.h>
28 #include <SketchPlugin_Line.h>
30 #include <V3d_View.hxx>
31 #include <TopoDS_Vertex.hxx>
33 #include <BRep_Tool.hxx>
34 #include <AIS_DimensionOwner.hxx>
35 #include <AIS_DimensionSelectionMode.hxx>
41 #include <QMouseEvent>
45 PartSet_OperationFeatureEdit::PartSet_OperationFeatureEdit(const QString& theId,
47 CompositeFeaturePtr theFeature)
48 : PartSet_OperationFeatureBase(theId, theParent, theFeature),
49 myIsBlockedSelection(false)
54 PartSet_OperationFeatureEdit::~PartSet_OperationFeatureEdit()
58 void PartSet_OperationFeatureEdit::initSelection(ModuleBase_ISelection* theSelection,
59 ModuleBase_IViewer* theViewer)
61 // the method of the parent should is useless here because it processes the given
62 // selection in different way
63 //PartSet_OperationFeatureBase::initSelection(theSelection, theViewer);
65 // 1. unite selected and hightlighted objects in order to have an opportunity to drag
66 // by the highlighted object
67 QList<ModuleBase_ViewerPrs> aFeatures = theSelection->getSelected();
68 QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
69 // add highlighted elements if they are not selected
70 foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
71 if (!PartSet_Tools::isContainPresentation(aFeatures, aPrs))
72 aFeatures.append(aPrs);
75 // 1. find all features with skipping features with selected vertex shapes
76 myFeature2Attribute.clear();
77 // firstly, collect the features without local selection
78 foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
79 const TopoDS_Shape& aShape = aPrs.shape();
80 if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
81 const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
82 if (!aVertex.IsNull()) {
87 ObjectPtr aObject = aPrs.object();
90 FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
91 if (aFeature && myFeature2Attribute.find(aFeature) == myFeature2Attribute.end()) {
92 std::list<std::string> aList;
93 // using an empty list as a sign, that this feature should be moved itself
94 myFeature2Attribute[aFeature] = aList;
98 // 2. collect the features with a local selection on them.
99 // if the list already has this feature, the local selection is skipped
100 // that means that if the selection contains a feature and a feature with local selected point,
101 // the edit is performed for a full feature
102 Handle(V3d_View) aView = theViewer->activeView();
103 foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
104 const TopoDS_Shape& aShape = aPrs.shape();
105 if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
106 const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
107 if (aVertex.IsNull())
109 ObjectPtr aObject = aPrs.object();
112 FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
116 // append the attribute of the vertex if it is found on the current feature
117 gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
119 PartSet_Tools::convertTo2D(aPoint, sketch(), aView, aVX, aVY);
120 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = PartSet_Tools::getFeaturePoint(
122 std::string anAttribute = aFeature->data()->id(aPoint2D);
123 std::list<std::string> aList;
124 if (myFeature2Attribute.find(aFeature) != myFeature2Attribute.end())
125 aList = myFeature2Attribute[aFeature];
127 aList.push_back(anAttribute);
128 myFeature2Attribute[aFeature] = aList;
133 void PartSet_OperationFeatureEdit::mousePressed(QMouseEvent* theEvent, ModuleBase_IViewer* theViewer, ModuleBase_ISelection* theSelection)
135 ModuleBase_ModelWidget* aActiveWgt = myPropertyPanel->activeWidget();
136 if(aActiveWgt && aActiveWgt->isViewerSelector()) {
137 // Almost do nothing, all stuff in on PartSet_OperationFeatureBase::mouseReleased
138 PartSet_OperationFeatureBase::mousePressed(theEvent, theViewer, theSelection);
142 // commit always until the selection restore is realized (for feature and local selection)
143 // TODO: check whether the selection is changed and restart the operation only if it is modified
145 emitFeaturesDeactivation();
146 // find nearest feature and restart the operation for it
147 Handle(V3d_View) aView = theViewer->activeView();
148 QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
149 QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
151 ObjectPtr aFeature = PartSet_Tools::nearestFeature(theEvent->pos(), aView, sketch(),
152 aSelected, aHighlighted);
154 restartOperation(PartSet_OperationFeatureEdit::Type(), aFeature);
157 // the next code is commented because the new attempt to commit/restart operation implementation:
158 //QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
159 //QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
160 //bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
161 //if (aHasShift && !aHighlighted.empty()) {
162 // foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
163 // aSelected.append(aPrs);
167 ///*if (!aSelected.empty()) {
168 // aObject = aSelected.first().object();
170 // if (!aHighlighted.empty())
171 // aObject = aHighlighted.first().object();
173 //// the priority to a highlighted object in order to edit it, even if the selected object is
174 //// the feature of this operation. Otherwise, the highlighting is ignored and the selected
176 //if (!aHighlighted.empty()) {
177 // aObject = aHighlighted.front().object();
179 //if (!aObject && !aSelected.empty()) // changed for a constrain
180 // aObject = aSelected.front().object();
182 //FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
183 //if (!aFeature || aFeature != feature() || (aSelected.size() > 1)) {
185 // theViewer->enableSelection(true);
186 // emit featureConstructed(feature(), FM_Deactivation);
188 // // If we have selection and prehilighting with shift pressed
189 // // Then we have to select all these objects and restart as multi edit operfation
190 // //bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
191 // //if (aHasShift && !theHighlighted.empty()) {
192 // // QList<ObjectPtr> aSelected;
193 // // std::list<ModuleBase_ViewerPrs>::const_iterator aIt;
194 // // for (aIt = theSelected.cbegin(); aIt != theSelected.cend(); ++aIt)
195 // // aSelected.append((*aIt).object());
197 // // for (aIt = theHighlighted.cbegin(); aIt != theHighlighted.cend(); ++aIt) {
198 // // if (!aSelected.contains((*aIt).object()))
199 // // aSelected.append((*aIt).object());
201 // // emit setSelection(aSelected);
204 // std::string anOperationType = PartSet_OperationFeatureEdit::Type();
205 // restartOperation(anOperationType, aFeature);
212 void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_IViewer* theViewer)
214 if (!(theEvent->buttons() & Qt::LeftButton))
216 Handle(V3d_View) aView = theViewer->activeView();
217 gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
219 theViewer->enableSelection(false);
221 //blockSelection(true);
222 if (myCurPoint.myIsInitialized) {
224 PartSet_Tools::convertTo2D(myCurPoint.myPoint, sketch(), aView, aCurX, aCurY);
227 PartSet_Tools::convertTo2D(aPoint, sketch(), aView, aX, anY);
229 double aDeltaX = aX - aCurX;
230 double aDeltaY = anY - aCurY;
232 // the next code is commented because it is obsolete by the multi edit operation realization here
233 //if (myIsMultiOperation) {
234 // std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
235 // while (aFeatIter != myFeature2Attribute.end()) {
236 // FeaturePtr aFeature = aFeatIter->first;
237 // std::list<std::string> anAttributes = aFeatIter->second;
238 // // perform edit for the feature
239 // if (anAttributes.empty()) {
240 // boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
241 // boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
242 // if (aSketchFeature) {
243 // aSketchFeature->move(aDeltaX, aDeltaY);
246 // // perform edit for the feature's attribute
248 // std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
249 // anAttrEnd = anAttributes.end();
250 // for (; anAttrIter != anAttrEnd; anAttrIter++) {
251 // boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
252 // GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
254 // aPointAttr->move(aDeltaX, aDeltaY);
261 //else { // multieditoperation
263 //boost::shared_ptr<SketchPlugin_Feature> aSketchFeature = boost::dynamic_pointer_cast<
264 // SketchPlugin_Feature>(feature());
266 bool isMoved = false;
267 // the functionality to move the feature attribute if it exists in the internal map
268 std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
269 while (aFeatIter != myFeature2Attribute.end()) {
270 FeaturePtr aFeature = aFeatIter->first;
271 // MPV: added condition because it could be external edge of some object, not sketch
272 if (aFeature && !sketch()->isSub(aFeature))
275 std::list<std::string> anAttributes = aFeatIter->second;
276 // perform edit for the feature
277 if (anAttributes.empty()) {
278 boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
279 boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
280 if (aSketchFeature) {
281 aSketchFeature->move(aDeltaX, aDeltaY);
285 // perform edit for the feature's attribute
287 std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
288 anAttrEnd = anAttributes.end();
289 for (; anAttrIter != anAttrEnd; anAttrIter++) {
290 boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
291 GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
293 aPointAttr->move(aDeltaX, aDeltaY);
300 // the next code is commented because it is obsolete by the multi edit operation realization here
301 // the feature is moved only if there is no a local selection on this feature
303 // // MPV: added condition because it could be external edge of some object, not sketch
304 // if (aSketchFeature && sketch()->isSub(aSketchFeature)) {
305 // aSketchFeature->move(aDeltaX, aDeltaY);
306 // static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
307 // ModelAPI_EventCreator::get()->sendUpdated(feature(), anEvent);
310 //} // multieditoperation
314 myCurPoint.setPoint(aPoint);
317 void PartSet_OperationFeatureEdit::mouseReleased(
318 QMouseEvent* theEvent, ModuleBase_IViewer* theViewer,
319 ModuleBase_ISelection* theSelection)
321 theViewer->enableSelection(true);
322 // the next code is commented because it is obsolete by the multi edit operation realization here
323 //if (myIsMultiOperation) {
325 // std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
326 // while (aFeatIter != myFeature2Attribute.end()) {
327 // FeaturePtr aFeature = aFeatIter->first;
329 // emit featureConstructed(aFeature, FM_Deactivation);
335 //else { // multieditoperation
336 ModuleBase_ModelWidget* aActiveWgt = 0;
338 aActiveWgt = myPropertyPanel->activeWidget();
339 if(aActiveWgt && aActiveWgt->isViewerSelector()) {
340 // Almost do nothing, all stuff in on PartSet_OperationFeatureBase::mouseReleased
341 PartSet_OperationFeatureBase::mouseReleased(theEvent, theViewer, theSelection);
343 ////blockSelection(false);
345 //} // multieditoperation
348 theViewer->enableSelection(true);
350 // commit operation if there is no selected an highlighted objects anymore
351 Handle(V3d_View) aView = theViewer->activeView();
352 QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
353 QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
355 if (aSelected.empty() && aHighlighted.empty()) {
357 emitFeaturesDeactivation();
362 void PartSet_OperationFeatureEdit::mouseDoubleClick(
363 QMouseEvent* theEvent, Handle_V3d_View theView,
364 ModuleBase_ISelection* theSelection)
366 // TODO the functionality is important only for constraint feature. Should be moved in another place
367 QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
368 if (!aSelected.empty()) {
369 ModuleBase_ViewerPrs aFeaturePrs = aSelected.first();
370 if (!aFeaturePrs.owner().IsNull()) {
371 Handle(AIS_DimensionOwner) anOwner = Handle(AIS_DimensionOwner)::DownCast(
372 aFeaturePrs.owner());
373 if (!anOwner.IsNull() && anOwner->SelectionMode() == AIS_DSM_Text) {
375 double aValue = PartSet_Tools::featureValue(feature(), SketchPlugin_Constraint::VALUE(),
378 ModuleBase_WidgetEditor::editFeatureValue(feature(), SketchPlugin_Constraint::VALUE());
386 void PartSet_OperationFeatureEdit::startOperation()
388 PartSet_OperationSketchBase::startOperation();
389 //emit multiSelectionEnabled(false);
394 void PartSet_OperationFeatureEdit::stopOperation()
396 //emit multiSelectionEnabled(true);
398 //blockSelection(false, false);
400 myFeature2Attribute.clear();
403 //void PartSet_OperationFeatureEdit::blockSelection(bool isBlocked, const bool isRestoreSelection)
405 // if (myIsBlockedSelection == isBlocked)
408 // myIsBlockedSelection = isBlocked;
409 // QList<ObjectPtr> aFeatureList;
410 // aFeatureList.append(feature());
412 // //if (isBlocked) {
413 // // emit setSelection(QList<ObjectPtr>());
414 // // emit stopSelection(aFeatureList, true);
416 // // emit stopSelection(aFeatureList, false);
417 // // if (isRestoreSelection)
418 // // emit setSelection(aFeatureList);
422 FeaturePtr PartSet_OperationFeatureEdit::createFeature(const bool theFlushMessage,
423 CompositeFeaturePtr theCompositeFeature)
425 // do nothing in order to do not create a new feature
429 void PartSet_OperationFeatureEdit::sendFeatures()
431 static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
433 std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
434 while (aFeatIter != myFeature2Attribute.end()) {
435 FeaturePtr aFeature = aFeatIter->first;
437 ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
442 Events_Loop::loop()->flush(anEvent);
446 void PartSet_OperationFeatureEdit::emitFeaturesDeactivation()
448 std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
449 while (aFeatIter != myFeature2Attribute.end()) {
450 FeaturePtr aFeature = aFeatIter->first;
452 emit featureConstructed(aFeature, FM_Deactivation);