Salome HOME
Boost has been removed from code
[modules/shaper.git] / src / PartSet / PartSet_OperationFeatureEdit.cpp
index 1a60197995a8a8c22ae815be93c30790e19f703c..d44dfa3d7f8d51084ac72356951b69aacf3334a8 100644 (file)
@@ -28,9 +28,6 @@
 #include <SketchPlugin_Line.h>
 
 #include <V3d_View.hxx>
-#include <TopoDS_Vertex.hxx>
-#include <TopoDS.hxx>
-#include <BRep_Tool.hxx>
 #include <AIS_DimensionOwner.hxx>
 #include <AIS_DimensionSelectionMode.hxx>
 
@@ -46,7 +43,7 @@ PartSet_OperationFeatureEdit::PartSet_OperationFeatureEdit(const QString& theId,
                                                            QObject* theParent,
                                                            CompositeFeaturePtr theFeature)
     : PartSet_OperationFeatureBase(theId, theParent, theFeature),
-      myIsBlockedSelection(false)
+      myIsBlockedSelection(false), myIsBlockedByDoubleClick(false)
 {
   myIsEditing = true;
 }
@@ -56,42 +53,52 @@ PartSet_OperationFeatureEdit::~PartSet_OperationFeatureEdit()
 }
 
 void PartSet_OperationFeatureEdit::initSelection(ModuleBase_ISelection* theSelection,
-                                                      ModuleBase_IViewer* theViewer)
+                                                 ModuleBase_IViewer* theViewer)
 {
   // the method of the parent should is useless here because it processes the given
   // selection in different way
   //PartSet_OperationFeatureBase::initSelection(theSelection, theViewer);
 
-  // 1. unite selected and hightlighted objects in order to have an opportunity to drag
-  // by the highlighted object
-  QList<ModuleBase_ViewerPrs> aFeatures = theSelection->getSelected();
+  QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
   QList<ModuleBase_ViewerPrs> aHighlighted = theSelection->getHighlighted();
-  // add highlighted elements if they are not selected
+
+  // there is a bug in OCC, where the highlighted objects are repeated and should be
+  // filtered on the unique state here
+  QList<ModuleBase_ViewerPrs> anUniqueHighlighted;
   foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
-    if (!PartSet_Tools::isContainPresentation(aFeatures, aPrs))
-      aFeatures.append(aPrs);
+    if (!PartSet_Tools::isContainPresentation(anUniqueHighlighted, aPrs))
+      anUniqueHighlighted.append(aPrs);
+  }
+  fillFeature2Attribute(anUniqueHighlighted, theViewer, myHighlightedFeature2Attribute);
+
+  foreach (ModuleBase_ViewerPrs aPrs, anUniqueHighlighted) {
+    if (!PartSet_Tools::isContainPresentation(aSelected, aPrs))
+      aSelected.append(aPrs);
   }
+  fillFeature2Attribute(aSelected, theViewer, myAllFeature2Attribute);
+}
 
