Salome HOME
"2.11 Constraint with a point from the intersection between an outer edge and plane...
[modules/shaper.git] / src / PartSet / PartSet_SketcherReetntrantMgr.cpp
index af2723111d3e85872fccf2dbe9691df9deeb02ef..15cf843d3072df5989d5dd1d08db2db2f0d81a1e 100755 (executable)
@@ -3,7 +3,7 @@
 #include "PartSet_SketcherReetntrantMgr.h"
 #include "PartSet_Module.h"
 #include "PartSet_SketcherMgr.h"
-#include "PartSet_WidgetPoint2D.h"
+#include "PartSet_WidgetPoint2d.h"
 
 #include "ModelAPI_Session.h"
 
 #include <ModuleBase_ModelWidget.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_WidgetSelector.h>
+#include <ModuleBase_PageWidget.h>
+#include <ModuleBase_PageBase.h>
+#include <ModuleBase_WidgetFactory.h>
+#include <ModuleBase_OperationDescription.h>
 
 #include <SketchPlugin_Feature.h>
 #include <SketchPlugin_Line.h>
 #include <XGUI_Workshop.h>
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_OperationMgr.h>
+#include <XGUI_PropertyPanel.h>
+
+#include <QToolButton>
 
 PartSet_SketcherReetntrantMgr::PartSet_SketcherReetntrantMgr(ModuleBase_IWorkshop* theWorkshop)
 : QObject(theWorkshop),
   myWorkshop(theWorkshop),
   myRestartingMode(RM_None),
   myIsFlagsBlocked(false),
-  myIsInternalEditOperation(false)
+  myIsInternalEditOperation(false),
+  myNoMoreWidgetsAttribute("")
 {
 }
 
@@ -43,24 +51,17 @@ ModuleBase_ModelWidget* PartSet_SketcherReetntrantMgr::internalActiveWidget() co
   if (aOperation) {
     ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
-    if (myIsInternalEditOperation && (!anActiveWidget || !anActiveWidget->isViewerSelector())) {
-      // finds the first widget which can accept a value
-      QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
-      ModuleBase_ModelWidget* aFirstWidget = 0;
-      ModuleBase_ModelWidget* aWgt;
-      QList<ModuleBase_ModelWidget*>::const_iterator aWIt;
-      for (aWIt = aWidgets.begin(); aWIt != aWidgets.end() && !aFirstWidget; ++aWIt) {
-        aWgt = (*aWIt);
-        if (aWgt->canSetValue())
-          aFirstWidget = aWgt;
-      }
-      if (aFirstWidget)
-        aWidget = aFirstWidget;
-    }
+    if (myIsInternalEditOperation && (!anActiveWidget || !anActiveWidget->isViewerSelector()))
+      aWidget = myInternalActiveWidget;
   }
   return aWidget;
 }
 
