Salome HOME
Issue #1664: In the Sketcher, add the function Split a segment: split of arc, move...
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
index 06fbec26cddd5bf4e0e5f2647c27293ae1e39cf2..a46d07f9d7413038f82e3b2086aca17e33aaa3e0 100755 (executable)
@@ -7,8 +7,7 @@
 #include "PartSet_SketcherMgr.h"
 #include "PartSet_SketcherReetntrantMgr.h"
 #include "PartSet_Module.h"
-#include "PartSet_WidgetPoint2d.h"
-#include "PartSet_WidgetPoint2dDistance.h"
+#include "PartSet_MouseProcessor.h"
 #include "PartSet_Tools.h"
 #include "PartSet_WidgetSketchLabel.h"
 #include "PartSet_WidgetEditor.h"
@@ -24,6 +23,7 @@
 #include <XGUI_PropertyPanel.h>
 #include <XGUI_ViewerProxy.h>
 #include <XGUI_OperationMgr.h>
+#include <XGUI_ErrorMgr.h>
 #include <XGUI_Tools.h>
 
 #include <ModuleBase_IPropertyPanel.h>
@@ -36,6 +36,9 @@
 #include <ModuleBase_OperationFeature.h>
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_WidgetEditor.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ResultPrs.h>
 
 #include <GeomDataAPI_Point2D.h>
 
 #include <ModelAPI_Session.h>
 #include <ModelAPI_AttributeString.h>
 
+#include <ModelAPI_Validator.h>
+#include <ModelAPI_Tools.h>
+
 #include <QMouseEvent>
 #include <QApplication>
 #include <QCursor>
 #include <QMessageBox>
+#include <QMainWindow>
 
 //#define DEBUG_DO_NOT_BY_ENTER
+//#define DEBUG_SKETCHER_ENTITIES
 
 //#define DEBUG_CURSOR
 
-/// Returns list of unique objects by sum of objects from List1 and List2
-/*QList<ModuleBase_ViewerPrs> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
-                                       const QList<ModuleBase_ViewerPrs>& theList2)
-{
-  QList<ModuleBase_ViewerPrs> aRes;
-  foreach (ModuleBase_ViewerPrs aPrs, theList1) {
-    if (!aRes.contains(aPrs))
-      aRes.append(aPrs);
-  }
-  foreach (ModuleBase_ViewerPrs aPrs, theList2) {
-    if (!aRes.contains(aPrs))
-      aRes.append(aPrs);
-  }
-  return aRes;
-}*/
-
-// Fills the list of features the list of selected presentations.
-// \param theList a list of selected presentations
-// \param theSketch a sketch to project a vertex shape of a presentation to the plane
-// and find the corresponded attribute
-// \param theFeatureList  an output list of features
-void fillFeatureList(const QList<ModuleBase_ViewerPrs>& theList,
-                     const FeaturePtr theSketch,
-                     QList<FeaturePtr>& theFeatureList)
-{
-  QList<ModuleBase_ViewerPrs> aRes;
-
-  QList<ModuleBase_ViewerPrs>::const_iterator anIt = theList.begin(),
-                                              aLast = theList.end();
-  for (; anIt != aLast; anIt++)
-  {
-    ModuleBase_ViewerPrs aPrs = *anIt;
-    FeaturePtr aFeature = ModelAPI_Feature::feature(aPrs.object());
-    if (aFeature.get()  && !theFeatureList.contains(aFeature))
-      theFeatureList.append(aFeature);
-  }
-}
-
 /// Fills attribute and result lists by the selected owner. In case if the attribute is found,
 /// by the owner shape, it is put to the list. Otherwise if type of owner shape is edge, put the function
 /// result as is to the list of results.
@@ -221,7 +191,7 @@ void PartSet_SketcherMgr::onEnterViewPort()
     }
   }
 
-  if (!isNestedCreateOperation(getCurrentOperation()))
+  if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
     return;
 
   operationMgr()->onValidateOperation();
@@ -246,9 +216,6 @@ void PartSet_SketcherMgr::onLeaveViewPort()
 {
   myIsMouseOverViewProcessed = false;
   myIsMouseOverWindow = false;
-  // it is important to validate operation here only if sketch entity create operation is active
-  // because at this operation we reacts to the mouse leave/enter view port
-  //operationMgr()->onValidateOperation();
 
   #ifdef DEBUG_DO_NOT_BY_ENTER
   return;
@@ -261,7 +228,7 @@ void PartSet_SketcherMgr::onLeaveViewPort()
 #endif
   }
 
-  if (!isNestedCreateOperation(getCurrentOperation()))
+  if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
     return;
 
   // the method should be performed if the popup menu is called,
@@ -269,6 +236,8 @@ void PartSet_SketcherMgr::onLeaveViewPort()
   if (myIsPopupMenuActive)
     return;
 
