Salome HOME
Merge remote-tracking branch 'origin/BR_REENTRANCE_OPERATION' into origin_Dev_1.5.0
authornds <nds@opencascade.com>
Mon, 9 Nov 2015 11:34:57 +0000 (14:34 +0300)
committernds <nds@opencascade.com>
Mon, 9 Nov 2015 11:34:57 +0000 (14:34 +0300)
Conflicts:
src/Model/Model_Document.cpp

31 files changed:
src/Model/Model_Document.cpp [changed mode: 0644->0755]
src/ModuleBase/ModuleBase_FilterValidated.cpp
src/ModuleBase/ModuleBase_IModule.cpp
src/ModuleBase/ModuleBase_IModule.h
src/ModuleBase/ModuleBase_IPropertyPanel.cpp
src/ModuleBase/ModuleBase_IPropertyPanel.h
src/ModuleBase/ModuleBase_ModelWidget.h
src/ModuleBase/ModuleBase_OperationFeature.cpp
src/ModuleBase/ModuleBase_OperationFeature.h
src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp
src/ModuleBase/ModuleBase_WidgetDoubleValue.h
src/ModuleBase/ModuleBase_WidgetEditor.h
src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
src/ModuleBase/ModuleBase_WidgetSelector.cpp
src/ModuleBase/ModuleBase_WidgetSelector.h
src/ModuleBase/ModuleBase_WidgetValidated.h
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_SketcherReetntrantMgr.cpp [new file with mode: 0755]
src/PartSet/PartSet_SketcherReetntrantMgr.h [new file with mode: 0755]
src/PartSet/PartSet_Validators.cpp
src/PartSet/PartSet_WidgetEditor.cpp
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetPoint2d.h
src/SketchPlugin/SketchPlugin_Sketch.cpp
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_PropertyPanel.cpp
src/XGUI/XGUI_Workshop.cpp

old mode 100644 (file)
new mode 100755 (executable)
index ecd12cf..e3ff4e0
 #include <TDataStd_Comment.hxx>
 #include <TDF_ChildIDIterator.hxx>
 #include <TDataStd_ReferenceArray.hxx>
+#include <TDataStd_ReferenceList.hxx>
 #include <TDataStd_IntegerArray.hxx>
 #include <TDataStd_HLabelArray1.hxx>
 #include <TDataStd_Name.hxx>
+#include <TDataStd_AsciiString.hxx>
 #include <TDF_Reference.hxx>
 #include <TDF_ChildIDIterator.hxx>
 #include <TDF_LabelMapHasher.hxx>
@@ -360,7 +362,7 @@ static bool isEqualContent(Handle(TDF_Attribute) theAttr1, Handle(TDF_Attribute)
       return false;
     if (anArr1->Lower() == anArr2->Lower() && anArr1->Upper() == anArr2->Upper()) {
       for(int a = anArr1->Lower(); a <= anArr1->Upper(); a++)
-        if (anArr1->Value(a) != anArr2->Value(a))
+        if (a != 1 && anArr1->Value(a) != anArr2->Value(a)) // second is for display
           return false;
       return true;
     }
@@ -382,6 +384,42 @@ static bool isEqualContent(Handle(TDF_Attribute) theAttr1, Handle(TDF_Attribute)
         }
       return true;
     }
+  } else if (Standard_GUID::IsEqual(theAttr1->ID(), TDataStd_ReferenceArray::GetID())) {
+    Handle(TDataStd_ReferenceArray) anArr1 = Handle(TDataStd_ReferenceArray)::DownCast(theAttr1);
+    Handle(TDataStd_ReferenceArray) anArr2 = Handle(TDataStd_ReferenceArray)::DownCast(theAttr2);
+    if (anArr1.IsNull() && anArr2.IsNull())
+      return true;
+    if (anArr1.IsNull() || anArr2.IsNull())
+      return false;
+    if (anArr1->Lower() == anArr2->Lower() && anArr1->Upper() == anArr2->Upper()) {
+      for(int a = anArr1->Lower(); a <= anArr1->Upper(); a++)
+        if (anArr1->Value(a) != anArr2->Value(a)) {
+          // avoid the transaction ID checking
+          if (a == 2 && anArr1->Upper() == 2 && anArr2->Label().Tag() == 1 &&
+            (anArr2->Label().Depth() == 4 || anArr2->Label().Depth() == 6))
+            continue;
+          return false;
+        }
+      return true;
+    }
+  } else if (Standard_GUID::IsEqual(theAttr1->ID(), TDataStd_ReferenceList::GetID())) {
+    Handle(TDataStd_ReferenceList) aList1 = Handle(TDataStd_ReferenceList)::DownCast(theAttr1);
+    Handle(TDataStd_ReferenceList) aList2= Handle(TDataStd_ReferenceList)::DownCast(theAttr2);
+    if (aList1.IsNull() && aList2.IsNull())
+      return true;
+    if (aList1.IsNull() || aList2.IsNull())
+      return false;
+    const TDF_LabelList& aLList1 = aList1->List();
+    const TDF_LabelList& aLList2 = aList2->List();
+    TDF_ListIteratorOfLabelList aLIter1(aLList1);
+    TDF_ListIteratorOfLabelList aLIter2(aLList2);
+    for(; aLIter1.More() && aLIter2.More(); aLIter1.Next(), aLIter2.Next()) {
+      if (aLIter1.Value() != aLIter2.Value())
+        return false;
+    }
+    return !aLIter1.More() && !aLIter2.More(); // both lists are with the same size
+  } else if (Standard_GUID::IsEqual(theAttr1->ID(), TDF_TagSource::GetID())) {
+    return true; // it just for created and removed feature: nothing is changed
   }
   return false;
 }
@@ -406,6 +444,8 @@ static bool isEmptyTransaction(const Handle(TDocStd_Document)& theDoc) {
         if (isEqualContent(anADelta->Attribute(), aCurrentAttr)) {
           continue; // attribute is not changed actually
         }
+      } else if (Standard_GUID::IsEqual(anADelta->Attribute()->ID(), TDataStd_AsciiString::GetID())) {
+        continue; // error message is disappeared
       }
     }
     return false;
index 88f16c6d8deb50eb9a9cf36c5b00d66ae77b1490..08314d734cc3cf2793e3e601ac6a9a53d891551d 100644 (file)
@@ -25,7 +25,7 @@ Standard_Boolean ModuleBase_FilterValidated::IsOk(const Handle(SelectMgr_EntityO
     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
     ModuleBase_ModelWidget* aCurrentWidget = aPanel->preselectionWidget();
     if (!aCurrentWidget)
-      aCurrentWidget = aPanel->activeWidget();
+      aCurrentWidget = myWorkshop->module()->activeWidget();
     ModuleBase_WidgetValidated* aWidgetValidated = dynamic_cast<ModuleBase_WidgetValidated*>
                                                                            (aCurrentWidget);
     ModuleBase_ViewerPrs aPrs;
index 3cbe89b5b4569b9970d29541b6cf10d410f037c0..29e89f3efff4863dffa23eccb418c231133f5a7a 100644 (file)
@@ -78,7 +78,7 @@ const char* toString(ModelAPI_ExecState theExecState)
 #undef TO_STRING
 }
 
-QString ModuleBase_IModule::getFeatureError(const FeaturePtr& theFeature)
+QString ModuleBase_IModule::getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI)
 {
   QString anError;
   if (!theFeature.get() || !theFeature->data()->isValid() || theFeature->isAction())
index f4d547d43c92c91d7afbc527be8fa16ee6874849..de02c0dfe5bf972adddf366c515562960c1a3cfe 100755 (executable)
@@ -101,6 +101,9 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
     return 0;\r
   }\r
 \r
+  /// Returns the active widget, by default it is the property panel active widget\r
+  virtual ModuleBase_ModelWidget* activeWidget() const = 0;\r
+\r
   /// Returns current workshop\r
   ModuleBase_IWorkshop* workshop() const { return myWorkshop; }\r
 \r
@@ -186,7 +189,7 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   //! Returns the feature error if the current state of the feature in the module is not correct\r
   //! If the feature is correct, it returns an empty value\r
   //! \return string value\r
-  virtual QString getFeatureError(const FeaturePtr& theFeature);\r
+  virtual QString getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI = true);\r
 \r
   /// Returns list of granted operation indices\r
   virtual void grantedOperationIds(ModuleBase_Operation* theOperation, QStringList& theIds) const;\r
@@ -200,6 +203,10 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject
   /// \param thePreviousState the previous state of the widget\r
   virtual void widgetStateChanged(int thePreviousState) {};\r
 \r
+  /// Returns true if the event is processed.\r
+  /// \param thePreviousAttributeID an index of the previous active attribute\r
+  virtual bool processEnter(const std::string& thePreviousAttributeID) { return false; };\r
+\r
 signals:\r
   /// Signal which is emitted when operation is launched\r
   void operationLaunched();\r