+bool PartSet_SketcherReetntrantMgr::isInternalEditActive() const
+{
+  return myIsInternalEditOperation;
+}
+
 bool PartSet_SketcherReetntrantMgr::operationCommitted(ModuleBase_Operation* theOperation)
 {
   bool aProcessed = false;
@@ -135,15 +136,19 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow*
 
   if (myIsInternalEditOperation) {
     ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
+    ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
 
-    ModuleBase_ModelWidget* anActiveWidget = anOperation->propertyPanel()->activeWidget();
+    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
     if (!anActiveWidget || !anActiveWidget->isViewerSelector()) {
       restartOperation();
       aProcessed = true;
 
-      // fill the widget by the mouse event point
+      // fill the first widget by the mouse event point
+      // if the active widget is not the first, it means that the restarted operation is filled by
+      // the current preselection.
       PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
-      if (aPoint2DWdg) {
+      ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
+      if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
         aPoint2DWdg->onMouseRelease(theWnd, theEvent);
       }
     }
@@ -173,25 +178,61 @@ void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePrevio
 {
   if (!isActiveMgr())
     return;
-  XGUI_OperationMgr* anOpMgr = workshop()->operationMgr();
-  if (!anOpMgr->isApplyEnabled())
+
+  // we should avoid processing of the signal about no more widgets attributes and 
+  // do this after the restart operaion is finished if it was called
+  // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
+  // if it should be called after restart
+  if (myIsFlagsBlocked) {
+    myNoMoreWidgetsAttribute = thePreviousAttributeID;
     return;
+  }
 
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                        (myWorkshop->currentOperation());
-  if (aFOperation) {
-    if (PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
-      XGUI_OperationMgr* anOpMgr = workshop()->operationMgr();
+  if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
+    return;
+
+  if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
+    bool isStarted = false;
+    if (!module()->sketchMgr()->sketchSolverError()) {
       if (myRestartingMode != RM_Forbided) {
         myRestartingMode = RM_LastFeatureUsed;
-        startInternalEdit(thePreviousAttributeID);
+        isStarted = startInternalEdit(thePreviousAttributeID);
       }
-      else
-        aFOperation->commit();
     }
+    if (!isStarted)
+      aFOperation->commit();
   }
 }
 
+bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
+{
+  bool isDone = false;
+
+  if (!isActiveMgr())
+    return isDone;
+
+  // empty previous attribute means that the Apply/Ok button has focus and the enter
+  // should not lead to start edition mode of the previous operation
+  if (thePreviousAttributeID.empty())
+    return isDone;
+
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                       (myWorkshop->currentOperation());
+  if (!myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty())
+    return isDone;
+
+  bool isSketchSolverError = module()->sketchMgr()->sketchSolverError();
+
+  if (!isSketchSolverError) {
+    myRestartingMode = RM_EmptyFeatureUsed;
+    isDone = startInternalEdit(thePreviousAttributeID);
+  }
+
+  return isDone;
+}
+
 void PartSet_SketcherReetntrantMgr::onVertexSelected()
 {
   if (!isActiveMgr())
@@ -217,15 +258,12 @@ void PartSet_SketcherReetntrantMgr::onVertexSelected()
   }
 }
 
-void PartSet_SketcherReetntrantMgr::onEnterReleased()
+void PartSet_SketcherReetntrantMgr::onBeforeStopped()
 {
-  if (!isActiveMgr())
+  if (!isActiveMgr() || !myIsInternalEditOperation)
     return;
 
-  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
-                                                      (myWorkshop->currentOperation());
-  if (myIsInternalEditOperation)
-    myRestartingMode = RM_EmptyFeatureUsed;
+  beforeStopInternalEdit();
 }
 
 bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
@@ -235,22 +273,44 @@ bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
 
 bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
 {
-  PartSet_SketcherMgr* aSketcherMgr = module()->sketchMgr();
   ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
-  return PartSet_SketcherMgr::isSketchOperation(aCurrentOperation) ||
-         PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation);
+
+  bool anActive = PartSet_SketcherMgr::isSketchOperation(aCurrentOperation);
+  if (!anActive) {
+    anActive = PartSet_SketcherMgr::isNestedSketchOperation(aCurrentOperation);
+    if (anActive) { // the manager is not active when the current operation is a usual Edit
+      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                       (myWorkshop->currentOperation());
+      if (aFOperation->isEditOperation())
+        anActive = myIsInternalEditOperation;
+    }
+  }
+  return anActive;
 }
 
-void PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
+bool PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
 {
+  bool isDone = false;
+  /// this is workaround for ModuleBase_WidgetEditor, used in SALOME mode. Sometimes key enter
+  /// event comes two times, so we should not start another internal edit operation
+  /// the Apply button becomes disabled becase the second additional internal feature is created
+  if (myIsInternalEditOperation)
+    return true;
+
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
                                                      (myWorkshop->currentOperation());
 
-  aFOperation->setEditOperation();
-  FeaturePtr anOperationFeature = aFOperation->feature();
-  if (anOperationFeature.get() != NULL) {
+  if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
+    aFOperation->setEditOperation(false);
+    workshop()->operationMgr()->updateApplyOfOperations();
+
+    createInternalFeature();
 
     myIsInternalEditOperation = true;
+    isDone = true;
+    connect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
+    connect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
+
     // activate selection filters of the first widget in the viewer
     onWidgetActivated();
 
@@ -266,11 +326,45 @@ void PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePrev
             aPreviousAttributeWidget = aWidgets[i];
         }
         // If the current widget is a selector, do nothing, it processes the mouse press
-        if (aPreviousAttributeWidget && !aPreviousAttributeWidget->isViewerSelector())
-          aPreviousAttributeWidget->focusTo();
+        if (aPreviousAttributeWidget) {
+          if (!aPreviousAttributeWidget->isViewerSelector()) {
+            aPreviousAttributeWidget->focusTo();
+            aPreviousAttributeWidget->selectContent();
+          }
+          else {
+            // in case of shape multi selector, the widget does not lose focus by filling
+            // like it is in shape selector. So, if enter is pressed, the multi shape selector
+            // control should be deactivated. The focus is moved to Apply button and there
+            // should not be active control visualized in property panel
+            if (aPreviousAttributeWidget == aPanel->activeWidget()) {
+              aPanel->activateWidget(NULL, false);
+            }
+            // if there is no the next widget to be automatically activated, the Ok button in property
+            // panel should accept the focus(example is parallel constraint on sketch lines)
+            QToolButton* anOkBtn = aPanel->findChild<QToolButton*>(PROP_PANEL_OK);
+            if (anOkBtn)
+              anOkBtn->setFocus(Qt::TabFocusReason);
+          }
+        }
       }
     }
   }