+  // it is important to validate operation here only if sketch entity create operation is active
+  // because at this operation we reacts to the mouse leave/enter view port
   operationMgr()->onValidateOperation();
 
   // 2. if the mouse IS NOT over window, reset the active widget value and hide the presentation
@@ -298,7 +267,7 @@ void PartSet_SketcherMgr::onLeaveViewPort()
 
 void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
 {
-  if (!isNestedEditOperation(getCurrentOperation()) ||
+  if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||
       myModule->sketchReentranceMgr()->isInternalEditActive())
     return;
   // it is necessary to save current selection in order to restore it after the values are modifed
@@ -312,7 +281,7 @@ void PartSet_SketcherMgr::onBeforeValuesChangedInPropertyPanel()
 
 void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
 {
-  if (!isNestedEditOperation(getCurrentOperation()) ||
+  if (!isNestedEditOperation(getCurrentOperation(), myModule->sketchMgr()->activeSketch()) ||
       myModule->sketchReentranceMgr()->isInternalEditActive()) {
     myModule->sketchReentranceMgr()->updateInternalEditActiveState();
     return;
@@ -370,7 +339,7 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       return;
 
     bool isSketcher = isSketchOperation(aFOperation);
-    bool isSketchOpe = isNestedSketchOperation(aFOperation);
+    bool isSketchOpe = isNestedSketchOperation(aFOperation, activeSketch());
 
     // Avoid non-sketch operations
     if ((!isSketchOpe) && (!isSketcher))
@@ -383,10 +352,6 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       return;
 
     Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-    if (!aContext.IsNull()) {
-      // MoveTo in order to highlight current object
-      aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
-    }
     // Remember highlighted objects for editing
     ModuleBase_ISelection* aSelect = aWorkshop->selection();
 
@@ -409,6 +374,9 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       myDragDone = false;
 
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
+      // selection should be restored before edit operation start to process the
+      // selected entities, e.g. selection of point(attribute on a line) should edit the point
+      restoreSelection();
       launchEditing();
       if (aFeature.get() != NULL) {
         std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
@@ -430,14 +398,11 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       myDragDone = false;
 
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
-
-      // this is temporary commented in order to avoid the following wrong case:
-      // Distance constraint is under edition, double click on the digit -> nothing happens
-      // because QApplication::processEvents() calls onMouseDoubleClick, which try to show editor
-      // but as the prev edit is commited an new one is not started, editor is not shown.
-      // This is necessary in order to finalize previous operation
-      //QApplication::processEvents();
+      // selection should be restored before edit operation start to process the
+      // selected entities, e.g. selection of point(attribute on a line) should edit the point
+      restoreSelection();
       launchEditing();
+      restoreSelection();
     }
   }
 }
@@ -453,23 +418,11 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
     return;
   ModuleBase_Operation* aOp = getCurrentOperation();
   if (aOp) {
-    if (isNestedSketchOperation(aOp)) {
-      //get2dPoint(theWnd, theEvent, myClickedPoint);
-
+    if (isNestedSketchOperation(aOp, activeSketch())) {
       // Only for sketcher operations
       if (myIsDragging) {
         if (myDragDone) {
-          //aOp->commit();
           myCurrentSelection.clear();
-          /*Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-          if (!aContext.IsNull()) {
-          // Reselect edited object
-          aContext->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
-          if (theEvent->modifiers() & Qt::ShiftModifier)
-            aContext->ShiftSelect();
-          else
-            aContext->Select();
-          */
         }
       }
     }
@@ -477,6 +430,11 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
 
   aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled);
   myIsDragging = false;
+
+  ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
+  PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
+  if (aProcessor)
+    aProcessor->mouseReleased(theWnd, theEvent);
 }
 
 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
@@ -484,31 +442,27 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve
   if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
     return;
 
-  if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
-    myIsMouseOverViewProcessed = true;
+  if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
     // 1. perform the widget mouse move functionality and display the presentation
     // the mouse move should be processed in the widget, if it can in order to visualize correct
     // presentation. These widgets correct the feature attribute according to the mouse position
-    ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
-    PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(anActiveWidget);
-    if (aPoint2DWdg) {
-      aPoint2DWdg->onMouseMove(theWnd, theEvent);
-    }
-    PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast<PartSet_WidgetPoint2dDistance*>
-                                                                (anActiveWidget);
-    if (aDistanceWdg) {
-      aDistanceWdg->onMouseMove(theWnd, theEvent);
-    }
-    // the feature is to be erased here, but it is correct to call canDisplayObject because
-    // there can be additional check (e.g. editor widget in distance constraint)
-    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                                             (getCurrentOperation());
-    if (aFOperation) {
-      FeaturePtr aFeature = aFOperation->feature();
-      visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
+    ModuleBase_ModelWidget* anActiveWidget = myModule->activeWidget();
+    PartSet_MouseProcessor* aProcessor = dynamic_cast<PartSet_MouseProcessor*>(anActiveWidget);
+    if (aProcessor)
+      aProcessor->mouseMoved(theWnd, theEvent);
+    if (!myIsMouseOverViewProcessed) {
+      myIsMouseOverViewProcessed = true;
+
+      // the feature is to be erased here, but it is correct to call canDisplayObject because
+      // there can be additional check (e.g. editor widget in distance constraint)
+      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                               (getCurrentOperation());
+      if (aFOperation) {
+        FeaturePtr aFeature = aFOperation->feature();
+        visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
+      }
     }
   }
-
   //myClickedPoint.clear();
 
   if (myIsDragging) {
@@ -613,7 +567,8 @@ void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMo
       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
       // Find corresponded widget to activate value editing
       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
-        if (aWgt->attributeID() == "ConstraintValue") {
+        if (aWgt->attributeID() == SketchPlugin_Constraint::VALUE() ||
+            aWgt->attributeID() == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) {
           PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
           if (anEditor)
             anEditor->showPopupEditor();
@@ -695,7 +650,7 @@ void PartSet_SketcherMgr::launchEditing()
     FeaturePtr aFeature = myCurrentSelection.begin().key();
     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-    if (aSPFeature) {
+    if (aSPFeature && (!aSPFeature->isExternal())) {
       myModule->editFeature(aSPFeature);
     }
   }
@@ -714,16 +669,17 @@ bool PartSet_SketcherMgr::sketchSolverError()
 
 QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
 {
-  QString anError = "";
+  std::string anError = "";
   if (!theFeature.get() || !theFeature->data()->isValid())
-    return anError;
+    return anError.c_str();
 
   CompositeFeaturePtr aSketch = activeSketch();
   if (aSketch.get() && aSketch == theFeature) {
     AttributeStringPtr aAttributeString = aSketch->string(SketchPlugin_Sketch::SOLVER_ERROR());
-    anError = aAttributeString->value().c_str();
+    anError = aAttributeString->value();
+    ModuleBase_Tools::translate(aSketch->getKind(), anError);
   }
-  return anError;
+  return anError.c_str();
 }
 
 void PartSet_SketcherMgr::clearClickedFlags()
@@ -732,47 +688,37 @@ void PartSet_SketcherMgr::clearClickedFlags()
   myCurrentPoint.clear();
 }
 
-const QStringList& PartSet_SketcherMgr::sketchOperationIdList()
+const QStringList& PartSet_SketcherMgr::replicationsIdList()
 {
-  static QStringList aIds;
-  if (aIds.size() == 0) {
-    aIds << SketchPlugin_Line::ID().c_str();
-    aIds << SketchPlugin_Point::ID().c_str();
-    aIds << SketchPlugin_Arc::ID().c_str();
-    aIds << SketchPlugin_Circle::ID().c_str();
-    aIds << SketchPlugin_ConstraintFillet::ID().c_str();
-    aIds << SketchPlugin_IntersectionPoint::ID().c_str();
-    // TODO
-    // SketchRectangle is a python feature, so its ID is passed just as a string
-    aIds << "SketchRectangle";
-    aIds.append(constraintsIdList());
+  static QStringList aReplicationIds;
+  if (aReplicationIds.size() == 0) {
+    aReplicationIds << SketchPlugin_ConstraintMirror::ID().c_str();
+    aReplicationIds << SketchPlugin_MultiRotation::ID().c_str();
+    aReplicationIds << SketchPlugin_MultiTranslation::ID().c_str();
   }
-  return aIds;
+  return aReplicationIds;
 }
 
 const QStringList& PartSet_SketcherMgr::constraintsIdList()
 {
-  static QStringList aIds;
-  if (aIds.size() == 0) {
-    aIds << SketchPlugin_ConstraintLength::ID().c_str();
-    aIds << SketchPlugin_ConstraintDistance::ID().c_str();
-    aIds << SketchPlugin_ConstraintRigid::ID().c_str();
-    aIds << SketchPlugin_ConstraintRadius::ID().c_str();
-    aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
-    aIds << SketchPlugin_ConstraintParallel::ID().c_str();
-    aIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
-    aIds << SketchPlugin_ConstraintVertical::ID().c_str();
-    aIds << SketchPlugin_ConstraintEqual::ID().c_str();
-    aIds << SketchPlugin_ConstraintTangent::ID().c_str();
-    aIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
-    aIds << SketchPlugin_ConstraintMirror::ID().c_str();
-    aIds << SketchPlugin_ConstraintAngle::ID().c_str();
-    aIds << SketchPlugin_MultiRotation::ID().c_str();
-    aIds << SketchPlugin_MultiTranslation::ID().c_str();
-    aIds << SketchPlugin_ConstraintCollinear::ID().c_str();
-    aIds << SketchPlugin_ConstraintMiddle::ID().c_str();
+  static QStringList aConstraintIds;
+  if (aConstraintIds.size() == 0) {
+    aConstraintIds << SketchPlugin_ConstraintLength::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintDistance::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintRigid::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintRadius::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintParallel::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintHorizontal::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintVertical::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintEqual::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintTangent::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintCoincidence::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintAngle::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintCollinear::ID().c_str();
+    aConstraintIds << SketchPlugin_ConstraintMiddle::ID().c_str();
   }
-  return aIds;
+  return aConstraintIds;
 }
 
 void PartSet_SketcherMgr::sketchSelectionModes(QIntList& theModes)
@@ -802,24 +748,38 @@ bool PartSet_SketcherMgr::isSketchOperation(ModuleBase_Operation* theOperation)
   return theOperation && theOperation->id().toStdString() == SketchPlugin_Sketch::ID();
 }
 
-bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation)
+bool PartSet_SketcherMgr::isNestedSketchOperation(ModuleBase_Operation* theOperation,
+                                                  const CompositeFeaturePtr& theSketch)
 {
-  return theOperation &&
-         PartSet_SketcherMgr::sketchOperationIdList().contains(theOperation->id());
+  bool aNestedSketch = false;
+
+  if (theOperation && theSketch.get()) {
+    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                 (theOperation);
+    if (aFOperation) {
+      FeaturePtr aFeature = aFOperation->feature();
+      aNestedSketch = theSketch->isSub(aFeature);
+    }
+  }
+  return aNestedSketch;
 }
 
-bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation)
+bool PartSet_SketcherMgr::isNestedCreateOperation(ModuleBase_Operation* theOperation,
+                                                  const CompositeFeaturePtr& theSketch)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                (theOperation);
-  return aFOperation && !aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
+  return aFOperation && !aFOperation->isEditOperation() &&
+         isNestedSketchOperation(aFOperation, theSketch);
 }
 
-bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation)
+bool PartSet_SketcherMgr::isNestedEditOperation(ModuleBase_Operation* theOperation,
+                                                const CompositeFeaturePtr& theSketch)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                (theOperation);
-  return aFOperation && aFOperation->isEditOperation() && isNestedSketchOperation(aFOperation);
+  return aFOperation && aFOperation->isEditOperation() &&
+    isNestedSketchOperation(aFOperation, theSketch);
 }
 
 bool PartSet_SketcherMgr::isEntity(const std::string& theId)