index ee4490aca9aa2450dc8a40a498962c1db91a69b0..0a87a74c838943d7ac01623d9f3a38c3e125d149 100644 (file)
@@ -8,8 +8,29 @@
  */
 
 #include "ModuleBase_IPropertyPanel.h"
+#include "ModuleBase_ModelWidget.h"
 
 ModuleBase_IPropertyPanel::ModuleBase_IPropertyPanel(QWidget* theParent) : QDockWidget(theParent), myIsEditing(false)
 {
 
 }
+
+ModuleBase_ModelWidget* ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget()
+{
+  return ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget(modelWidgets());
+}
+
+ModuleBase_ModelWidget* ModuleBase_IPropertyPanel::findFirstAcceptingValueWidget(
+                                                              const QList<ModuleBase_ModelWidget*>& theWidgets)
+{
+  ModuleBase_ModelWidget* aFirstWidget = 0;
+
+  ModuleBase_ModelWidget* aWgt;
+  QList<ModuleBase_ModelWidget*>::const_iterator aWIt;
+  for (aWIt = theWidgets.begin(); aWIt != theWidgets.end() && !aFirstWidget; ++aWIt) {
+    aWgt = (*aWIt);
+    if (aWgt->canSetValue())
+      aFirstWidget = aWgt;
+  }
+  return aFirstWidget;
+}
index c8c0f17215af55092aa3e6c2247a1677ac39490d..afafce7a756ce91ae5cf7506d52d0b16f3b3691b 100644 (file)
@@ -64,6 +64,15 @@ public:
   /// Sets widget processed by preselection
   virtual void setPreselectionWidget(ModuleBase_ModelWidget* theWidget) = 0;
 
+  /// Returns the first widget, where canSetValue returns true 
+  /// \return a widget or null
+  ModuleBase_ModelWidget* findFirstAcceptingValueWidget();
+
+  /// Returns the first widget, where canSetValue returns true 
+  /// \return a widget or null
+  static ModuleBase_ModelWidget* findFirstAcceptingValueWidget(
+                          const QList<ModuleBase_ModelWidget*>& theWidgets);
+
 signals:
   /// The signal about key release on the control, that corresponds to the attribute
   /// \param theEvent key release event
@@ -78,7 +87,8 @@ signals:
   void widgetActivated(ModuleBase_ModelWidget* theWidget);
 
   /// Emited when there is no next widget
-  void noMoreWidgets();
+  /// \param thePreviousAttributeID an attribute key of the previous active widget
+  void noMoreWidgets(const std::string& thePreviousAttributeID);
 
 public slots:
   /// Activate the next widget in the property panel
index dd2c9edd3a1817899a8cddbdeafce020525f1005..6e6b1aac416f420a7d17ce35dffec20d8c16df52 100644 (file)
@@ -107,6 +107,9 @@ Q_OBJECT
   /// \return the state whether the widget can accept the focus
   virtual bool focusTo();
 
+  /// Select the internal content if it can be selected. It is empty in the default realization
+  virtual void selectContent() {}
+
   /// The method called when widget is activated
   void activate();
 
index ca34bc942de059db29023c2e57affb7bcdea1f54..da5ff1fcb2c3f5325ad25c0e63fbf2621719d138 100755 (executable)
@@ -49,6 +49,32 @@ ModuleBase_OperationFeature::~ModuleBase_OperationFeature()
   clearPreselection();
 }
 