+  if (isDone)
+    module()->sketchMgr()->clearClickedFlags();
+
+  return isDone;
+}
+
+void PartSet_SketcherReetntrantMgr::beforeStopInternalEdit()
+{
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                      (myWorkshop->currentOperation());
+  if (aFOperation) {
+    disconnect(aFOperation, SIGNAL(beforeCommitted()), this, SLOT(onBeforeStopped()));
+    disconnect(aFOperation, SIGNAL(beforeAborted()), this, SLOT(onBeforeStopped()));
+  }
+
+  deleteInternalFeature();
 }
 
 void PartSet_SketcherReetntrantMgr::restartOperation()
@@ -279,15 +373,77 @@ void PartSet_SketcherReetntrantMgr::restartOperation()
     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
                                                                   myWorkshop->currentOperation());
     if (aFOperation) {
+      myNoMoreWidgetsAttribute = "";
       myIsFlagsBlocked = true;
       aFOperation->commit();
       module()->launchOperation(aFOperation->id());
       myIsFlagsBlocked = false;
       resetFlags();
+      // we should avoid processing of the signal about no more widgets attributes and 
+      // do this after the restart operaion is finished if it was called
+      // onNoMoreWidgets depends on myIsFlagsBlocked and fill myNoMoreWidgetsAttribute
+      // if it should be called after restart
+      if (!myNoMoreWidgetsAttribute.empty()) {
+        onNoMoreWidgets(myNoMoreWidgetsAttribute);
+        myNoMoreWidgetsAttribute = "";
+      }
     }
   }
 }
 
+void PartSet_SketcherReetntrantMgr::createInternalFeature()
+{
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                     (myWorkshop->currentOperation());
+
+  if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
+    FeaturePtr anOperationFeature = aFOperation->feature();
+
+    CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
+    myInternalFeature = aSketch->addFeature(anOperationFeature->getKind());
+    XGUI_PropertyPanel* aPropertyPanel = dynamic_cast<XGUI_PropertyPanel*>
+                                                  (aFOperation->propertyPanel());
+
+    myInternalWidget = new QWidget(aPropertyPanel->contentWidget()->pageWidget());
+    myInternalWidget->setVisible(false);
+
+    ModuleBase_PageWidget* anInternalPage = new ModuleBase_PageWidget(myInternalWidget);
+
+    QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
+    ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myWorkshop);
+
+    aFactory.createWidget(anInternalPage);
+    QList<ModuleBase_ModelWidget*> aWidgets = aFactory.getModelWidgets();
+
+    foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
+      bool isStoreValue = !aFOperation->isEditOperation() &&
+                          !aWidget->getDefaultValue().empty() &&
+                          !aWidget->isComputedDefault();
+      aWidget->setFeature(myInternalFeature, isStoreValue);
+    }
+    ModuleBase_ModelWidget* aFirstWidget = ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget
+                                                                                        (aWidgets);
+    if (aFirstWidget)
+      myInternalActiveWidget = aFirstWidget;
+  }
+}
+
+void PartSet_SketcherReetntrantMgr::deleteInternalFeature()
+{
+  if (myInternalActiveWidget) {
+    ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(myInternalActiveWidget);
+    if (aWSelector)
+      aWSelector->activateSelectionAndFilters(false);
+    myInternalActiveWidget = 0;
+  }
+  delete myInternalWidget;
+  myInternalWidget = 0;
+
+  QObjectPtrList anObjects;
+  anObjects.append(myInternalFeature);
+  workshop()->deleteFeatures(anObjects);
+}
+
 void PartSet_SketcherReetntrantMgr::resetFlags()
 {
   if (!myIsFlagsBlocked) {
@@ -306,3 +462,4 @@ PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
 {
   return dynamic_cast<PartSet_Module*>(myWorkshop->module());
 }
+