@@ -857,7 +817,6 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   // Display all sketcher sub-Objects
   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFOperation->feature());
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
-  aConnector->workshop()->displayer()->activateTrihedron(true);
 
   // Hide sketcher result
   std::list<ResultPtr> aResults = myCurrentSketch->results();
@@ -867,9 +826,50 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   }
   myCurrentSketch->setDisplayed(false);
 
+  // Remove invalid sketch entities
+  std::set<FeaturePtr> anInvalidFeatures;
+  ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+  for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
+    FeaturePtr aFeature = myCurrentSketch->subFeature(i);
+    if (aFeature.get()) {
+      if (!aFactory->validate(aFeature))
+        anInvalidFeatures.insert(aFeature);
+    }
+  }
+  if (!anInvalidFeatures.empty()) {
+    std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
+    ModelAPI_Tools::findAllReferences(anInvalidFeatures, aReferences, false);
+
+    std::set<FeaturePtr>::const_iterator anIt = anInvalidFeatures.begin(),
+                                         aLast = anInvalidFeatures.end();
+    // separate features to references to parameter features and references to others
+    QStringList anInvalidFeatureNames;
+    for (; anIt != aLast; anIt++) {
+      FeaturePtr aFeature = *anIt;
+      if (aFeature.get())
+        anInvalidFeatureNames.append(aFeature->name().c_str());
+    }
+    std::string aPrefixInfo = QString("Invalid features of the sketch will be deleted: %1.\n\n").
+                                  arg(anInvalidFeatureNames.join(", ")).toStdString().c_str();
+    std::set<FeaturePtr> aFeatureRefsToDelete;
+    if (ModuleBase_Tools::askToDelete(anInvalidFeatures, aReferences, aConnector->desktop(),
+                                      aFeatureRefsToDelete, aPrefixInfo)) {
+      if (!aFeatureRefsToDelete.empty())
+        anInvalidFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());
+      ModelAPI_Tools::removeFeatures(anInvalidFeatures, true);
+      Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+      // TODO: call the next method in the XGUI_OperationMgr::onOperationStarted().
+      workshop()->errorMgr()->updateAcceptAllAction(myCurrentSketch);
+    }
+  }
+
   // Display sketcher objects