+void ModuleBase_OperationFeature::setEditOperation(const bool theRestartTransaction)
+{
+  if (isEditOperation())
+    return;
+
+  if (theRestartTransaction) {
+    // finsh previous create operation
+    emit beforeCommitted();
+    SessionPtr aMgr = ModelAPI_Session::get();
+    ModelAPI_Session::get()->finishOperation();
+
+    // start new edit operation
+    myIsEditing = true;
+    QString anId = getDescription()->operationId();
+    if (myIsEditing) {
+      anId = anId.append(EditSuffix());
+    }
+    ModelAPI_Session::get()->startOperation(anId.toStdString());
+    emit beforeStarted();
+  }
+  else
+    myIsEditing = true;
+
+  propertyPanel()->setEditingMode(isEditOperation());
+}
+
 FeaturePtr ModuleBase_OperationFeature::feature() const
 {
   return myFeature;
@@ -243,6 +269,7 @@ void ModuleBase_OperationFeature::abort()
 bool ModuleBase_OperationFeature::commit()
 {
   if (canBeCommitted()) {
+    emit beforeCommitted();
     // the widgets of property panel should not process any events come from data mode
     // after commit clicked. Some signal such as redisplay/create influence on content
     // of the object browser and viewer context. Therefore it influence to the current
@@ -257,7 +284,6 @@ bool ModuleBase_OperationFeature::commit()
     SessionPtr aMgr = ModelAPI_Session::get();
     /// Set current feature and remeber old current feature
 
-    emit beforeCommitted();
     commitOperation();
     aMgr->finishOperation();
 
index 11de99701c7756b512baa1be04422c5418a9e4dd..32e648bd9b0fc96797cf4c76613e55984fcf857a 100755 (executable)
@@ -64,6 +64,13 @@ Q_OBJECT
   /// Returns True id the current operation is launched in editing mode
   bool isEditOperation() const { return myIsEditing; }
 
+  /// Change the operation mode from create to edit.
+  /// The transaction and the operation name in the model history of transaction are the same.
+  /// It updates the edit state in the widgets of property panel
+  /// \param theRestartTransaction if true, the current model transaction is committed and
+  /// the new one is started
+  void setEditOperation(const bool theRestartTransaction);
+
   /// Returns the operation feature
   /// \return the feature
   FeaturePtr feature() const;
index 4e6ce242c0c41df11844d919760410023e4e83b4..a43f02cb6b2b6e43db5d314a612e487f082e453c 100644 (file)
@@ -144,6 +144,11 @@ bool ModuleBase_WidgetDoubleValue::restoreValueCustom()
   return true;
 }
 
+void ModuleBase_WidgetDoubleValue::selectContent()
+{
+  mySpinBox->selectAll();
+}
+
 QList<QWidget*> ModuleBase_WidgetDoubleValue::getControls() const
 {
   QList<QWidget*> aList;
index 8c1e0a1d8d955f0488b389ca23201d36caf0c836..cfd49221c3d525eef39aca22ca7a4154bfada40a 100644 (file)
@@ -37,6 +37,9 @@ Q_OBJECT
 
   virtual ~ModuleBase_WidgetDoubleValue();
 
+  /// Select the internal content if it can be selected. It is empty in the default realization
+  virtual void selectContent();
+
   /// Returns list of widget controls
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
index f63ec0bcaf59762fdcd607280933c9c6a8db87dd..5f26a60cc1dae3b96841998102e6933eb81b719e 100644 (file)
@@ -43,7 +43,6 @@ Q_OBJECT
   /// \return the state whether the widget can accept the focus
   virtual bool focusTo();
 
- private slots:
    /// Shous popup window under cursor for data editing
    void showPopupEditor();
 
index af676208cc5d3c9c53c12096e93c092d6ab06812..cadef7521a29517de99e82411f091e6feb78128c 100755 (executable)
@@ -304,8 +304,7 @@ QList<QWidget*> ModuleBase_WidgetMultiSelector::getControls() const
 //********************************************************************
 void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged()
 {
-  activateSelection(true);
-  activateFilters(true);
+  activateSelectionAndFilters(true);
   QList<ModuleBase_ViewerPrs> anEmptyList;
   // This method will call Selection changed event which will call onSelectionChanged
   // To clear mySelection, myListControl and storeValue()
@@ -354,14 +353,12 @@ void ModuleBase_WidgetMultiSelector::setCurrentShapeType(const TopAbs_ShapeEnum
     aShapeTypeName = myTypeCombo->itemText(idx);
     TopAbs_ShapeEnum aRefType = ModuleBase_Tools::shapeType(aShapeTypeName);
     if(aRefType == theShapeType && idx != myTypeCombo->currentIndex()) {
-      activateSelection(false);
-      activateFilters(false);
+      activateSelectionAndFilters(false);
       bool isBlocked = myTypeCombo->blockSignals(true);
       myTypeCombo->setCurrentIndex(idx);
       myTypeCombo->blockSignals(isBlocked);
 
-      activateSelection(true);
-      activateFilters(true);
+      activateSelectionAndFilters(true);
       break;
     }
   }
index 06163532001fea989b218fcffb4432e3ac8ba405..99edfb890e390b33024d5a85b05baefa0aa2ed43 100755 (executable)
@@ -110,7 +110,7 @@ bool ModuleBase_WidgetSelector::acceptSubShape(const GeomShapePtr& theShape,
 }
 
 //********************************************************************
-void ModuleBase_WidgetSelector::activateSelection(bool toActivate)
+void ModuleBase_WidgetSelector::activateSelectionAndFilters(bool toActivate)
 {
   updateSelectionName();
 
@@ -119,6 +119,7 @@ void ModuleBase_WidgetSelector::activateSelection(bool toActivate)
   } else {
     myWorkshop->deactivateSubShapesSelection();
   }
+  activateFilters(toActivate);
 }
 
 //********************************************************************
@@ -127,12 +128,10 @@ void ModuleBase_WidgetSelector::activateCustom()
   connect(myWorkshop, SIGNAL(selectionChanged()), this,
           SLOT(onSelectionChanged()), Qt::UniqueConnection);
   
-  activateSelection(true);
+  activateSelectionAndFilters(true);
 
   // Restore selection in the viewer by the attribute selection list
   myWorkshop->setSelected(getAttributeSelection());
-
-  activateFilters(true);
 }
 
 //********************************************************************
@@ -167,7 +166,7 @@ void ModuleBase_WidgetSelector::deactivate()
 {
   ModuleBase_ModelWidget::deactivate();
   disconnect(myWorkshop, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged()));
-  activateSelection(false);
-  activateFilters(false);
+  activateSelectionAndFilters(false);
+  ModuleBase_ModelWidget::deactivate();
 }
 
index 0deb253bdb1358353d186f7164d5aeb479164ba5..cb7d76e42ab1ada09ee8def3cacde5cd607ecadc 100755 (executable)
@@ -42,6 +42,9 @@ Q_OBJECT
   /// Defines if it is supposed that the widget should interact with the viewer.
   virtual bool isViewerSelector() { return true; }
 
+  /// Activate or deactivate selection and selection filters
+  void activateSelectionAndFilters(bool toActivate);
+
   /// Checks the widget validity. By default, it returns true.
   /// \param thePrs a selected presentation in the view
   /// \return a boolean value
@@ -54,10 +57,6 @@ Q_OBJECT
   /// The methiod called when widget is deactivated
   virtual void deactivate();
 
-protected:
-  /// Activate or deactivate selection
-  void activateSelection(bool toActivate);
-
  private slots:
    /// Slot which is called on selection event
   void onSelectionChanged();
index f1a5ef17ee27842fb50ca4362c0fbef5de396996..385f11a00f04e334e29fd048ebad38dc6765ae0e 100644 (file)
@@ -67,10 +67,6 @@ class MODULEBASE_EXPORT ModuleBase_WidgetValidated : public ModuleBase_ModelWidg
   //! Returns data object by AIS
   ObjectPtr findPresentedObject(const AISObjectPtr& theAIS) const;
 
-  /// It obtains selection filters from the workshop and activates them in the active viewer
-  /// \param toActivate a flag about activation or deactivation the filters
-  void activateFilters(const bool toActivate);
-
 protected:
   /// Creates a backup of the current values of the attribute
   /// It should be realized in the specific widget because of different
@@ -123,6 +119,10 @@ protected:
   /// \param theValues a list of presentations.
   void filterPresentations(QList<ModuleBase_ViewerPrs>& theValues);
 
+  /// It obtains selection filters from the workshop and activates them in the active viewer
+  /// \param toActivate a flag about activation or deactivation the filters
+  void activateFilters(const bool toActivate);
+
 protected:
   /// Reference to workshop
   ModuleBase_IWorkshop* myWorkshop; 
index 31ba5f79e3fb2b6c2f45b90e13dbd68b0fced9d6..03f142b91cc28dcc8a6bd9953a87efb2950a9706 100644 (file)
@@ -25,6 +25,7 @@ SET(PROJECT_HEADERS
        PartSet_Filters.h
        PartSet_FilterInfinite.h
        PartSet_SketcherMgr.h
+       PartSet_SketcherReetntrantMgr.h
        PartSet_MenuMgr.h
        PartSet_WidgetSketchCreator.h
        PartSet_IconFactory.h
@@ -49,6 +50,7 @@ SET(PROJECT_SOURCES
        PartSet_Filters.cpp
        PartSet_FilterInfinite.cpp
        PartSet_SketcherMgr.cpp
+       PartSet_SketcherReetntrantMgr.cpp
        PartSet_MenuMgr.cpp
        PartSet_WidgetSketchCreator.cpp
        PartSet_IconFactory.cpp
index 34c838a741f8924ffecde5e0a1163755453bb1ec..abf7f605ff13e08c8fbe16039be43cbad8414bb1 100755 (executable)
@@ -14,6 +14,7 @@
 #include "PartSet_WidgetFileSelector.h"
 #include "PartSet_WidgetSketchCreator.h"
 #include "PartSet_SketcherMgr.h"
+#include "PartSet_SketcherReetntrantMgr.h"
 #include "PartSet_MenuMgr.h"
 #include "PartSet_CustomPrs.h"
 #include "PartSet_IconFactory.h"
 
 #include <SketchPlugin_Feature.h>
 #include <SketchPlugin_Sketch.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Point.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintDistance.h>
@@ -112,18 +109,18 @@ extern "C" PARTSET_EXPORT ModuleBase_IModule* createModule(ModuleBase_IWorkshop*
 }
 
 PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop)
-  : ModuleBase_IModule(theWshop),
-  myRestartingMode(RM_None), myVisualLayerId(0), myHasConstraintShown(true)
+: ModuleBase_IModule(theWshop),
+  myVisualLayerId(0), myHasConstraintShown(true)
 {
   new PartSet_IconFactory();
 
   mySketchMgr = new PartSet_SketcherMgr(this);
+  mySketchReentrantMgr = new PartSet_SketcherReetntrantMgr(theWshop);
 
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWshop);
   XGUI_Workshop* aWorkshop = aConnector->workshop();
 
   XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
-  connect(anOpMgr, SIGNAL(keyEnterReleased()), this, SLOT(onEnterReleased()));
   connect(anOpMgr, SIGNAL(operationActivatedByPreselection()),
           this, SLOT(onOperationActivatedByPreselection()));
 
@@ -226,44 +223,28 @@ void PartSet_Module::operationCommitted(ModuleBase_Operation* theOperation)
     mySketchMgr->commitNestedSketch(theOperation);
   }
 
-  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
-  if (!aFOperation || aFOperation->isEditOperation())
-    return;
-  // the selection is cleared after commit the create operation
-  // in order to do not use the same selected objects in the restarted operation
-  // for common behaviour, the selection is cleared even if the operation is not restarted
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
-  XGUI_Workshop* aWorkshop = aConnector->workshop();
-  aWorkshop->selector()->clearSelection();
-
   /// Restart sketcher operations automatically
-  FeaturePtr aFeature = aFOperation->feature();
-  std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
-            std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-  if (aSPFeature && (myRestartingMode == RM_LastFeatureUsed ||
-                     myRestartingMode == RM_EmptyFeatureUsed)) {
-    myLastOperationId = aFOperation->id();
-    myLastFeature = myRestartingMode == RM_LastFeatureUsed ? aFOperation->feature() : FeaturePtr();
-    if (!sketchMgr()->sketchSolverError())
-      launchOperation(myLastOperationId);
+  if (!mySketchReentrantMgr->operationCommitted(theOperation)) {
+    // the selection is cleared after commit the create operation
+    // in order to do not use the same selected objects in the restarted operation
+    // for common behaviour, the selection is cleared even if the operation is not restarted
+    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
+    XGUI_Workshop* aWorkshop = aConnector->workshop();
+    aWorkshop->selector()->clearSelection();
   }
-  breakOperationSequence();
-}
-
-void PartSet_Module::breakOperationSequence()
-{
-  myLastOperationId = "";
-  myLastFeature = FeaturePtr();
-  myRestartingMode = RM_None;
 }
 
 void PartSet_Module::operationAborted(ModuleBase_Operation* theOperation)
 {
-  breakOperationSequence();
+  /// Restart sketcher operations automatically
+  mySketchReentrantMgr->operationAborted(theOperation);
 }
 
 void PartSet_Module::operationStarted(ModuleBase_Operation* theOperation)
 {
+  /// Restart sketcher operations automatically
+  mySketchReentrantMgr->operationStarted(theOperation);
+
   if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
     mySketchMgr->startSketch(theOperation);
   }
@@ -388,11 +369,11 @@ void PartSet_Module::updateViewerMenu(const QMap<QString, QAction*>& theStdActio
   myMenuMgr->updateViewerMenu(theStdActions);
 }
 
-QString PartSet_Module::getFeatureError(const FeaturePtr& theFeature)
+QString PartSet_Module::getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI)
 {
-  QString anError = ModuleBase_IModule::getFeatureError(theFeature);
+  QString anError = ModuleBase_IModule::getFeatureError(theFeature, isCheckGUI);
   if (anError.isEmpty())
-    anError = sketchMgr()->getFeatureError(theFeature);
+    anError = sketchMgr()->getFeatureError(theFeature, isCheckGUI);
 
   return anError;
 }
