X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FModuleBase%2FModuleBase_OperationFeature.cpp;h=77b0956e0b1cc04d89e63a45fe1a7eb66254d21d;hb=cab05e015079888e5cd3a501e9d5b6d23facfc96;hp=a6829d1bc3a256591b7c899b1e54f5a3c7a2d34f;hpb=72604b9da2705f9030a886193ce9bb632dfda376;p=modules%2Fshaper.git diff --git a/src/ModuleBase/ModuleBase_OperationFeature.cpp b/src/ModuleBase/ModuleBase_OperationFeature.cpp old mode 100755 new mode 100644 index a6829d1bc..77b0956e0 --- a/src/ModuleBase/ModuleBase_OperationFeature.cpp +++ b/src/ModuleBase/ModuleBase_OperationFeature.cpp @@ -1,11 +1,21 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -/* - * ModuleBase_OperationFeature.cpp - * - * Created on: Apr 2, 2014 - * Author: sbh - */ +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include "ModuleBase_OperationFeature.h" @@ -15,6 +25,7 @@ #include "ModuleBase_IPropertyPanel.h" #include "ModuleBase_ISelection.h" #include "ModuleBase_IViewer.h" +#include "ModuleBase_Tools.h" #include #include @@ -26,6 +37,7 @@ #include #include #include +#include #include @@ -33,13 +45,22 @@ #include +// the define to check the activated object as a sub-feature by argument of +// the operation feature. E.g. rectangle feature(operation), line(in argument) to be not activated +#define DEBUG_DO_NOT_ACTIVATE_SUB_FEATURE +#ifdef DEBUG_DO_NOT_ACTIVATE_SUB_FEATURE +#include +#endif + +//#define DEBUG_OPERATION_START + #ifdef _DEBUG #include #endif ModuleBase_OperationFeature::ModuleBase_OperationFeature(const QString& theId, QObject* theParent) -: ModuleBase_Operation(theId, theParent), - myIsEditing(false) +: ModuleBase_Operation(theId, theParent), myIsEditing(false), myNeedToBeAborted(false), +myRestartTransactionOnResume(false) { } @@ -48,6 +69,36 @@ ModuleBase_OperationFeature::~ModuleBase_OperationFeature() clearPreselection(); } +void ModuleBase_OperationFeature::setEditOperation(const bool& isEditState + /*const bool theRestartTransaction*/) +{ + bool isCurrentEditState = isEditOperation(); + if (isCurrentEditState == isEditState) + return; + + /* + // this case is obsolete as it was not approved for reentrant sketch operation + // it was implemented when isEditState did not exist and only edit operation can be set + 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 = isEditState; + + propertyPanel()->setEditingMode(isEditOperation()); +} + FeaturePtr ModuleBase_OperationFeature::feature() const { return myFeature; @@ -59,17 +110,10 @@ bool ModuleBase_OperationFeature::isValid() const return true; // rename operation if (myFeature->isAction()) return true; - //Get validators for the Id - SessionPtr aMgr = ModelAPI_Session::get(); - ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - bool aValid = aFactory->validate(myFeature); - - // the feature exec state should be checked in order to do not apply features, which result can not - // be built. E.g. extrusion on sketch, where the "to" is a perpendicular plane to the sketch - bool isDone = ( myFeature->data()->execState() == ModelAPI_StateDone - || myFeature->data()->execState() == ModelAPI_StateMustBeUpdated ); - return aValid && isDone; + std::string anError = ModelAPI_Tools::getFeatureError(myFeature); + //ModuleBase_Tools::translate(myFeature->getKind(), anError); + return anError.empty(); } void ModuleBase_OperationFeature::startOperation() @@ -78,9 +122,13 @@ void ModuleBase_OperationFeature::startOperation() if (!aFeature.get() || !isEditOperation()) return; + if (aFeature.get() && isEditOperation()) + aFeature->setStable(false); + myVisualizedObjects.clear(); // store hidden result features - std::list aResults = aFeature->results(); + std::list aResults; + ModelAPI_Tools::allResults(aFeature, aResults); std::list::const_iterator aIt; for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { ObjectPtr anObject = *aIt; @@ -103,7 +151,8 @@ void ModuleBase_OperationFeature::stopOperation() return; // store hidden result features - std::list aResults = aFeature->results(); + std::list aResults; + ModelAPI_Tools::allResults(aFeature, aResults); std::list::const_iterator aIt; for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { ObjectPtr anObject = *aIt; @@ -114,7 +163,6 @@ void ModuleBase_OperationFeature::stopOperation() if (myVisualizedObjects.find(aFeature) != myVisualizedObjects.end()) { aFeature->setDisplayed(false); } - aFeature->setStable(true); if (myVisualizedObjects.size() > 0) Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)); } @@ -127,27 +175,12 @@ FeaturePtr ModuleBase_OperationFeature::createFeature(const bool theFlushMessage std::shared_ptr aDoc = ModelAPI_Session::get()->activeDocument(); myFeature = aDoc->addFeature(getDescription()->operationId().toStdString()); } - if (myFeature) { // TODO: generate an error if feature was not created - setIsModified(true); - // Model update should call "execute" of a feature. - //myFeature->execute(); - // Init default values - /*QList aWidgets = getDescription()->modelWidgets(); - QList::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end(); - for (; anIt != aLast; anIt++) { - (*anIt)->storeValue(aFeature); - }*/ - } - - if (theFlushMessage) - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); return myFeature; } void ModuleBase_OperationFeature::setFeature(FeaturePtr theFeature) { myFeature = theFeature; - myFeature->setStable(false); myIsEditing = true; } @@ -157,12 +190,35 @@ bool ModuleBase_OperationFeature::hasObject(ObjectPtr theObj) const if (aFeature) { if (aFeature == theObj) return true; - std::list aResults = aFeature->results(); - std::list::const_iterator aIt; - for (aIt = aResults.cbegin(); aIt != aResults.cend(); ++aIt) { - if (theObj == (*aIt)) - return true; + ResultPtr anObjRes = std::dynamic_pointer_cast(theObj); + if (anObjRes.get() && aFeature == aFeature->document()->feature(anObjRes)) { + return true; } +#ifdef DEBUG_DO_NOT_ACTIVATE_SUB_FEATURE + if (aFeature->isMacro()) { + // macro feature may refers to sub-features, + // which also should be deactivated when the operation + // is active, e.g. rectangle'lines. + FeaturePtr anObjectFeature = ModelAPI_Feature::feature(theObj); + std::list anAttributes = aFeature->data()->attributes( + ModelAPI_AttributeRefList::typeId()); + std::list::const_iterator + anIt = anAttributes.begin(), aLast = anAttributes.end(); + bool aFoundObject = false; + for (; anIt != aLast && !aFoundObject; anIt++) { + std::shared_ptr aCurSelList = + std::dynamic_pointer_cast(*anIt); + for (int i = 0, aNb = aCurSelList->size(); i < aNb && !aFoundObject; i++) { + ObjectPtr aCurObj = aCurSelList->object(i); + FeaturePtr aCurFeat = std::dynamic_pointer_cast(aCurObj); + if (aCurFeat.get()) { + aFoundObject = anObjectFeature == aCurFeat; + } + } + } + return aFoundObject; + } +#endif } return false; } @@ -172,15 +228,18 @@ bool ModuleBase_OperationFeature::isDisplayedOnStart(ObjectPtr theObject) return myVisualizedObjects.find(theObject) != myVisualizedObjects.end(); } -void ModuleBase_OperationFeature::start() +bool ModuleBase_OperationFeature::start() { - setIsModified(false); +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::start -- begin"); +#endif QString anId = getDescription()->operationId(); if (myIsEditing) { anId = anId.append(EditSuffix()); } ModelAPI_Session::get()->startOperation(anId.toStdString()); + emit beforeStarted(); startOperation(); if (!myIsEditing) { @@ -191,32 +250,28 @@ void ModuleBase_OperationFeature::start() // in order to update commands status in the workshop, to be exact the feature action // to be unchecked abort(); - return; +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::start -- end : IMPOSSIBLE to start"); +#endif + return false; } } - /// Set current feature and remeber old current feature - if (myIsEditing) { - SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aDoc = aMgr->activeDocument(); - // the parameter of current feature should be false, we should use all feature, not only visible - // in order to correctly save the previous feature of the nested operation, where the - // features can be not visible in the tree. The problem case is Edit sketch entitity(line) - // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit. - // When sketch entity operation started, the sketch should be cashed here as the current. - // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch - // 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. - myPreviousCurrentFeature = aDoc->currentFeature(false); - aDoc->setCurrentFeature(feature(), false); - } - - startOperation(); + //Already called startOperation(); emit started(); - +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::start -- end"); +#endif + return true; } void ModuleBase_OperationFeature::abort() { +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::abort -- begin"); +#endif + + emit beforeAborted(); + // the viewer update should be blocked in order to avoid the features blinking before they are // hidden std::shared_ptr aMsg = std::shared_ptr( @@ -232,21 +287,13 @@ void ModuleBase_OperationFeature::abort() if (aPropertyPanel) aPropertyPanel->cleanContent(); - SessionPtr aMgr = ModelAPI_Session::get(); - if (myIsEditing) { - DocumentPtr aDoc = aMgr->activeDocument(); - bool aIsOp = aMgr->isOperation(); - if (!aIsOp) - aMgr->startOperation(); - aDoc->setCurrentFeature(myPreviousCurrentFeature, true); - if (!aIsOp) - aMgr->finishOperation(); - myPreviousCurrentFeature = FeaturePtr(); - } - abortOperation(); + if (myFeature.get()) + myFeature->setStable(true); + abortOperation(); stopOperation(); + SessionPtr aMgr = ModelAPI_Session::get(); aMgr->abortOperation(); emit stopped(); // the viewer update should be unblocked in order to avoid the features blinking before they are @@ -257,11 +304,26 @@ void ModuleBase_OperationFeature::abort() Events_Loop::loop()->send(aMsg); emit aborted(); +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::abort -- end"); +#endif } bool ModuleBase_OperationFeature::commit() { +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::commit -- begin"); +#endif + ModuleBase_IPropertyPanel* aPanel = propertyPanel(); + if (aPanel) { + ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget(); + if (anActiveWidget && anActiveWidget->getValueState() == ModuleBase_ModelWidget::ModifiedInPP) { + anActiveWidget->storeValue(); + } + aPanel->onAcceptData(); + } 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 @@ -271,75 +333,88 @@ bool ModuleBase_OperationFeature::commit() if (aPropertyPanel) aPropertyPanel->cleanContent(); - SessionPtr aMgr = ModelAPI_Session::get(); - /// Set current feature and remeber old current feature - if (myIsEditing) { - DocumentPtr aDoc = aMgr->activeDocument(); - bool aIsOp = aMgr->isOperation(); - if (!aIsOp) - aMgr->startOperation(); - aDoc->setCurrentFeature(myPreviousCurrentFeature, true); - if (!aIsOp) - aMgr->finishOperation(); - myPreviousCurrentFeature = FeaturePtr(); - } + myFeature->setStable(true); + commitOperation(); - aMgr->finishOperation(); stopOperation(); + + SessionPtr aMgr = ModelAPI_Session::get(); + aMgr->finishOperation(); + // Finish operation has to be before stopped because stopped caused update of Object browser + // If it will be done before of cleaning of obsolete objects it will cause crash emit stopped(); emit committed(); afterCommitOperation(); +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::commit -- end"); +#endif return true; } +#ifdef DEBUG_OPERATION_START + qDebug("ModuleBase_OperationFeature::commit -- end : IMPOSSIBLE to commit"); +#endif return false; } -void ModuleBase_OperationFeature::activateByPreselection() +ModuleBase_ModelWidget* ModuleBase_OperationFeature::activateByPreselection( + const std::string& theGreedAttributeId) { + ModuleBase_ModelWidget* aWidget = 0; if (myPreSelection.empty()) - return; + return aWidget; - ModuleBase_ModelWidget* aFilledWgt = 0; ModuleBase_IPropertyPanel* aPropertyPanel = propertyPanel(); + ModuleBase_ModelWidget* aFilledWgt = 0; if (aPropertyPanel) { const QList& aWidgets = aPropertyPanel->modelWidgets(); + QList::const_iterator aWIt; + ModuleBase_ModelWidget* aWgt = 0; if (!aWidgets.empty()) { - ModuleBase_ModelWidget* aWgt = 0; - QList::const_iterator aWIt; - bool isSet = false; - // 1. apply the selection to controls - for (aWIt = aWidgets.constBegin(); aWIt != aWidgets.constEnd(); ++aWIt) { - aWgt = (*aWIt); - if (!aWgt->canSetValue()) - continue; - aPropertyPanel->setPreselectionWidget(aWgt); - if (!aWgt->setSelection(myPreSelection, true)) { - isSet = false; - break; - } else { - isSet = true; - aFilledWgt = aWgt; + // equal vertices should not be used here + ModuleBase_ISelection::filterSelectionOnEqualPoints(myPreSelection); + + if (!theGreedAttributeId.empty()) { + // set preselection to greed widget + for (aWIt = aWidgets.constBegin(); aWIt != aWidgets.constEnd(); ++aWIt) { + aWgt = (*aWIt); + if (aWgt->attributeID() == theGreedAttributeId) { + aPropertyPanel->setPreselectionWidget(aWgt); + if (aWgt->setSelection(myPreSelection, true)) { + aPropertyPanel->setPreselectionWidget(NULL); + aFilledWgt = aWgt; + break; + } + else { // do not process invalid for greed widget selection + break; + } + } + } + } + else { + // 1. apply the selection to controls + for (aWIt = aWidgets.constBegin(); aWIt != aWidgets.constEnd(); ++aWIt) { + aWgt = (*aWIt); + if (!aWgt->canAcceptFocus()) + continue; + aPropertyPanel->setPreselectionWidget(aWgt); + if (myPreSelection.empty() || !aWgt->setSelection(myPreSelection, true)) + break; + else + aFilledWgt = aWgt; } } aPropertyPanel->setPreselectionWidget(NULL); // in order to redisplay object in the viewer, the update/redisplay signals should be flushed // it is better to perform it not in setSelection of each widget, but do it here, // after the preselection is processed - ModuleBase_ModelWidget::updateObject(myFeature); - - // 3. a signal should be emitted before the next widget activation - // because, the activation of the next widget will give a focus to the widget. As a result - // the value of the widget is initialized. And commit may happens until the value is entered. - if (aFilledWgt) - emit activatedByPreselection(); + ModuleBase_Tools::flushUpdated(myFeature); } - // 4. activate the next obligatory widget - aPropertyPanel->activateNextWidget(aFilledWgt); } - clearPreselection(); + + return aFilledWgt; } void ModuleBase_OperationFeature::setParentFeature(CompositeFeaturePtr theParent) @@ -352,31 +427,47 @@ CompositeFeaturePtr ModuleBase_OperationFeature::parentFeature() const return myParentFeature; } -void ModuleBase_OperationFeature::initSelection(ModuleBase_ISelection* theSelection, - ModuleBase_IViewer* theViewer) +void ModuleBase_OperationFeature::setPreviousCurrentFeature(const FeaturePtr& theFeature) { - clearPreselection(); + myPreviousCurrentFeature = theFeature; +} + +FeaturePtr ModuleBase_OperationFeature::previousCurrentFeature() +{ + return myPreviousCurrentFeature; +} + +void ModuleBase_OperationFeature::initSelection( + const QList& thePreSelected) +{ + QObjectPtrList aCurrentFeatureResults; - QList aPreSelected; // Check that the selected result are not results of operation feature FeaturePtr aFeature = feature(); if (aFeature) { - QList aSelected = theSelection->getSelected(ModuleBase_ISelection::AllControls); - - std::list aResults = aFeature->results(); - QObjectPtrList aResList; + std::list aResults; + ModelAPI_Tools::allResults(aFeature, aResults); std::list::const_iterator aIt; for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) - aResList.append(*aIt); + aCurrentFeatureResults.append(*aIt); + } - foreach (ModuleBase_ViewerPrs aPrs, aSelected) { - if ((!aResList.contains(aPrs.object())) && (aPrs.object() != aFeature)) + if (aCurrentFeatureResults.empty()) /// filtering of selection is not necessary + setPreselection(thePreSelected); + else { // create preselection list without results of current feature + QList aPreSelected; + foreach (ModuleBase_ViewerPrsPtr aPrs, thePreSelected) { + if ((!aCurrentFeatureResults.contains(aPrs->object())) && (aPrs->object() != aFeature)) aPreSelected.append(aPrs); } - } else - aPreSelected = theSelection->getSelected(ModuleBase_ISelection::AllControls); + setPreselection(aPreSelected); + } +} - myPreSelection = aPreSelected; +void ModuleBase_OperationFeature::setPreselection(const QList& theValues) +{ + clearPreselection(); + myPreSelection = theValues; } void ModuleBase_OperationFeature::clearPreselection() @@ -384,7 +475,7 @@ void ModuleBase_OperationFeature::clearPreselection() myPreSelection.clear(); } -void ModuleBase_OperationFeature::setPropertyPanel(ModuleBase_IPropertyPanel* theProp) +void ModuleBase_OperationFeature::setPropertyPanel(ModuleBase_IPropertyPanel* theProp) { ModuleBase_Operation::setPropertyPanel(theProp); @@ -396,11 +487,12 @@ void ModuleBase_OperationFeature::setPropertyPanel(ModuleBase_IPropertyPanel* th for (aWIt = aWidgets.constBegin(); aWIt != aWidgets.constEnd(); ++aWIt) { ModuleBase_ModelWidget* aWgt = (*aWIt); connect(aWgt, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged())); + connect(aWgt, SIGNAL(valueStateChanged(int)), this, SLOT(onValueStateChanged(int))); } } // Do not activate widgets by default if the current operation is editing operation - // Because we don't know which widget is going to be edited. + // Because we don't know which widget is going to be edited. if (!isEditOperation()) { // 4. activate the first obligatory widget theProp->activateNextWidget(NULL); @@ -411,3 +503,11 @@ void ModuleBase_OperationFeature::setPropertyPanel(ModuleBase_IPropertyPanel* th theProp->setFocusOnOkButton(); } } + +void ModuleBase_OperationFeature::resumeOperation() +{ + if (myRestartTransactionOnResume) { + ModelAPI_Session::get()->startOperation(this->id().toStdString(), true); + myRestartTransactionOnResume = false; + } +}