+  QStringList anInfo;
   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
+#ifdef DEBUG_SKETCHER_ENTITIES
+    anInfo.append(ModuleBase_Tools::objectInfo(aFeature));
+#endif
     std::list<ResultPtr> aResults = aFeature->results();
     std::list<ResultPtr>::const_iterator aIt;
     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
@@ -877,6 +877,10 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
     }
     aFeature->setDisplayed(true);
   }
+#ifdef DEBUG_SKETCHER_ENTITIES
+  QString anInfoStr = anInfo.join(";\t");
+  qDebug(QString("startSketch: %1, %2").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
+#endif
 
   if(myCirclePointFilter.IsNull()) {
     myCirclePointFilter = new PartSet_CirclePointFilter(myModule->workshop());
@@ -890,18 +894,13 @@ void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
   bool aHasPlane = false;
   std::shared_ptr<GeomAPI_Pln> aPln;
-  if (aFOperation->isEditOperation()) {
-    // If it is editing of sketch then it means that plane is already defined
-    aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
-    if (aPln.get())
-      aHasPlane = true;
-  }
+  aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
   myPlaneFilter->setPlane(aPln);
 
   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
-  // all sketch objects should be activated in the sketch selection modes by edit operation start
-  // in case of creation operation, there is an active widget, which activates own selection mode
-  if (aFOperation->isEditOperation() && aHasPlane)
+  // all displayed objects should be activated in current selection modes according to switched
+  // plane filter
+  if (aPln.get())
     aConnector->activateModuleSelectionModes();
 }
 
@@ -924,7 +923,6 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
 
     // Erase all sketcher objects
-    QStringList aSketchIds = sketchOperationIdList();
     QObjectPtrList aObjects = aDisplayer->displayedObjects();
     foreach (ObjectPtr aObj, aObjects) {
       DataPtr aObjData = aObj->data();
@@ -971,7 +969,6 @@ void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
   }
   // restore the module selection modes, which were changed on startSketch
   aConnector->activateModuleSelectionModes();
-  aConnector->workshop()->displayer()->activateTrihedron(false);
 }
 
 void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