@@ -444,31 +425,9 @@ void PartSet_Module::propertyPanelDefined(ModuleBase_Operation* theOperation)
     return;
 
   ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
-  if (PartSet_SketcherMgr::isSketchOperation(aFOperation) &&  (aFOperation->isEditOperation())) {
-    // we have to manually activate the sketch label in edit mode
-      aPanel->activateWidget(aPanel->modelWidgets().first());
-      return;
-  }
-
-  // Restart last operation type 
-  if ((aFOperation->id() == myLastOperationId) && myLastFeature) {
-    ModuleBase_ModelWidget* aWgt = aPanel->activeWidget();
-    if (aFOperation->id().toStdString() == SketchPlugin_Line::ID()) {
-      // Initialise new line with first point equal to end of previous
-      PartSet_WidgetPoint2D* aPnt2dWgt = dynamic_cast<PartSet_WidgetPoint2D*>(aWgt);
-      if (aPnt2dWgt) {
-        std::shared_ptr<ModelAPI_Data> aData = myLastFeature->data();
-        std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
-          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(SketchPlugin_Line::END_ID()));
-        if (aPoint) {
-          aPnt2dWgt->setPoint(aPoint->x(), aPoint->y());
-          PartSet_Tools::setConstraints(mySketchMgr->activeSketch(), aFOperation->feature(), 
-            aWgt->attributeID(), aPoint->x(), aPoint->y());
-          aPanel->activateNextWidget(aPnt2dWgt);
-        }
-      }
-    }
-  }
+  // we have to manually activate the sketch label in edit mode
+  if (PartSet_SketcherMgr::isSketchOperation(aFOperation) &&  (aFOperation->isEditOperation()))
+    aPanel->activateWidget(aPanel->modelWidgets().first());
 }
 
 
@@ -512,13 +471,11 @@ void PartSet_Module::onKeyRelease(ModuleBase_IViewWindow* theWnd, QKeyEvent* the
   anOpMgr->onKeyReleased(theEvent);
 }
 
-void PartSet_Module::onEnterReleased()
-{
-  myRestartingMode = RM_EmptyFeatureUsed;
-}
-
 void PartSet_Module::onOperationActivatedByPreselection()
 {
+  if (!mySketchReentrantMgr->canBeCommittedByPreselection())
+    return;
+
   ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
   if(anOperation && PartSet_SketcherMgr::isNestedSketchOperation(anOperation)) {
     // Set final definitions if they are necessary
@@ -529,45 +486,6 @@ void PartSet_Module::onOperationActivatedByPreselection()
   }
 }
 
-void PartSet_Module::onNoMoreWidgets()
-{
-  ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
-  if (anOperation) {
-    if (PartSet_SketcherMgr::isNestedSketchOperation(anOperation)) {
-      if (myRestartingMode != RM_Forbided)
-        myRestartingMode = RM_LastFeatureUsed;
-      XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(workshop());
-      XGUI_Workshop* aWorkshop = aConnector->workshop();
-      XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
-      // do nothing if the feature can not be applyed
-      if (anOpMgr->isApplyEnabled())
-        anOperation->commit();
-    }
-  }
-}
-
-void PartSet_Module::onVertexSelected()
-{
-  ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
-  if (aOperation->id().toStdString() == SketchPlugin_Line::ID()) {
-    /// If last line finished on vertex the lines creation sequence has to be break
-    ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
-    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
-    const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
-    QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
-    bool aFoundWidget = false;
-    bool aFoundObligatory = false;
-    for (; anIt != aLast && !aFoundObligatory; anIt++) {
-      if (!aFoundWidget)
-        aFoundWidget = *anIt == anActiveWidget;
-      else
-        aFoundObligatory = (*anIt)->isObligatory();
-    }
-    if (!aFoundObligatory)
-      myRestartingMode = RM_Forbided;
-  }
-}
-
 ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& theType, QWidget* theParent,
                                             Config_WidgetAPI* theWidgetApi, std::string theParentId)
 {
@@ -587,13 +505,13 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
     PartSet_WidgetPoint2D* aPointWgt = new PartSet_WidgetPoint2D(theParent, aWorkshop,
                                                                  theWidgetApi, theParentId);
     aPointWgt->setSketch(mySketchMgr->activeSketch());
-    connect(aPointWgt, SIGNAL(vertexSelected()), this, SLOT(onVertexSelected()));
+    connect(aPointWgt, SIGNAL(vertexSelected()), sketchReentranceMgr(), SLOT(onVertexSelected()));
     aWgt = aPointWgt;
   } else if (theType == "sketch-2dpoint_flyout_selector") {
     PartSet_WidgetPoint2DFlyout* aPointWgt = new PartSet_WidgetPoint2DFlyout(theParent, aWorkshop,
                                                                  theWidgetApi, theParentId);
     aPointWgt->setSketch(mySketchMgr->activeSketch());
-    connect(aPointWgt, SIGNAL(vertexSelected()), this, SLOT(onVertexSelected()));
+    connect(aPointWgt, SIGNAL(vertexSelected()), sketchReentranceMgr(), SLOT(onVertexSelected()));
     aWgt = aPointWgt;
   } else if (theType == "point2ddistance") {
     PartSet_WidgetPoint2dDistance* aDistanceWgt = new PartSet_WidgetPoint2dDistance(theParent,
@@ -625,6 +543,20 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
   return aWgt;
 }
 
+ModuleBase_ModelWidget* PartSet_Module::activeWidget() const
+{
+  ModuleBase_ModelWidget* anActiveWidget = 0;
+
+  anActiveWidget = mySketchReentrantMgr->internalActiveWidget();
+  if (!anActiveWidget) {
+    ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
+    if (aOperation) {
+      ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
+      anActiveWidget = aPanel->activeWidget();
+    }
+  }
+  return anActiveWidget;
+}
 
 bool PartSet_Module::deleteObjects()
 {
@@ -1063,13 +995,11 @@ void PartSet_Module::onViewCreated(ModuleBase_IViewWindow*)
   // the filters of this widget should be activated in the created view
   ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
   if (aOperation) {
-    ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
-    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
+    ModuleBase_ModelWidget* anActiveWidget = activeWidget();
     if (anActiveWidget) {
-      ModuleBase_WidgetValidated* aWidgetValidated = dynamic_cast<ModuleBase_WidgetValidated*>
-                                                                             (anActiveWidget);
-      if (aWidgetValidated)
-        aWidgetValidated->activateFilters(true);
+      ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(anActiveWidget);
+      if (aWSelector)
+        aWSelector->activateSelectionAndFilters(true);
     }
   }
 }
@@ -1079,3 +1009,8 @@ void PartSet_Module::widgetStateChanged(int thePreviousState)
 {
   mySketchMgr->widgetStateChanged(thePreviousState);
 }
+
+bool PartSet_Module::processEnter(const std::string& thePreviousAttributeID)
+{
+  return mySketchReentrantMgr->processEnter(thePreviousAttributeID);
+}
index 5ff0b77dfe6d1905d4fffc072b23cc3e8854ea71..26f7ace3431a7ec298888c5000ed51013a2e318f 100755 (executable)
@@ -31,6 +31,7 @@ class ModuleBase_IViewWindow;
 class PartSet_MenuMgr;
 class PartSet_CustomPrs;
 class PartSet_SketcherMgr;
+class PartSet_SketcherReetntrantMgr;
 
 class QAction;
 
@@ -66,6 +67,10 @@ public:
   virtual ModuleBase_ModelWidget* createWidgetByType(const std::string& theType, QWidget* theParent,
                                                      Config_WidgetAPI* theWidgetApi, std::string theParentId);
 
+  /// Returns the active widget, by default it is the property panel active widget
+  /// If the internal edit operation is started, this is the first widget of the operation
+  virtual ModuleBase_ModelWidget* activeWidget() const;
+
   /// Call back forlast tuning of property panel before operation performance
   virtual void propertyPanelDefined(ModuleBase_Operation* theOperation);
 
@@ -158,6 +163,9 @@ public:
   /// Returns sketch manager object
   PartSet_SketcherMgr* sketchMgr() const { return mySketchMgr; }
 
+  /// Returns sketch reentrant manager
+  PartSet_SketcherReetntrantMgr* sketchReentranceMgr() { return mySketchReentrantMgr; }
+
   /// Performs functionality on closing document
   virtual void closeDocument();
 
@@ -198,7 +206,7 @@ public:
   //! Returns the feature error if the current state of the feature in the module is not correct
   //! If the feature is correct, it returns an empty value
   //! \return string value
-  virtual QString getFeatureError(const FeaturePtr& theFeature);
+  virtual QString getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI = true);
 
   /// Returns list of granted operation indices
   virtual void grantedOperationIds(ModuleBase_Operation* theOperation, QStringList& theIds) const;
