From: nds Date: Mon, 9 Nov 2015 11:34:57 +0000 (+0300) Subject: Merge remote-tracking branch 'origin/BR_REENTRANCE_OPERATION' into origin_Dev_1.5.0 X-Git-Tag: V_2.0.0_alfa1~6 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=42985955d89fa845790a7e38609f5b6838285147;hp=ef7a793f109f7507b0f48e12bf72d943c5d22487;p=modules%2Fshaper.git Merge remote-tracking branch 'origin/BR_REENTRANCE_OPERATION' into origin_Dev_1.5.0 Conflicts: src/Model/Model_Document.cpp --- diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp old mode 100644 new mode 100755 index ecd12cf45..e3ff4e04c --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -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; diff --git a/src/ModuleBase/ModuleBase_FilterValidated.cpp b/src/ModuleBase/ModuleBase_FilterValidated.cpp index 88f16c6d8..08314d734 100644 --- a/src/ModuleBase/ModuleBase_FilterValidated.cpp +++ b/src/ModuleBase/ModuleBase_FilterValidated.cpp @@ -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 (aCurrentWidget); ModuleBase_ViewerPrs aPrs; diff --git a/src/ModuleBase/ModuleBase_IModule.cpp b/src/ModuleBase/ModuleBase_IModule.cpp index 3cbe89b5b..29e89f3ef 100644 --- a/src/ModuleBase/ModuleBase_IModule.cpp +++ b/src/ModuleBase/ModuleBase_IModule.cpp @@ -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()) diff --git a/src/ModuleBase/ModuleBase_IModule.h b/src/ModuleBase/ModuleBase_IModule.h index f4d547d43..de02c0dfe 100755 --- a/src/ModuleBase/ModuleBase_IModule.h +++ b/src/ModuleBase/ModuleBase_IModule.h @@ -101,6 +101,9 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject return 0; } + /// Returns the active widget, by default it is the property panel active widget + virtual ModuleBase_ModelWidget* activeWidget() const = 0; + /// Returns current workshop ModuleBase_IWorkshop* workshop() const { return myWorkshop; } @@ -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 //! 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; @@ -200,6 +203,10 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// \param thePreviousState the previous state of the widget virtual void widgetStateChanged(int thePreviousState) {}; + /// Returns true if the event is processed. + /// \param thePreviousAttributeID an index of the previous active attribute + virtual bool processEnter(const std::string& thePreviousAttributeID) { return false; }; + signals: /// Signal which is emitted when operation is launched void operationLaunched(); diff --git a/src/ModuleBase/ModuleBase_IPropertyPanel.cpp b/src/ModuleBase/ModuleBase_IPropertyPanel.cpp index ee4490aca..0a87a74c8 100644 --- a/src/ModuleBase/ModuleBase_IPropertyPanel.cpp +++ b/src/ModuleBase/ModuleBase_IPropertyPanel.cpp @@ -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& theWidgets) +{ + ModuleBase_ModelWidget* aFirstWidget = 0; + + ModuleBase_ModelWidget* aWgt; + QList::const_iterator aWIt; + for (aWIt = theWidgets.begin(); aWIt != theWidgets.end() && !aFirstWidget; ++aWIt) { + aWgt = (*aWIt); + if (aWgt->canSetValue()) + aFirstWidget = aWgt; + } + return aFirstWidget; +} diff --git a/src/ModuleBase/ModuleBase_IPropertyPanel.h b/src/ModuleBase/ModuleBase_IPropertyPanel.h index c8c0f1721..afafce7a7 100644 --- a/src/ModuleBase/ModuleBase_IPropertyPanel.h +++ b/src/ModuleBase/ModuleBase_IPropertyPanel.h @@ -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& 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 diff --git a/src/ModuleBase/ModuleBase_ModelWidget.h b/src/ModuleBase/ModuleBase_ModelWidget.h index dd2c9edd3..6e6b1aac4 100644 --- a/src/ModuleBase/ModuleBase_ModelWidget.h +++ b/src/ModuleBase/ModuleBase_ModelWidget.h @@ -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(); diff --git a/src/ModuleBase/ModuleBase_OperationFeature.cpp b/src/ModuleBase/ModuleBase_OperationFeature.cpp index ca34bc942..da5ff1fcb 100755 --- a/src/ModuleBase/ModuleBase_OperationFeature.cpp +++ b/src/ModuleBase/ModuleBase_OperationFeature.cpp @@ -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(); diff --git a/src/ModuleBase/ModuleBase_OperationFeature.h b/src/ModuleBase/ModuleBase_OperationFeature.h index 11de99701..32e648bd9 100755 --- a/src/ModuleBase/ModuleBase_OperationFeature.h +++ b/src/ModuleBase/ModuleBase_OperationFeature.h @@ -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; diff --git a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp index 4e6ce242c..a43f02cb6 100644 --- a/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp +++ b/src/ModuleBase/ModuleBase_WidgetDoubleValue.cpp @@ -144,6 +144,11 @@ bool ModuleBase_WidgetDoubleValue::restoreValueCustom() return true; } +void ModuleBase_WidgetDoubleValue::selectContent() +{ + mySpinBox->selectAll(); +} + QList ModuleBase_WidgetDoubleValue::getControls() const { QList aList; diff --git a/src/ModuleBase/ModuleBase_WidgetDoubleValue.h b/src/ModuleBase/ModuleBase_WidgetDoubleValue.h index 8c1e0a1d8..cfd49221c 100644 --- a/src/ModuleBase/ModuleBase_WidgetDoubleValue.h +++ b/src/ModuleBase/ModuleBase_WidgetDoubleValue.h @@ -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 getControls() const; diff --git a/src/ModuleBase/ModuleBase_WidgetEditor.h b/src/ModuleBase/ModuleBase_WidgetEditor.h index f63ec0bca..5f26a60cc 100644 --- a/src/ModuleBase/ModuleBase_WidgetEditor.h +++ b/src/ModuleBase/ModuleBase_WidgetEditor.h @@ -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(); diff --git a/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp b/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp index af676208c..cadef7521 100755 --- a/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp +++ b/src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp @@ -304,8 +304,7 @@ QList ModuleBase_WidgetMultiSelector::getControls() const //******************************************************************** void ModuleBase_WidgetMultiSelector::onSelectionTypeChanged() { - activateSelection(true); - activateFilters(true); + activateSelectionAndFilters(true); QList 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; } } diff --git a/src/ModuleBase/ModuleBase_WidgetSelector.cpp b/src/ModuleBase/ModuleBase_WidgetSelector.cpp index 061635320..99edfb890 100755 --- a/src/ModuleBase/ModuleBase_WidgetSelector.cpp +++ b/src/ModuleBase/ModuleBase_WidgetSelector.cpp @@ -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(); } diff --git a/src/ModuleBase/ModuleBase_WidgetSelector.h b/src/ModuleBase/ModuleBase_WidgetSelector.h index 0deb253bd..cb7d76e42 100755 --- a/src/ModuleBase/ModuleBase_WidgetSelector.h +++ b/src/ModuleBase/ModuleBase_WidgetSelector.h @@ -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(); diff --git a/src/ModuleBase/ModuleBase_WidgetValidated.h b/src/ModuleBase/ModuleBase_WidgetValidated.h index f1a5ef17e..385f11a00 100644 --- a/src/ModuleBase/ModuleBase_WidgetValidated.h +++ b/src/ModuleBase/ModuleBase_WidgetValidated.h @@ -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& 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; diff --git a/src/PartSet/CMakeLists.txt b/src/PartSet/CMakeLists.txt index 31ba5f79e..03f142b91 100644 --- a/src/PartSet/CMakeLists.txt +++ b/src/PartSet/CMakeLists.txt @@ -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 diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 34c838a74..abf7f605f 100755 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -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" @@ -62,10 +63,6 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -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(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(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(workshop()); - XGUI_Workshop* aWorkshop = aConnector->workshop(); - aWorkshop->selector()->clearSelection(); - /// Restart sketcher operations automatically - FeaturePtr aFeature = aFOperation->feature(); - std::shared_ptr aSPFeature = - std::dynamic_pointer_cast(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(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& 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(aWgt); - if (aPnt2dWgt) { - std::shared_ptr aData = myLastFeature->data(); - std::shared_ptr aPoint = - std::dynamic_pointer_cast(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(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& aWidgets = aPanel->modelWidgets(); - QList::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 - (anActiveWidget); - if (aWidgetValidated) - aWidgetValidated->activateFilters(true); + ModuleBase_WidgetSelector* aWSelector = dynamic_cast(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); +} diff --git a/src/PartSet/PartSet_Module.h b/src/PartSet/PartSet_Module.h index 5ff0b77df..26f7ace34 100755 --- a/src/PartSet/PartSet_Module.h +++ b/src/PartSet/PartSet_Module.h @@ -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; diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index 97a5ce43c..ac3eaf7f9 100755 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -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 #include @@ -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(aWgt); + if (anEditor) + anEditor->showPopupEditor(); return; } } @@ -582,10 +595,17 @@ void PartSet_SketcherMgr::onApplicationStarted() ModuleBase_IWorkshop* anIWorkshop = myModule->workshop(); XGUI_ModuleConnector* aConnector = dynamic_cast(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(); } diff --git a/src/PartSet/PartSet_SketcherMgr.h b/src/PartSet/PartSet_SketcherMgr.h index 38981450b..b7e7ffd6e 100644 --- a/src/PartSet/PartSet_SketcherMgr.h +++ b/src/PartSet/PartSet_SketcherMgr.h @@ -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 index 000000000..abde2a78b --- /dev/null +++ b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +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(module()->activeWidget()); + if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (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(aPanel->activeWidget()); + if (aPoint2DWdg && aPoint2DWdg->canBeActivatedByMove()) { + QList 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(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(aFirstWidget); + if (aWSelector) + aWSelector->activateSelectionAndFilters(true); + } +} + +void PartSet_SketcherReetntrantMgr::onNoMoreWidgets(const std::string& thePreviousAttributeID) +{ + if (!isActiveMgr()) + return; + + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (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 + (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& aWidgets = aPanel->modelWidgets(); + QList::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 + (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 + (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 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 + (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( + myWorkshop->currentOperation()); + if (aFOperation) { + myIsFlagsBlocked = true; + aFOperation->commit(); + module()->launchOperation(aFOperation->id()); + myIsFlagsBlocked = false; + resetFlags(); + } + } +} + +void PartSet_SketcherReetntrantMgr::createInternalFeature() +{ + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (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 + (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 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(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(myWorkshop); + return aConnector->workshop(); +} + +PartSet_Module* PartSet_SketcherReetntrantMgr::module() const +{ + return dynamic_cast(myWorkshop->module()); +} + diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.h b/src/PartSet/PartSet_SketcherReetntrantMgr.h new file mode 100755 index 000000000..2d76dd637 --- /dev/null +++ b/src/PartSet/PartSet_SketcherReetntrantMgr.h @@ -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 + +#include + +#include + +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 diff --git a/src/PartSet/PartSet_Validators.cpp b/src/PartSet/PartSet_Validators.cpp index a53eb3596..9b4aa471d 100755 --- a/src/PartSet/PartSet_Validators.cpp +++ b/src/PartSet/PartSet_Validators.cpp @@ -7,6 +7,7 @@ #include "PartSet_Validators.h" #include "PartSet_Tools.h" +#include "PartSet_SketcherMgr.h" #include #include @@ -92,14 +93,21 @@ std::shared_ptr sketcherPlane(ModuleBase_Operation* theOperation) bool isEmptySelectionValid(ModuleBase_Operation* theOperation) { ModuleBase_OperationFeature* aFeatureOp = dynamic_cast(theOperation); + // during the create operation empty selection is always valid if (!aFeatureOp->isEditOperation()) { return true; } - std::shared_ptr aPlane = sketcherPlane(theOperation); - if (aPlane.get()) - return true; - else - return false; + else { + if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) { + std::shared_ptr 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 diff --git a/src/PartSet/PartSet_WidgetEditor.cpp b/src/PartSet/PartSet_WidgetEditor.cpp index 4857863b5..d0a129aba 100644 --- a/src/PartSet/PartSet_WidgetEditor.cpp +++ b/src/PartSet/PartSet_WidgetEditor.cpp @@ -23,7 +23,7 @@ PartSet_WidgetEditor::PartSet_WidgetEditor(QWidget* theParent, ModuleBase_IWorks bool PartSet_WidgetEditor::focusTo() { PartSet_Module* aModule = dynamic_cast(myWorkshop->module()); - if (aModule->isMouseOverWindow()) + if (aModule->isMouseOverWindow() && !isEditingMode()) return ModuleBase_WidgetEditor::focusTo(); else { return ModuleBase_WidgetDoubleValue::focusTo(); diff --git a/src/PartSet/PartSet_WidgetPoint2d.cpp b/src/PartSet/PartSet_WidgetPoint2d.cpp index 8d9f07d31..ebfe32e00 100644 --- a/src/PartSet/PartSet_WidgetPoint2d.cpp +++ b/src/PartSet/PartSet_WidgetPoint2d.cpp @@ -133,21 +133,45 @@ PartSet_WidgetPoint2D::~PartSet_WidgetPoint2D() bool PartSet_WidgetPoint2D::setSelection(QList& 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(aValue.object()); + // Initialise new line with first point equal to end of previous + if (aFeature.get()) { + std::shared_ptr aData = aFeature->data(); + std::shared_ptr aPoint = + std::dynamic_pointer_cast( + 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(); diff --git a/src/PartSet/PartSet_WidgetPoint2d.h b/src/PartSet/PartSet_WidgetPoint2d.h index eb277a883..9a54efa4b 100755 --- a/src/PartSet/PartSet_WidgetPoint2d.h +++ b/src/PartSet/PartSet_WidgetPoint2d.h @@ -56,12 +56,19 @@ Q_OBJECT virtual bool setSelection(QList& 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 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 diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 3f6c91b59..a63344e58 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -145,9 +145,15 @@ void SketchPlugin_Sketch::removeFeature(std::shared_ptr 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 diff --git a/src/XGUI/XGUI_OperationMgr.cpp b/src/XGUI/XGUI_OperationMgr.cpp index e169adcd5..4cf2001e1 100644 --- a/src/XGUI/XGUI_OperationMgr.cpp +++ b/src/XGUI/XGUI_OperationMgr.cpp @@ -17,6 +17,7 @@ #include #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 #include +//#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 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(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(currentOperation()); - if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature()).isEmpty()) { - emit keyEnterReleased(); - commitOperation(); + if (!myWorkshop->module()->processEnter(aActiveWgt ? aActiveWgt->attributeID() : "")) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast(currentOperation()); + if (!aFOperation || myWorkshop->module()->getFeatureError(aFOperation->feature(), false).isEmpty()) { + emit keyEnterReleased(); + commitOperation(); + } + else + isAccepted = false; } - else - isAccepted = false; } } break; diff --git a/src/XGUI/XGUI_PropertyPanel.cpp b/src/XGUI/XGUI_PropertyPanel.cpp index f75ca242b..57f55e9d9 100755 --- a/src/XGUI/XGUI_PropertyPanel.cpp +++ b/src/XGUI/XGUI_PropertyPanel.cpp @@ -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); } diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index c12cce271..25ed50fd3 100755 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -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)),