@@ -997,11 +994,16 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
     qDebug("stopNestedSketch() : None");
 #endif
   }
+  /// improvement to deselect automatically all eventual selected objects, when
+  // returning to the neutral point of the Sketcher
+  // if the operation is restarted, the previous selection is used to initialize started operation
+  if (!myModule->sketchReentranceMgr()->isInternalEditStarted())
+    workshop()->selector()->clearSelection();
 }
 
 void PartSet_SketcherMgr::commitNestedSketch(ModuleBase_Operation* theOperation)
 {
-  if (isNestedCreateOperation(theOperation)) {
+  if (isNestedCreateOperation(theOperation, activeSketch())) {
     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                              (theOperation);
     if (aFOperation) {
@@ -1027,7 +1029,7 @@ bool PartSet_SketcherMgr::operationActivatedByPreselection()
 {
   bool isOperationStopped = false;
   ModuleBase_Operation* anOperation = getCurrentOperation();
-  if(anOperation && PartSet_SketcherMgr::isNestedSketchOperation(anOperation)) {
+  if(anOperation && PartSet_SketcherMgr::isNestedSketchOperation(anOperation, activeSketch())) {
     // Set final definitions if they are necessary
     //propertyPanelDefined(aOperation);
     /// Commit sketcher operations automatically
@@ -1036,8 +1038,12 @@ bool PartSet_SketcherMgr::operationActivatedByPreselection()
     bool aCanCommitOperation = true;
     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                             (anOperation);
-    if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation))
-      aCanCommitOperation = setDistanceValueByPreselection(anOperation, myModule->workshop());
+    if (aFOperation && PartSet_SketcherMgr::isDistanceOperation(aFOperation)) {
+      bool aValueAccepted = setDistanceValueByPreselection(anOperation, myModule->workshop(),
+                                                           aCanCommitOperation);
+      if (!aValueAccepted)
+        return isOperationStopped;
+    }
 
     if (aCanCommitOperation)
       isOperationStopped = anOperation->commit();
@@ -1051,12 +1057,12 @@ bool PartSet_SketcherMgr::operationActivatedByPreselection()
 
 bool PartSet_SketcherMgr::canUndo() const
 {
-  return isNestedCreateOperation(getCurrentOperation());
+  return isNestedCreateOperation(getCurrentOperation(), activeSketch());
 }
 
 bool PartSet_SketcherMgr::canRedo() const
 {
-  return isNestedCreateOperation(getCurrentOperation());
+  return isNestedCreateOperation(getCurrentOperation(), activeSketch());
 }
 
 bool PartSet_SketcherMgr::canEraseObject(const ObjectPtr& theObject) const
@@ -1094,6 +1100,11 @@ bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
     if (aFeature.get() != NULL && aFeature == activeSketch()) {
       aCanDisplay = false;
     }
+    std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+                            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+    /// some sketch entities should be never shown, e.g. projection feature
+    if (aSketchFeature.get())
+      aCanDisplay = aSketchFeature->canBeDisplayed();
   }
   else { // there are no an active sketch
     // 2. sketch sub-features should not be visualized if the sketch operation is not active
@@ -1109,43 +1120,45 @@ bool PartSet_SketcherMgr::canDisplayObject(const ObjectPtr& theObject) const
 
   // 3. the method should not filter the objects, which are not related to the current operation.
   // The object is filtered just if it is a current operation feature or this feature result
-  bool isObjectFound = false;
-  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                               (getCurrentOperation());
-  if (aFOperation) {
-    FeaturePtr aFeature = aFOperation->feature();
-    if (aFeature.get()) {
-      std::list<ResultPtr> aResults = aFeature->results();
-      if (theObject == aFeature)
-        isObjectFound = true;
-      else {
-        std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
-        for (; anIt != aLast && !isObjectFound; anIt++) {
-          isObjectFound = *anIt == theObject;
+  if (aCanDisplay) {
+    bool isObjectFound = false;
+    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                                 (getCurrentOperation());
+    if (aFOperation) {
+      FeaturePtr aFeature = aFOperation->feature();
+      if (aFeature.get()) {
+        std::list<ResultPtr> aResults = aFeature->results();
+        if (theObject == aFeature)
+          isObjectFound = true;
+        else {
+          std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLast = aResults.end();
+          for (; anIt != aLast && !isObjectFound; anIt++) {
+            isObjectFound = *anIt == theObject;
+          }
         }
       }
     }
-  }
-  if (isObjectFound) {
-    // 4. For created nested feature operation do not display the created feature if
-    // the mouse curstor leaves the OCC window.
-    // The correction cases, which ignores this condition:
-    // a. the property panel values modification
-    // b. the popup menu activated
-    // c. widget editor control
-    #ifndef DEBUG_DO_NOT_BY_ENTER
-    if (aCanDisplay && isNestedCreateOperation(getCurrentOperation())) {
-      ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
-      ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
-      // the active widget editor should not influence here. The presentation should be visible always
-      // when this widget is active.
-      if (!anEditorWdg && !myIsPopupMenuActive) {
-        // during a nested create operation, the feature is redisplayed only if the mouse over view
-        // of there was a value modified in the property panel after the mouse left the view
-        aCanDisplay = canDisplayCurrentCreatedFeature();
+    if (isObjectFound) {
+      // 4. For created nested feature operation do not display the created feature if
+      // the mouse curstor leaves the OCC window.
+      // The correction cases, which ignores this condition:
+      // a. the property panel values modification
+      // b. the popup menu activated
+      // c. widget editor control
+      #ifndef DEBUG_DO_NOT_BY_ENTER
+      if (isNestedCreateOperation(getCurrentOperation(), activeSketch())) {
+        ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
+        ModuleBase_WidgetEditor* anEditorWdg = anActiveWidget ? dynamic_cast<ModuleBase_WidgetEditor*>(anActiveWidget) : 0;
+        // the active widget editor should not influence here. The presentation should be visible always
+        // when this widget is active.
+        if (!anEditorWdg && !myIsPopupMenuActive) {
+          // during a nested create operation, the feature is redisplayed only if the mouse over view
+          // of there was a value modified in the property panel after the mouse left the view
+          aCanDisplay = canDisplayCurrentCreatedFeature();
+        }
       }
+      #endif
     }
-    #endif
   }
 
   // checks the sketcher constraints visibility according to active sketch check box states
@@ -1207,7 +1220,7 @@ bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature,
   return aSwitchedOn;
 }
 
-void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
+/*void PartSet_SketcherMgr::processHiddenObject(const std::list<ObjectPtr>& theObjects)
 {
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                            (getCurrentOperation());
@@ -1283,7 +1296,7 @@ will be hidden: %1. Would you like to delete them?")
       }
     }
   }
-}
+}*/
 
 bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
 {
@@ -1298,7 +1311,7 @@ bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const
 
 bool PartSet_SketcherMgr::canChangeCursor(ModuleBase_Operation* theOperation) const
 {
-  return isNestedCreateOperation(theOperation) ||
+  return isNestedCreateOperation(theOperation, activeSketch()) ||
          myModule->sketchReentranceMgr()->isInternalEditActive();
 }
 
@@ -1331,9 +1344,11 @@ void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& th
 }
 
 bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* theOperation,
-                                                         ModuleBase_IWorkshop* theWorkshop)
+                                                         ModuleBase_IWorkshop* theWorkshop,
+                                                         bool& theCanCommitOperation)
 {
   bool isValueAccepted = false;
+  theCanCommitOperation = false;
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                               (theOperation);
@@ -1395,6 +1410,7 @@ bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* t
             }
             anEditor->setCursorPosition(aX, anY);
             isValueAccepted = anEditor->showPopupEditor(false);
+            theCanCommitOperation = true;
           }
         }
       }
@@ -1403,54 +1419,6 @@ bool PartSet_SketcherMgr::setDistanceValueByPreselection(ModuleBase_Operation* t
   return isValueAccepted;
 }
 
-void PartSet_SketcherMgr::getCurrentSelection(const FeaturePtr& theFeature,
-                                              const FeaturePtr& theSketch,
-                                              ModuleBase_IWorkshop* theWorkshop,
-                                              FeatureToSelectionMap& theSelection)
-{
-  if (theFeature.get() == NULL)
-    return;
-
-  std::set<AttributePtr> aSelectedAttributes;
-  std::set<ResultPtr> aSelectedResults;
-
-  ModuleBase_IViewer* aViewer = theWorkshop->viewer();
-  Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
-  if (!aContext.IsNull()) {
-    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
-    XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
-
-    std::list<ResultPtr> aResults = theFeature->results();
-    std::list<ResultPtr>::const_iterator aIt;
-    for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt)
-    {
-      ResultPtr aResult = *aIt;
-      AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
-      if (aAISObj.get() == NULL)
-        continue;
-      Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
-      for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
-      {
-        Handle(SelectMgr_EntityOwner) anOwner = aContext->SelectedOwner();
-        if (anOwner->Selectable() != anAISIO)
-          continue;
-        getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
-                               aSelectedAttributes, aSelectedResults);
-      }
-      for (aContext->InitDetected(); aContext->MoreDetected(); aContext->NextDetected()) {
-        Handle(SelectMgr_EntityOwner) anOwner = aContext->DetectedOwner();
-        if (anOwner.IsNull())
-          continue;
-        if (anOwner->Selectable() != anAISIO)
-          continue;
-        getAttributesOrResults(anOwner, theFeature, theSketch, aResult,
-                               aSelectedAttributes, aSelectedResults);
-      }
-    }
-  }
-  theSelection[theFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
-}
-
 void PartSet_SketcherMgr::getSelectionOwners(const FeaturePtr& theFeature,
                                              const FeaturePtr& theSketch,
                                              ModuleBase_IWorkshop* theWorkshop,
@@ -1541,7 +1509,7 @@ void PartSet_SketcherMgr::widgetStateChanged(int thePreviousState)
                                                                            (getCurrentOperation());
   if (aFOperation) {
     if (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
-        PartSet_SketcherMgr::isNestedSketchOperation(aFOperation) &&
+        PartSet_SketcherMgr::isNestedSketchOperation(aFOperation, activeSketch()) &&
         thePreviousState == ModuleBase_ModelWidget::ModifiedInPP) {
       FeaturePtr aFeature = aFOperation->feature();
       visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
@@ -1554,8 +1522,20 @@ void PartSet_SketcherMgr::customizePresentation(const ObjectPtr& theObject)
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                                            (getCurrentOperation());
   if (aFOperation && (PartSet_SketcherMgr::isSketchOperation(aFOperation) ||
-                      PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)))
+                      PartSet_SketcherMgr::isNestedSketchOperation(aFOperation, activeSketch())))
     SketcherPrs_Tools::sendExpressionShownEvent(myIsConstraintsShown[PartSet_Tools::Expressions]);
+
+  // update entities selection priorities
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+  if (aFeature.get() && PartSet_SketcherMgr::isEntity(aFeature->getKind())) {
+    // update priority for feature
+    updateSelectionPriority(aFeature, aFeature);
+    // update priority for results of the feature
+    std::list<ResultPtr> aResults = aFeature->results();
+    std::list<ResultPtr>::const_iterator anIt = aResults.begin(), aLastIt = aResults.end();
+    for (; anIt != aLastIt; anIt++)
+      updateSelectionPriority(*anIt, aFeature);
+  }
 }
 
 ModuleBase_Operation* PartSet_SketcherMgr::getCurrentOperation() const
@@ -1621,24 +1601,58 @@ void PartSet_SketcherMgr::storeSelection(const bool theHighlightedOnly)
 
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
   ModuleBase_ISelection* aSelect = aWorkshop->selection();
-  QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
+  QList<ModuleBase_ViewerPrsPtr> aStoredPrs = aSelect->getHighlighted();
 
   QList<FeaturePtr> aFeatureList;
-  if (theHighlightedOnly) {
-    fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
-  }
-  else {
-    fillFeatureList(aHighlighted, myCurrentSketch, aFeatureList);
-
-    QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected(ModuleBase_ISelection::AllControls);
-    fillFeatureList(aSelected, myCurrentSketch, aFeatureList);
+  if (!theHighlightedOnly) {
+    QList<ModuleBase_ViewerPrsPtr> aSelected = aSelect->getSelected(
+                                                              ModuleBase_ISelection::AllControls);
+    aStoredPrs.append(aSelected);
   }
 
   // 1. it is necessary to save current selection in order to restore it after the features moving
   myCurrentSelection.clear();
-  QList<FeaturePtr>::const_iterator anIt = aFeatureList.begin(), aLast = aFeatureList.end();
+
+  QList<ModuleBase_ViewerPrsPtr>::const_iterator anIt = aStoredPrs.begin(), aLast = aStoredPrs.end();
+
+  CompositeFeaturePtr aSketch = activeSketch();
   for (; anIt != aLast; anIt++) {
-    getCurrentSelection(*anIt, myCurrentSketch, aWorkshop, myCurrentSelection);
+    ModuleBase_ViewerPrsPtr aPrs = *anIt;
+    ObjectPtr anObject = aPrs->object();
+    if (!anObject.get())
+      continue;
+
+    ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
+    FeaturePtr aFeature;
+    if (aResult.get())
+      aFeature = ModelAPI_Feature::feature(aResult);
+    else
+      aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+
+
+    std::set<AttributePtr> aSelectedAttributes;
+    std::set<ResultPtr> aSelectedResults;
+    if (myCurrentSelection.find(aFeature) != myCurrentSelection.end()) {
+      std::pair<std::set<AttributePtr>, std::set<ResultPtr> > aPair = myCurrentSelection.find(aFeature).value();
+      aSelectedAttributes = aPair.first;
+      aSelectedResults = aPair.second;
+    }
+
+    Handle(SelectMgr_EntityOwner) anOwner = aPrs->owner();
+    if (aResult.get()) {
+      getAttributesOrResults(anOwner, aFeature, aSketch, aResult,
+                             aSelectedAttributes, aSelectedResults);
+    }
+    else {
+      std::list<ResultPtr> aResults = aFeature->results();
+      std::list<ResultPtr>::const_iterator aIt;
+      for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
+        ResultPtr aResult = *aIt;
+        getAttributesOrResults(anOwner, aFeature, aSketch, aResult,
+                               aSelectedAttributes, aSelectedResults);
+      }
+    }
+    myCurrentSelection[aFeature] = std::make_pair(aSelectedAttributes, aSelectedResults);
   }
   //qDebug(QString("  storeSelection: %1").arg(myCurrentSelection.size()).toStdString().c_str());
 }
@@ -1697,15 +1711,64 @@ void PartSet_SketcherMgr::updateBySketchParameters(
     }
     break;
     case PartSet_Tools::Expressions: {
-      /// call all sketch features redisplay, the expression state will be corrected in customize
-      /// of distance presentation
-      Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-      PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
+      if (aPrevState != theState) {
+        /// call all sketch features redisplay, the expression state will be corrected in customize
+        /// of distance presentation
+        Events_ID anEventId = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+        PartSet_Tools::sendSubFeaturesEvent(myCurrentSketch, anEventId);
+      }
     }
     break;
   }
 }
 