@@ -207,11 +215,11 @@ public:
   /// \param thePreviousState the previous widget value state
   virtual void widgetStateChanged(int thePreviousState);
 
-public slots:
-  /// SLOT, that is called by no more widget signal emitted by property panel
-  /// Set a specific flag to restart the sketcher operation
-  void onNoMoreWidgets();
+  /// Returns true if the event is processed. It gives the reentrance manager to process the enter.
+  /// \param thePreviousAttributeID an index of the previous active attribute
+  virtual bool processEnter(const std::string& thePreviousAttributeID);
 
+public slots:
   /// Redefines the parent method in order to customize the next case:
   /// If the sketch nested operation is active and the presentation is not visualized in the viewer,
   /// the operation should be always aborted.
@@ -240,10 +248,6 @@ protected slots:
   /// \param theEvent the key event
   void onKeyRelease(ModuleBase_IViewWindow* theWnd, QKeyEvent* theEvent);
 
-  /// SLOT, that is called by enter key released
-  /// Set a specific type of restarting the current operation
-  void onEnterReleased();
-
   /// SLOT, that is called by the current operation filling with the preselection.
   /// It commits the operation of it is can be committed
   void onOperationActivatedByPreselection();
@@ -267,30 +271,20 @@ protected:
   virtual void connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect);
 
  private slots:
-   /// Processing of vertex selected
-   void onVertexSelected();
-
    void onTreeViewDoubleClick(const QModelIndex&);
 
    void onActiveDocPopup(const QPoint&);
 
  private:
-  /// Breaks sequense of automatically resterted operations
-  void breakOperationSequence();
 
   //! Delete features
   virtual bool deleteObjects();
 
  private:
-   QString myLastOperationId;
-   FeaturePtr myLastFeature;
-
-   // Automatical restarting mode flag
-   RestartingMode myRestartingMode;
-
   SelectMgr_ListOfFilter mySelectionFilters;
 
   PartSet_SketcherMgr* mySketchMgr;
+  PartSet_SketcherReetntrantMgr* mySketchReentrantMgr;
   PartSet_MenuMgr* myMenuMgr;
   /// A default custom presentation, which is used for references objects of started operation
   PartSet_CustomPrs* myCustomPrs;
index 97a5ce43c6021061ca2056f1d946d84429254494..ac3eaf7f9449aed7c41b43f2fbed95da31645513 100755 (executable)
@@ -5,11 +5,13 @@
 // Author:      Vitaly SMETANNIKOV
 
 #include "PartSet_SketcherMgr.h"
+#include "PartSet_SketcherReetntrantMgr.h"
 #include "PartSet_Module.h"
 #include "PartSet_WidgetPoint2d.h"
 #include "PartSet_WidgetPoint2dDistance.h"
 #include "PartSet_Tools.h"
 #include "PartSet_WidgetSketchLabel.h"
+#include "PartSet_WidgetEditor.h"
 
 #include <XGUI_ModuleConnector.h>
 #include <XGUI_Displayer.h>
@@ -298,6 +300,9 @@ void PartSet_SketcherMgr::onAfterValuesChangedInPropertyPanel()
 
 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
+  if (myModule->sketchReentranceMgr()->processMousePressed(theWnd, theEvent))
+    return;
+
   get2dPoint(theWnd, theEvent, myClickedPoint);
 
   if (!(theEvent->buttons() & Qt::LeftButton))
@@ -400,6 +405,9 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
 
 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
+  if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
+    return;
+
   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
   if (!aViewer->canDragByMouse())
@@ -435,6 +443,9 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse
 
 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
 {
+  if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
+    return;
+
   if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) {
     myIsMouseOverViewProcessed = true;
     // 1. perform the widget mouse move functionality and display the presentation
@@ -569,7 +580,9 @@ void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMo
       // Find corresponded widget to activate value editing
       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
         if (aWgt->attributeID() == "ConstraintValue") {
-          aWgt->focusTo();
+          PartSet_WidgetEditor* anEditor = dynamic_cast<PartSet_WidgetEditor*>(aWgt);
+          if (anEditor)
+            anEditor->showPopupEditor();
           return;
         }
       }
@@ -582,10 +595,17 @@ void PartSet_SketcherMgr::onApplicationStarted()
   ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(anIWorkshop);
   XGUI_Workshop* aWorkshop = aConnector->workshop();
+  PartSet_SketcherReetntrantMgr* aReentranceMgr = myModule->sketchReentranceMgr();
+
   XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
   if (aPropertyPanel) {
     connect(aPropertyPanel, SIGNAL(beforeWidgetActivated(ModuleBase_ModelWidget*)),
             this, SLOT(onBeforeWidgetActivated(ModuleBase_ModelWidget*)));
+
+    connect(aPropertyPanel, SIGNAL(noMoreWidgets(const std::string&)),
+            aReentranceMgr, SLOT(onNoMoreWidgets(const std::string&)));
+    connect(aPropertyPanel, SIGNAL(widgetActivated(ModuleBase_ModelWidget*)),
+            aReentranceMgr, SLOT(onWidgetActivated()));
   }
 
   XGUI_ViewerProxy* aViewerProxy = aWorkshop->viewer();
@@ -658,7 +678,7 @@ bool PartSet_SketcherMgr::sketchSolverError()
   return anError;
 }
 
-QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
+QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI)
 {
   QString anError = "";
   if (!theFeature.get() || !theFeature->data()->isValid())
@@ -671,7 +691,7 @@ QString PartSet_SketcherMgr::getFeatureError(const FeaturePtr& theFeature)
   }
   else {
     ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
-    if (anActiveWidget) {
+    if (isCheckGUI && anActiveWidget) {
       ModuleBase_ModelWidget::ValueState aState = anActiveWidget->getValueState();
       if (aState != ModuleBase_ModelWidget::Stored) {
         AttributePtr anAttr = anActiveWidget->feature()->attribute(anActiveWidget->attributeID());
@@ -907,7 +927,7 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOp)
 {
   myIsMouseOverViewProcessed = true;
   operationMgr()->onValidateOperation();
-  if (isNestedCreateOperation(theOp))
+  if (isNestedCreateOperation(theOp) || myModule->sketchReentranceMgr()->isInternalEditActive())
     QApplication::restoreOverrideCursor();
 }
 
index 38981450ba4c3756ec9bbc9e35373750203e7796..b7e7ffd6e5333d5a0bfd5c5aa716f2a04284a99f 100644 (file)
@@ -180,7 +180,7 @@ public:
   //! Incorrect states: the feature is sketch, the solver error value
   //! The feature value is reset, this is the flag of sketch mgr
   //! \return string value
-  QString getFeatureError(const FeaturePtr& theFeature);
+  QString getFeatureError(const FeaturePtr& theFeature, const bool isCheckGUI = true);
 
   /// Returns list of strings which contains id's of sketch operations
   static const QStringList& sketchOperationIdList();
diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.cpp b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp
new file mode 100755 (executable)
index 0000000..abde2a7
--- /dev/null
@@ -0,0 +1,405 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+#include "PartSet_SketcherReetntrantMgr.h"
+#include "PartSet_Module.h"
+#include "PartSet_SketcherMgr.h"
+#include "PartSet_WidgetPoint2D.h"
+
+#include "ModelAPI_Session.h"
+
+#include <ModuleBase_IPropertyPanel.h>
+#include <ModuleBase_OperationFeature.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>
+
+PartSet_SketcherReetntrantMgr::PartSet_SketcherReetntrantMgr(ModuleBase_IWorkshop* theWorkshop)
+: QObject(theWorkshop),
+  myWorkshop(theWorkshop),
+  myRestartingMode(RM_None),
+  myIsFlagsBlocked(false),
+  myIsInternalEditOperation(false)
+{
+}
+
+PartSet_SketcherReetntrantMgr::~PartSet_SketcherReetntrantMgr()
+{
+}
+
+ModuleBase_ModelWidget* PartSet_SketcherReetntrantMgr::internalActiveWidget() const
+{
+  ModuleBase_ModelWidget* aWidget = 0;
+  if (!isActiveMgr())
+    return aWidget;
+
+  ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
+  if (aOperation) {
+    ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
+    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
+    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;
+  if (!isActiveMgr())
+    return aProcessed;
+
+  aProcessed = myIsInternalEditOperation;
+  resetFlags();
+
+  return aProcessed;
+}
+
+void PartSet_SketcherReetntrantMgr::operationStarted(ModuleBase_Operation* theOperation)
+{
+  if (!isActiveMgr())
+    return;
+
+  resetFlags();
+}
+
+void PartSet_SketcherReetntrantMgr::operationAborted(ModuleBase_Operation* theOperation)
+{
+  if (!isActiveMgr())
+    return;
+
+  resetFlags();
+}
+
+bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /* theWnd*/,
+                                                      QMouseEvent* /* theEvent*/)
+{
+  bool aProcessed = false;
+  if (!isActiveMgr())
+    return aProcessed;
+
+  if  (myIsInternalEditOperation) {
+    PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(module()->activeWidget());
+    if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) {
+      ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                         (myWorkshop->currentOperation());
+      FeaturePtr aLastFeature = myRestartingMode == RM_LastFeatureUsed ? aFOperation->feature() : FeaturePtr();
+      restartOperation();
+      aProcessed = true;
+
+      if (aLastFeature) {
+        ModuleBase_IPropertyPanel* aPanel = myWorkshop->currentOperation()->propertyPanel();
+        PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast<PartSet_WidgetPoint2D*>(aPanel->activeWidget());
+        if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) {
+          QList<ModuleBase_ViewerPrs> aSelection;
+          aSelection.append(ModuleBase_ViewerPrs(aLastFeature, TopoDS_Shape(), NULL));
+          if (aPoint2DWdg->setSelection(aSelection, true))
+            aPanel->activateNextWidget(aPoint2DWdg);
+        }
+      }
+    }
+  }
+  return aProcessed;
+}
+
+bool PartSet_SketcherReetntrantMgr::processMousePressed(ModuleBase_IViewWindow* /* theWnd*/,
+                                                        QMouseEvent* /* theEvent*/)
+{
+  return isActiveMgr() && myIsInternalEditOperation;
+}
+
+bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* theWnd,
+                                                         QMouseEvent* theEvent)
+{
+  bool aProcessed = false;
+  if (!isActiveMgr())
+    return aProcessed;
+
+  if (myIsInternalEditOperation) {
+    ModuleBase_Operation* anOperation = myWorkshop->currentOperation();
+    ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
+
+    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
+    if (!anActiveWidget || !anActiveWidget->isViewerSelector()) {
+      restartOperation();
+      aProcessed = true;
+
+      // 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());
+      ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget();
+      if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) {
+        aPoint2DWdg->onMouseRelease(theWnd, theEvent);
+      }
+    }
+  }
+
+  return aProcessed;
+}
+
+void PartSet_SketcherReetntrantMgr::onWidgetActivated()
+{
+  if (!isActiveMgr())
+    return;
+  if (!myIsInternalEditOperation)
+    return;
+
+  PartSet_Module* aModule = module();
+  ModuleBase_ModelWidget* aFirstWidget = aModule->activeWidget();
+  ModuleBase_IPropertyPanel* aPanel = aModule->currentOperation()->propertyPanel();
+  if (aFirstWidget != aPanel->activeWidget()) {
+    ModuleBase_WidgetSelector* aWSelector = dynamic_cast<ModuleBase_WidgetSelector*>(aFirstWidget);
+    if (aWSelector)
+      aWSelector->activateSelectionAndFilters(true);
+  }
+}
+
+void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePreviousAttributeID)
+{
+  if (!isActiveMgr())
+    return;
+
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                       (myWorkshop->currentOperation());
+  if (!myWorkshop->module()->getFeatureError(aFOperation->feature(), false).isEmpty())
+    return;
+
+  if (aFOperation && PartSet_SketcherMgr::isNestedSketchOperation(aFOperation)) {
+    bool isStarted = false;
+    if (myRestartingMode != RM_Forbided) {
+      myRestartingMode = RM_LastFeatureUsed;
+      isStarted = startInternalEdit(thePreviousAttributeID);
+    }
+    if (!isStarted)
+      aFOperation->commit();
+  }
+}
+
+bool PartSet_SketcherReetntrantMgr::processEnter(const std::string& thePreviousAttributeID)
+{
+  bool isDone = false;
+
+  if (!isActiveMgr())
+    return isDone;
+
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                       (myWorkshop->currentOperation());
+  if (!myWorkshop->module()->getFeatureError(aFOperation->feature(), false).isEmpty())
+    return isDone;
+
+  myRestartingMode = RM_EmptyFeatureUsed;
+  isDone = startInternalEdit(thePreviousAttributeID);
+
+  return isDone;
+}
+
+void PartSet_SketcherReetntrantMgr::onVertexSelected()
+{
+  if (!isActiveMgr())
+    return;
+
+  ModuleBase_Operation* aOperation = myWorkshop->currentOperation();
+  if (aOperation->id().toStdString() == SketchPlugin_Line::ID()) {
+    /// If last line finished on vertex the lines creation sequence has to be break
+    ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
+    ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
+    const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
+    QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
+    bool aFoundWidget = false;
+    bool aFoundObligatory = false;
+    for (; anIt != aLast && !aFoundObligatory; anIt++) {
+      if (!aFoundWidget)
+        aFoundWidget = *anIt == anActiveWidget;
+      else
+        aFoundObligatory = (*anIt)->isObligatory();
+    }
+    if (!aFoundObligatory)
+      myRestartingMode = RM_Forbided;
+  }
+}
+
+void PartSet_SketcherReetntrantMgr::onBeforeStopped()
+{
+  if (!isActiveMgr() || !myIsInternalEditOperation)
+    return;
+
+  beforeStopInternalEdit();
+}
+
+bool PartSet_SketcherReetntrantMgr::canBeCommittedByPreselection()
+{
+  return !isActiveMgr() || myRestartingMode == RM_None;
+}
+
+bool PartSet_SketcherReetntrantMgr::isActiveMgr() const
+{
+  ModuleBase_Operation* aCurrentOperation = myWorkshop->currentOperation();
+
+  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;
+}
+
+bool PartSet_SketcherReetntrantMgr::startInternalEdit(const std::string& thePreviousAttributeID)
+{
+  bool isDone = false;
+  ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
+                                                     (myWorkshop->currentOperation());
+
+  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();
+
+    // activate the last active widget in the Property Panel
+    if (!thePreviousAttributeID.empty()) {
+      ModuleBase_Operation* anEditOperation = module()->currentOperation();
+      if (anEditOperation) {
+        ModuleBase_IPropertyPanel* aPanel = aFOperation->propertyPanel();
+        ModuleBase_ModelWidget* aPreviousAttributeWidget = 0;
+        QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
+        for (int i = 0, aNb = aWidgets.size(); i < aNb && !aPreviousAttributeWidget; i++) {
+          if (aWidgets[i]->attributeID() == thePreviousAttributeID)
+            aPreviousAttributeWidget = aWidgets[i];
+        }
+        // If the current widget is a selector, do nothing, it processes the mouse press
+        if (aPreviousAttributeWidget && !aPreviousAttributeWidget->isViewerSelector()) {
+          aPreviousAttributeWidget->focusTo();
+          aPreviousAttributeWidget->selectContent();
+        }
+      }
+    }
+  }
+  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()
+{
+  if (myIsInternalEditOperation) {
+    ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(
+                                                                  myWorkshop->currentOperation());
+    if (aFOperation) {
+      myIsFlagsBlocked = true;
+      aFOperation->commit();
+      module()->launchOperation(aFOperation->id());
+      myIsFlagsBlocked = false;
+      resetFlags();
+    }
+  }
+}
+
+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) {
+      aWidget->setFeature(myInternalFeature, true);
+    }
+    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) {
+    myIsInternalEditOperation = false;
+    myRestartingMode = RM_None;
+  }
+}
+
+XGUI_Workshop* PartSet_SketcherReetntrantMgr::workshop() const
+{
+  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
+  return aConnector->workshop();
+}
+
+PartSet_Module* PartSet_SketcherReetntrantMgr::module() const
+{
+  return dynamic_cast<PartSet_Module*>(myWorkshop->module());
+}
+
diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.h b/src/PartSet/PartSet_SketcherReetntrantMgr.h
new file mode 100755 (executable)
index 0000000..2d76dd6
--- /dev/null
@@ -0,0 +1,160 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+#ifndef PartSet_SketcherReetntrantMgr_H
+#define PartSet_SketcherReetntrantMgr_H
+
+#include "PartSet.h"
+
+#include <ModelAPI_Feature.h>
+
+#include <string>
+
+#include <QObject>
+
+class ModuleBase_IWorkshop;
+class ModuleBase_Operation;
+class ModuleBase_ModelWidget;
+class ModuleBase_IViewWindow;
+
+class QMouseEvent;
+
+class XGUI_Workshop;
+class PartSet_Module;
+
+/// \ingroup PartSet_SketcherReetntrantMgr
+/// It provides reentrant create operations in sketch, that is when all inputs are valid,
+/// automatic validation of the creation and switch the created entity to edit mode
+/// ('internal' edit operation), with the ability to simultaneously create the next entity
+/// of same type (re-entrance of the operation).
+/// OK valids the current edition and exits from the operation (no re-entrance).
+/// Cancel removes (undo) the entity currently edited and exits from the operation (no re-entrance).
+class PARTSET_EXPORT PartSet_SketcherReetntrantMgr : public QObject
+{
+Q_OBJECT
+
+/// Enumeration to specify the restart operation properties.
+enum RestartingMode {
+  RM_None, /// the operation should not be restarted
+  RM_Forbided, /// the operation should not be restarted after there is no active widget
+  RM_LastFeatureUsed, /// the operation is restarted and use the previous feature for own initialization
+  RM_EmptyFeatureUsed /// the operation is restarted and does not use the previous feature
+};
+
+public:
+  /// Constructor
+  /// \param theParent a parent object
+  PartSet_SketcherReetntrantMgr(ModuleBase_IWorkshop* theWorkshop);
+  virtual ~PartSet_SketcherReetntrantMgr();
+
+public:
+  /// Returns a first widget of the current opeation if the internal edit operation is active
+  /// or return null. If the current widget of the operation is a viewer selector, it returns null.
+  ModuleBase_ModelWidget* internalActiveWidget() const;
+
+  /// Return true if the current edit operation is an internal
+  bool isInternalEditActive() const;
+
+  /// if the internal flags allow it and the manager is active, it starts an internal edit operation
+  /// for the created operation.
+  /// \param thePreviousAttributeID an index of the previous active attribute
+  //bool restartOperation(const std::string& thePreviousAttributeID);
+  bool processEnter(const std::string& thePreviousAttributeID);
+
+  /// Resets the internal flags
+  /// \param theOperation a started operation
+  void operationStarted(ModuleBase_Operation* theOperation);
+
+  /// Resets the internal flags
+  /// \param theOperation a started operation
+  /// \return state whether the internal edit operation was active
+  bool operationCommitted(ModuleBase_Operation* theOperation);
+
+  /// Resets the internal flags
+  /// \param theOperation a started operation
+  void operationAborted(ModuleBase_Operation* theOperation);
+
+  /// Return true if the manager processes the mouse move event
+  /// It happens if the current operation is an internal edit operation and the first
+  /// control can be filled by the mouse move event. The operation is restarted.
+  /// \return true if operation is committed.
+  bool processMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+
+  /// Return true if the manager processes the mouse press event
+  /// \return true if the current operation is an internal edit operation.
+  bool processMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+
+  /// Return true if the manager processes the mouse enter event
+  /// It happens if the current operation is an internal edit operation.
+  /// The operation is restarted. If the first widget of the started operation is
+  /// the point 2d, it processes this mouse event
+  /// \return true if operation is committed.
+  bool processMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
+
+  /// It is called by the current operation filling with the preselection.
+  /// Returns false if the reentrant mode of the operation is not empty.
+  bool canBeCommittedByPreselection();
+
+private slots:
+  /// SLOT, that is called by a widget activating in the property panel
+  /// If the 'internal' edit operation is started, it activates the first widget selection
+  void onWidgetActivated();
+
+  /// SLOT, that is called by no more widget signal emitted by property panel
+  /// Start an internal edit operation or, if the internal flag is forbided, commits
+  /// the current operation
+  /// \param thePreviousAttributeID an index of the previous active attribute
+  void onNoMoreWidgets(const std::string& thePreviousAttributeID);
+
+  /// Processing of vertex selected. Set an internal reentrant flag to forbiddent state if
+  /// the current feature is a line and there are not obligate widgets anymore
+  void onVertexSelected();
+
+  /// Deactivates selection and filters of the first operation widget if it is an internal
+  /// 'edit' operation
+  void onBeforeStopped();
+
+private:
+  /// Returns true if the current operation is a sketch or a nested sketch operation
+  bool isActiveMgr() const;
+
+  /// Sets the focus to the last control of the property panel and activates selection
+  /// of the first widget to can select first value of the next create operation
+  /// \param thePreviousAttributeID an index of the previous attribute to set focus to this widget
+  /// \return true if it is started
+  bool startInternalEdit(const std::string& thePreviousAttributeID);
+
+  /// Disconnects this manager from operation signals, deactivate selection of the first control
+  /// in the viewer.
+  void beforeStopInternalEdit();
+
+  /// Commits the current operation and launches a new with the commited operation feature index
+  void restartOperation();
+
+  /// Creates an internal feature and controls to process it
+  void createInternalFeature();
+
+  /// A pair method for an internal creation to remove it and clear all created controls
+  void deleteInternalFeature();
+
+  /// Breaks sequense of automatically resterted operations
+  void resetFlags();
+
+  /// Returns the workshop
+  XGUI_Workshop* workshop() const;
+
+  /// Returns the workshop module
+  PartSet_Module* module() const;
+
+private:
+  ModuleBase_IWorkshop* myWorkshop; /// the workshop
+
+  RestartingMode myRestartingMode;  /// automatical restarting mode flag
+  bool myIsFlagsBlocked; /// true when reset of flags should not be perfromed
+  bool myIsInternalEditOperation; /// true when the 'internal' edit is started
+
+  FeaturePtr myInternalFeature;
+  QWidget* myInternalWidget;
+  ModuleBase_ModelWidget* myInternalActiveWidget;
+};
+
+#endif
index a53eb3596cd4e314138db36954cac113726a9ca7..9b4aa471db355d9369f04e6c83e2a6526a7b91be 100755 (executable)
@@ -7,6 +7,7 @@
 #include "PartSet_Validators.h"
 
 #include "PartSet_Tools.h"