+void PartSet_OperationFeatureEdit::fillFeature2Attribute(
+                                    const QList<ModuleBase_ViewerPrs>& thePresentations,
+                                    ModuleBase_IViewer* theViewer,
+                                    std::map<FeaturePtr, std::list<std::string> >& theFeature2Attribute)
+{
   // 1. find all features with skipping features with selected vertex shapes
-  myFeature2Attribute.clear();
+  theFeature2Attribute.clear();
   // firstly, collect the features without local selection
-  foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
-    const TopoDS_Shape& aShape = aPrs.shape();
-    if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
-      const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
-      if (!aVertex.IsNull()) {
-        continue;
-      }
-    }
+  double aX, anY;
+  foreach (ModuleBase_ViewerPrs aPrs, thePresentations) {
+    if (getViewerPoint(aPrs, theViewer, aX, anY))
+      continue;
     else {
       ObjectPtr aObject = aPrs.object();
       if (!aObject)
         continue;
       FeaturePtr aFeature = ModelAPI_Feature::feature(aObject);
-      if (aFeature && myFeature2Attribute.find(aFeature) == myFeature2Attribute.end()) {
+      if (aFeature && theFeature2Attribute.find(aFeature) == theFeature2Attribute.end()) {
         std::list<std::string> aList;
         // using an empty list as a sign, that this feature should be moved itself
-        myFeature2Attribute[aFeature] = aList;
+        theFeature2Attribute[aFeature] = aList;
       }
     }
   }
@@ -99,13 +106,8 @@ void PartSet_OperationFeatureEdit::initSelection(ModuleBase_ISelection* theSelec
   // if the list already has this feature, the local selection is skipped
   // that means that if the selection contains a feature and a feature with local selected point,
   // the edit is performed for a full feature
-  Handle(V3d_View) aView = theViewer->activeView();
-  foreach (ModuleBase_ViewerPrs aPrs, aFeatures) {
-    const TopoDS_Shape& aShape = aPrs.shape();
-    if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) { // a point is selected
-      const TopoDS_Vertex& aVertex = TopoDS::Vertex(aShape);
-      if (aVertex.IsNull())
-        continue;
+  foreach (ModuleBase_ViewerPrs aPrs, thePresentations) {
+    if (getViewerPoint(aPrs, theViewer, aX, anY)) {
       ObjectPtr aObject = aPrs.object();
       if (!aObject)
         continue;
@@ -114,18 +116,15 @@ void PartSet_OperationFeatureEdit::initSelection(ModuleBase_ISelection* theSelec
         continue;
 
       // append the attribute of the vertex if it is found on the current feature
-      gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
-      double aVX, aVY;
-      PartSet_Tools::convertTo2D(aPoint, sketch(), aView, aVX, aVY);
-      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = PartSet_Tools::getFeaturePoint(
-                                                                    aFeature, aVX, aVY);
+      std::shared_ptr<GeomDataAPI_Point2D> aPoint2D = PartSet_Tools::getFeaturePoint(
+                                                                    aFeature, aX, anY);
       std::string anAttribute = aFeature->data()->id(aPoint2D);
       std::list<std::string> aList;
-      if (myFeature2Attribute.find(aFeature) != myFeature2Attribute.end())
-        aList = myFeature2Attribute[aFeature];
+      if (theFeature2Attribute.find(aFeature) != theFeature2Attribute.end())
+        aList = theFeature2Attribute[aFeature];
 
       aList.push_back(anAttribute);
-      myFeature2Attribute[aFeature] = aList;
+      theFeature2Attribute[aFeature] = aList;
     }
   }
 }
@@ -136,7 +135,10 @@ void PartSet_OperationFeatureEdit::mousePressed(QMouseEvent* theEvent, ModuleBas
   if(aActiveWgt && aActiveWgt->isViewerSelector()) {
     // Almost do nothing, all stuff in on PartSet_OperationFeatureBase::mouseReleased
     PartSet_OperationFeatureBase::mousePressed(theEvent, theViewer, theSelection);
-    return;
+    // the current point should be cleared because it is saved from the previous move and 
+    // should be reinitialized after the start moving. It is important for example for the lenght
+    // constraint where the first widget is a viewer selector.
+    myCurPoint.clear();
   }
   else {
     // commit always until the selection restore is realized (for feature and local selection)
@@ -237,8 +239,8 @@ void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_
     //    std::list<std::string> anAttributes = aFeatIter->second;
     //    // perform edit for the feature
     //    if (anAttributes.empty()) {
-    //      boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
-    //                                     boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+    //      std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+    //                                     std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
     //      if (aSketchFeature) {
     //        aSketchFeature->move(aDeltaX, aDeltaY);
     //      }
@@ -248,7 +250,7 @@ void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_
     //      std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
     //                                             anAttrEnd = anAttributes.end();
     //      for (; anAttrIter != anAttrEnd; anAttrIter++) {
-    //        boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
+    //        std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = std::dynamic_pointer_cast<
     //                         GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
     //        if (aPointAttr) {
     //          aPointAttr->move(aDeltaX, aDeltaY);
@@ -260,23 +262,36 @@ void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_
     //}
     //else { // multieditoperation
 
-    //boost::shared_ptr<SketchPlugin_Feature> aSketchFeature = boost::dynamic_pointer_cast<
+    //std::shared_ptr<SketchPlugin_Feature> aSketchFeature = std::dynamic_pointer_cast<
     //    SketchPlugin_Feature>(feature());
 
     bool isMoved = false;
+    bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
+
     // the functionality to move the feature attribute if it exists in the internal map
-    std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
-    while (aFeatIter != myFeature2Attribute.end()) {
+    std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter, aFeatLast;
+    if (aHasShift || myHighlightedFeature2Attribute.empty()) {
+      aFeatIter = myAllFeature2Attribute.begin();
+      aFeatLast = myAllFeature2Attribute.end();
+    }
+    else {
+      aFeatIter = myHighlightedFeature2Attribute.begin();
+      aFeatLast = myHighlightedFeature2Attribute.end();
+    }
+
+    while (aFeatIter != aFeatLast) {
       FeaturePtr aFeature = aFeatIter->first;
       // MPV: added condition because it could be external edge of some object, not sketch
-      if (aFeature && !sketch()->isSub(aFeature))
+      if (aFeature && !sketch()->isSub(aFeature)) {
+        aFeatIter++;
         continue;
+      }
 
       std::list<std::string> anAttributes = aFeatIter->second;
       // perform edit for the feature
       if (anAttributes.empty()) {
-        boost::shared_ptr<SketchPlugin_Feature> aSketchFeature =
-                                       boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+        std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                                       std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
         if (aSketchFeature) {
           aSketchFeature->move(aDeltaX, aDeltaY);
           isMoved = true;
@@ -287,7 +302,7 @@ void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_
         std::list<std::string>::const_iterator anAttrIter = anAttributes.begin(),
                                                anAttrEnd = anAttributes.end();
         for (; anAttrIter != anAttrEnd; anAttrIter++) {
-          boost::shared_ptr<GeomDataAPI_Point2D> aPointAttr = boost::dynamic_pointer_cast<
+          std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = std::dynamic_pointer_cast<
                            GeomDataAPI_Point2D>(aFeature->data()->attribute(*anAttrIter));
           if (aPointAttr) {
             aPointAttr->move(aDeltaX, aDeltaY);
@@ -308,8 +323,8 @@ void PartSet_OperationFeatureEdit::mouseMoved(QMouseEvent* theEvent, ModuleBase_
     //  }
     // }
     //} // multieditoperation
+    sendFeatures(aHasShift);
   }
-  sendFeatures();
 
   myCurPoint.setPoint(aPoint);
 }
@@ -318,6 +333,11 @@ void PartSet_OperationFeatureEdit::mouseReleased(
     QMouseEvent* theEvent, ModuleBase_IViewer* theViewer,
     ModuleBase_ISelection* theSelection)
 {
+  // the block is processed in order to do not commit the transaction until the started
+  // double click functionality is performed. It is reproduced on Linux only
+  if (myIsBlockedByDoubleClick)
+    return;
+
   theViewer->enableSelection(true);
   // the next code is commented because it is obsolete by the multi edit operation realization here
   //if (myIsMultiOperation) {
@@ -356,6 +376,18 @@ void PartSet_OperationFeatureEdit::mouseReleased(
       commit();
       emitFeaturesDeactivation();
     }
+    else if (aSelected.size() == 1) {
+     /// TODO: OCC bug: 25034 - the highlighted list should be filled not only for AIS_Shape
+     /// but for other IO, for example constraint dimensions.
+     /// It is empty and we have to use the process mouse release to start edition operation
+     /// for these objects
+      ObjectPtr anObject = aSelected.first().object();
+      FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
+      if (aFeature && PartSet_Tools::isConstraintFeature(aFeature->getKind()) &&
+          aFeature != feature()) {
+        restartOperation(PartSet_OperationFeatureEdit::Type(), aFeature);
+      }
+    }
   }
 }
 
@@ -365,6 +397,28 @@ void PartSet_OperationFeatureEdit::mouseDoubleClick(
 {
   // TODO the functionality is important only for constraint feature. Should be moved in another place
   QList<ModuleBase_ViewerPrs> aSelected = theSelection->getSelected();
+  // in case when the double click happens on another constraint feature when selection control is active
+  // we should not perform the double click functionality
+  // if there is no the viewer selector widget active, the operation is restarted with a correct feature
+  ModuleBase_ModelWidget* aActiveWgt = myPropertyPanel->activeWidget();
+  if(aActiveWgt && aActiveWgt->isViewerSelector()) {
+    if (!aSelected.empty()) {
+      if (aSelected.size() == 1) {
+       /// TODO: OCC bug: 25034 - the highlighted list should be filled not only for AIS_Shape
+       /// but for other IO, for example constraint dimensions.
+       /// It is empty and we have to use the process mouse release to start edition operation
+       /// for these objects
+        ObjectPtr anObject = aSelected.first().object();
+        FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
+        if (aFeature && PartSet_Tools::isConstraintFeature(aFeature->getKind()) &&
+            aFeature != feature()) {
+          return;
+        }
+      }
+    }
+  }
+
+  myIsBlockedByDoubleClick = true;
   if (!aSelected.empty()) {
     ModuleBase_ViewerPrs aFeaturePrs = aSelected.first();
     if (!aFeaturePrs.owner().IsNull()) {
@@ -381,6 +435,7 @@ void PartSet_OperationFeatureEdit::mouseDoubleClick(
       }
     }
   }
+  myIsBlockedByDoubleClick  = false;
 }
 
 void PartSet_OperationFeatureEdit::startOperation()
@@ -397,7 +452,8 @@ void PartSet_OperationFeatureEdit::stopOperation()
 
   //blockSelection(false, false);
 
-  myFeature2Attribute.clear();
+  myHighlightedFeature2Attribute.clear();
+  myAllFeature2Attribute.clear();
 }
 
 //void PartSet_OperationFeatureEdit::blockSelection(bool isBlocked, const bool isRestoreSelection)
@@ -426,12 +482,20 @@ FeaturePtr PartSet_OperationFeatureEdit::createFeature(const bool theFlushMessag
   return FeaturePtr();
 }
 
-void PartSet_OperationFeatureEdit::sendFeatures()
+void PartSet_OperationFeatureEdit::sendFeatures(const bool theIsAllFeatures)
 {
   static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
 
-  std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
-  while (aFeatIter != myFeature2Attribute.end()) {
+  std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter, aFeatLast;
+  if (theIsAllFeatures || myHighlightedFeature2Attribute.empty()) {
+    aFeatIter = myAllFeature2Attribute.begin();
+    aFeatLast = myAllFeature2Attribute.end();
+  }
+  else {
+    aFeatIter = myHighlightedFeature2Attribute.begin();
+    aFeatLast = myHighlightedFeature2Attribute.end();
+  }
+  while (aFeatIter != aFeatLast) {
     FeaturePtr aFeature = aFeatIter->first;
     if (aFeature) {
       ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent);
@@ -445,8 +509,8 @@ void PartSet_OperationFeatureEdit::sendFeatures()
 
 void PartSet_OperationFeatureEdit::emitFeaturesDeactivation()
 {
-  std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myFeature2Attribute.begin();
-  while (aFeatIter != myFeature2Attribute.end()) {
+  std::map<FeaturePtr, std::list<std::string>>::iterator aFeatIter = myAllFeature2Attribute.begin();
+  while (aFeatIter != myAllFeature2Attribute.end()) {
     FeaturePtr aFeature = aFeatIter->first;
     if (aFeature) {
       emit featureConstructed(aFeature, FM_Deactivation);