+void PartSet_SketcherMgr::updateSelectionPriority(ObjectPtr theObject,
+                                                  FeaturePtr theFeature)
+{
+  if (!theObject.get() || !theFeature.get())
+    return;
+
+  AISObjectPtr anAIS = workshop()->displayer()->getAISObject(theObject);
+  Handle(AIS_InteractiveObject) anAISIO;
+  if (anAIS.get() != NULL) {
+    anAISIO = anAIS->impl<Handle(AIS_InteractiveObject)>();
+  }
+
+  if (!anAISIO.IsNull()) { // the presentation for the object is visualized
+    int anAdditionalPriority = 0;
+    // current feature
+    std::shared_ptr<SketchPlugin_Feature> aSPFeature =
+            std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
+    if (aSPFeature.get() != NULL) {
+      // 1. Vertices
+      // 2. Simple segments
+      // 3. External objects (violet color)
+      // 4. Auxiliary segments (dotted)
+      // StdSelect_BRepSelectionTool::Load uses priority calculating:
+      // Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
+      // Priority of Vertex is 8, edge(segment) is 7.
+      // It might be not corrected as provides the condition above.
+      bool isExternal = aSPFeature->isExternal();
+      bool isAuxiliary = PartSet_Tools::isAuxiliarySketchEntity(aSPFeature);
+      // current feature
+      if (!isExternal && !isAuxiliary)
+        anAdditionalPriority = 30;
+      // external feature
+      if (isExternal)
+        anAdditionalPriority = 20;
+      // auxiliary feature
+      if (isAuxiliary) {
+        anAdditionalPriority = 10; /// auxiliary objects should have less priority that
+        // edges/vertices of local selection on not-sketch objects
+      }
+      Handle(ModuleBase_ResultPrs) aResult = Handle(ModuleBase_ResultPrs)::DownCast(anAISIO);
+      if (!aResult.IsNull()) {
+        aResult->setAdditionalSelectionPriority(anAdditionalPriority);
+      }
+    }
+  }
+}
+
 XGUI_Workshop* PartSet_SketcherMgr::workshop() const
 {
   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();