+#include "PartSet_SketcherMgr.h"
 
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
@@ -92,14 +93,21 @@ std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
 {
   ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
+  // during the create operation empty selection is always valid
   if (!aFeatureOp->isEditOperation()) {
     return true;
   }
-  std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
-  if (aPlane.get())
-    return true;
-  else 
-    return false;
+  else {
+    if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
+      std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
+      if (aPlane.get())
+        return true;
+      else 
+        return false;
+    }
+    else// in edit operation an empty selection is always valid, performed for re-entrant operrations
+      return true;
+  }
 }
 
 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
index 4857863b5ea31d1f905187ffcb0a67fad13d6ac7..d0a129aba01b49031ea569c398776a79f3683fb8 100644 (file)
@@ -23,7 +23,7 @@ PartSet_WidgetEditor::PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorks
 bool PartSet_WidgetEditor::focusTo()
 {
   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
-  if (aModule->isMouseOverWindow())
+  if (aModule->isMouseOverWindow() && !isEditingMode())
     return ModuleBase_WidgetEditor::focusTo();
   else {
     return ModuleBase_WidgetDoubleValue::focusTo();
index 8d9f07d31afe6579a720e41bc74e139c100b686f..ebfe32e00530ccc34534908a0970a667f7910d6b 100644 (file)
@@ -133,21 +133,45 @@ PartSet_WidgetPoint2D::~PartSet_WidgetPoint2D()
 bool PartSet_WidgetPoint2D::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
                                          const bool theToValidate)
 {
+  bool isDone = false;
   if (theValues.empty())
-    return false;
+    return isDone;
 
   ModuleBase_ViewerPrs aValue = theValues.takeFirst();
-
-  Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
-  bool isDone = false;
   TopoDS_Shape aShape = aValue.shape();
-  double aX, aY;
-  if (getPoint2d(aView, aShape, aX, aY)) {
-    isDone = setPoint(aX, aY);
+  if (!aShape.IsNull()) {
+    Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
+    double aX, aY;
+    if (getPoint2d(aView, aShape, aX, aY)) {
+      isDone = setPoint(aX, aY);
+    }
+  }
+  else if (canBeActivatedByMove()) {
+    if (feature()->getKind() == SketchPlugin_Line::ID()) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aValue.object());
+      // Initialise new line with first point equal to end of previous
+      if (aFeature.get()) {
+        std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
+        std::shared_ptr<GeomDataAPI_Point2D> aPoint = 
+          std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+                                       aData->attribute(SketchPlugin_Line::END_ID()));
+        if (aPoint) {
+          setPoint(aPoint->x(), aPoint->y());
+          PartSet_Tools::setConstraints(mySketch, feature(), attributeID(), aPoint->x(),
+                                        aPoint->y());
+          isDone = true;
+        }
+      }
+    }
   }
   return isDone;
 }
 
+void PartSet_WidgetPoint2D::selectContent()
+{
+  myXSpin->selectAll();
+}
+
 bool PartSet_WidgetPoint2D::setPoint(double theX, double theY)
 {
   if (fabs(theX) >= MaxCoordinate)
@@ -250,6 +274,16 @@ void PartSet_WidgetPoint2D::activateCustom()
   myWorkshop->activateSubShapesSelection(aModes);
 }
 
+bool PartSet_WidgetPoint2D::canBeActivatedByMove()
+{
+  bool aCanBeActivated = false;
+  if (feature()->getKind() == SketchPlugin_Line::ID() &&
+      attributeID() == SketchPlugin_Line::START_ID())
+    aCanBeActivated = true;
+
+  return aCanBeActivated;
+}
+
 void PartSet_WidgetPoint2D::deactivate()
 {
   ModuleBase_ModelWidget::deactivate();
index eb277a88338c9db4da414c5db8a270efe3b0470a..9a54efa4b14075d1837a79361d29260632fa5008 100755 (executable)
@@ -56,12 +56,19 @@ Q_OBJECT
   virtual bool setSelection(QList<ModuleBase_ViewerPrs>& theValues,
                             const bool theToValidate);
 
+  /// Select the internal content if it can be selected. It is empty in the default realization
+  virtual void selectContent();
+
   /// Returns list of widget controls
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
 
   //bool initFromPrevious(ObjectPtr theObject);
 
+  /// Defines if the widget can be activated by mouse move.
+  /// By default it returns false
+  virtual bool canBeActivatedByMove();
+
   /// The methiod called when widget is deactivated
   virtual void deactivate();
 
@@ -96,7 +103,6 @@ public slots:
   /// \param theEvent a mouse event
   void onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent);
 
-protected slots:
   /// Process mouse release event
   /// \param theWnd a view window
   /// \param theEvent a mouse event
index 3f6c91b59e77071cb62f56cafe583d2d9e7fa763..a63344e58fda66b21299919bd574339b87b9fcad 100644 (file)
@@ -145,9 +145,15 @@ void SketchPlugin_Sketch::removeFeature(std::shared_ptr<ModelAPI_Feature> theFea
 {
   if (!data()->isValid()) // sketch is already removed (case on undo of sketch), sync is not needed
     return;
-  // to keep the persistent sub-elements indexing, do not remove elements from list,
-  // but substitute by nulls
-  reflist(SketchPlugin_Sketch::FEATURES_ID())->substitute(theFeature, ObjectPtr());
+  AttributeRefListPtr aList = reflist(SketchPlugin_Sketch::FEATURES_ID());
+  // if the object is last, remove it from the list (needed to skip empty transaction on edit of sketch feature)
+  if (aList->object(aList->size(true) - 1, true) == theFeature) {
+    aList->remove(theFeature);
+  } else {
+    // to keep the persistent sub-elements indexing, do not remove elements from list,
+    // but substitute by nulls
+    aList->substitute(theFeature, ObjectPtr());
+  }
 }
 
 int SketchPlugin_Sketch::numberOfSubs(bool forTree) const
index e169adcd5e32bcd00778fb3548f69577f0181804..4cf2001e1e28a50ae8ba778c624a1eea9f9de397 100644 (file)
@@ -17,6 +17,7 @@
 #include <ModuleBase_IViewer.h>
 #include "ModuleBase_OperationDescription.h"
 #include "ModuleBase_OperationFeature.h"
+#include "ModuleBase_Tools.h"
 
 #include "ModelAPI_CompositeFeature.h"
 #include "ModelAPI_Session.h"
@@ -25,6 +26,8 @@
 #include <QApplication>
 #include <QKeyEvent>
 
+//#define DEBUG_CURRENT_FEATURE
+
 XGUI_OperationMgr::XGUI_OperationMgr(QObject* theParent,
                                      ModuleBase_IWorkshop* theWorkshop)
 : QObject(theParent), myIsApplyEnabled(false), myWorkshop(theWorkshop)
@@ -291,7 +294,7 @@ bool XGUI_OperationMgr::isGrantedOperation(const QString& theId)
   QListIterator<ModuleBase_Operation*> anIt(myOperations);
   anIt.toBack();
   ModuleBase_Operation* aPreviousOperation = 0;
-  while (anIt.hasPrevious()) {
+  while (anIt.hasPrevious() && !isGranted) {
     ModuleBase_Operation* anOp = anIt.previous();
     if (anOp)
       isGranted = anOp->isGranted(theId);
@@ -396,9 +399,27 @@ void XGUI_OperationMgr::onBeforeOperationStarted()
     // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
     // As a result the sketch disappears from the viewer. However after commit it is displayed back.
     aFOperation->setPreviousCurrentFeature(aDoc->currentFeature(false));
+
+#ifdef DEBUG_CURRENT_FEATURE
+    FeaturePtr aFeature = aFOperation->feature();
+    QString aKind = aFeature ? aFeature->getKind().c_str() : "";
+    qDebug(QString("onBeforeOperationStarted(), edit operation = %1, feature = %2")
+            .arg(aFOperation->isEditOperation())
+            .arg(ModuleBase_Tools::objectInfo(aFeature)).toStdString().c_str());
+
+    qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
+            ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
+#endif
+
     if (aFOperation->isEditOperation()) // it should be performed by the feature edit only
       // in create operation, the current feature is changed by addFeature()
       aDoc->setCurrentFeature(aFOperation->feature(), false);
+
+#ifdef DEBUG_CURRENT_FEATURE
+    qDebug("\tdocument->setCurrentFeature");
+    qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
+            ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
+#endif
   }
 }
 
@@ -429,6 +450,16 @@ void XGUI_OperationMgr::onBeforeOperationCommitted()
   /// Restore the previous current feature
   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
   if (aFOperation) {
+#ifdef DEBUG_CURRENT_FEATURE
+    QString aKind = aFOperation->feature()->getKind().c_str();
+    qDebug(QString("onBeforeOperationCommitted(), edit operation = %1, feature = %2")
+            .arg(aFOperation->isEditOperation())
+            .arg(ModuleBase_Tools::objectInfo(aFOperation->feature())).toStdString().c_str());
+
+    qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
+            ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
+#endif
+
     if (aFOperation->isEditOperation()) {
       /// Restore the previous current feature
       setCurrentFeature(aFOperation->previousCurrentFeature());
@@ -440,6 +471,11 @@ void XGUI_OperationMgr::onBeforeOperationCommitted()
       if (myOperations.front() != aFOperation)
         setCurrentFeature(aFOperation->previousCurrentFeature());
     }
+#ifdef DEBUG_CURRENT_FEATURE
+    qDebug("\tdocument->setCurrentFeature");
+    qDebug(QString("\tdocument->currentFeature(false) = %1").arg(
+            ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str());
+#endif
   }
 }
 
@@ -503,13 +539,15 @@ bool XGUI_OperationMgr::onKeyReleased(QKeyEvent* theEvent)
       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
       ModuleBase_ModelWidget* aActiveWgt = aPanel->activeWidget();
       if (!aActiveWgt || !aActiveWgt->processEnter()) {
-        ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(currentOperation());
-        if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty()) {
-          emit keyEnterReleased();
-          commitOperation();
+        if (!myWorkshop->module()->processEnter(aActiveWgt ? aActiveWgt->attributeID() : "")) {
+          ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(currentOperation());
+          if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature(), false).isEmpty()) {
+            emit keyEnterReleased();
+            commitOperation();
+          }
+          else
+            isAccepted = false;
         }
-        else
-          isAccepted = false;
       }
     }
     break;
index f75ca242bb7db523fdb59c0a5120dc2d64077cc2..57f55e9d9c7a1becebae3622b9248a86c3768726 100755 (executable)
@@ -243,13 +243,15 @@ void XGUI_PropertyPanel::activateNextWidget()
 
 void XGUI_PropertyPanel::activateWidget(ModuleBase_ModelWidget* theWidget)
 {
+  std::string aPreviosAttributeID;
+  if(myActiveWidget)
+    aPreviosAttributeID = myActiveWidget->attributeID();
+
   // Avoid activation of already actve widget. It could happen on focusIn event many times
   if (setActiveWidget(theWidget)) {
-    if (myActiveWidget) {
-      emit widgetActivated(myActiveWidget);
-    } else if (!isEditingMode()) {
-      emit noMoreWidgets();
-      //setFocusOnOkButton();
+    emit widgetActivated(myActiveWidget);
+    if (!myActiveWidget && !isEditingMode()) {
+      emit noMoreWidgets(aPreviosAttributeID);
     }
   }
 }
@@ -260,7 +262,9 @@ bool XGUI_PropertyPanel::setActiveWidget(ModuleBase_ModelWidget* theWidget)
   if (theWidget == myActiveWidget) {
     return false;
   }
+  std::string aPreviosAttributeID;
   if(myActiveWidget) {
+    aPreviosAttributeID = myActiveWidget->attributeID();
     myActiveWidget->deactivate();
     myActiveWidget->setHighlighted(false);
   }
index c12cce271ca22096c51a5674d840d0bbcb0859b0..25ed50fd39464097d6644633235e667595e9f337 100755 (executable)
@@ -487,6 +487,7 @@ void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
 
   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
     setPropertyPanel(theOperation);
+    connectToPropertyPanel(true);
   }
   updateCommandStatus();
 
@@ -1045,7 +1046,6 @@ void XGUI_Workshop::createDockWidgets()
 
   QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
   connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation()));
-  connect(myPropertyPanel, SIGNAL(noMoreWidgets()), myModule, SLOT(onNoMoreWidgets()));
   connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)),
           myOperationMgr,  SLOT(onKeyReleased(QKeyEvent*)));
   //connect(myOperationMgr,  SIGNAL(validationStateChanged(bool)),