From 318198d7b52d6e046d85eeb838cf5a7247703786 Mon Sep 17 00:00:00 2001 From: spo Date: Thu, 17 Sep 2015 08:52:19 +0300 Subject: [PATCH] Issue #818 - Deletion of a parameter used in a feature -- Replace parameters --- src/ModelAPI/ModelAPI_Events.cpp | 31 +++++ src/ModelAPI/ModelAPI_Events.h | 29 +++++ .../ParametersPlugin_EvalListener.cpp | 119 +++++++++++++----- .../ParametersPlugin_EvalListener.h | 4 + src/XGUI/XGUI_Workshop.cpp | 79 ++++++++---- 5 files changed, 207 insertions(+), 55 deletions(-) diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index 85c6c02b7..278867e0a 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -195,3 +195,34 @@ void ModelAPI_ObjectRenamedMessage::setNewName(const std::string& theNewName) { myNewName = theNewName; } + +ModelAPI_ReplaceParameterMessage::ModelAPI_ReplaceParameterMessage(const Events_ID theID, + const void* theSender) +: Events_Message(theID, theSender) +{ + +} + +ModelAPI_ReplaceParameterMessage::~ModelAPI_ReplaceParameterMessage() +{ + +} + +void ModelAPI_ReplaceParameterMessage::send(ObjectPtr theObject, + const void* theSender) +{ + std::shared_ptr aMessage( + new ModelAPI_ReplaceParameterMessage(eventId(), theSender)); + aMessage->setObject(theObject); + Events_Loop::loop()->send(aMessage); +} + +ObjectPtr ModelAPI_ReplaceParameterMessage::object() const +{ + return myObject; +} + +void ModelAPI_ReplaceParameterMessage::setObject(ObjectPtr theObject) +{ + myObject = theObject; +} diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index 4ba952cf5..45349a52c 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -273,4 +273,33 @@ class ModelAPI_ObjectRenamedMessage : public Events_Message MODELAPI_EXPORT void setNewName(const std::string& theNewName); }; +/// Message that the parameter should be replaced with its value +class ModelAPI_ReplaceParameterMessage : public Events_Message +{ + ObjectPtr myObject; + + public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char * MY_EVENT_ID("ReplaceParameter"); + static Events_ID anId = Events_Loop::eventByName(MY_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the AttributeEvalMessage event + MODELAPI_EXPORT static void send(ObjectPtr theObject, + const void* theSender); + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ReplaceParameterMessage(const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ReplaceParameterMessage(); + + /// Returns an object + MODELAPI_EXPORT ObjectPtr object() const; + /// Sets an object + MODELAPI_EXPORT void setObject(ObjectPtr theObject); +}; + #endif diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp index 029800afa..8b5e915ee 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp @@ -29,13 +29,35 @@ #include #include +//------------------------------------------------------------------------------ +// Tools + +std::string toStdString(double theValue) +{ + std::ostringstream sstream; + sstream << theValue; + return sstream.str(); +} + +std::set toSet(const std::list& theContainer) +{ + return std::set(theContainer.begin(), theContainer.end()); +} + +//------------------------------------------------------------------------------ + ParametersPlugin_EvalListener::ParametersPlugin_EvalListener() { Events_Loop* aLoop = Events_Loop::loop(); - const Events_ID kEvaluationEvent = ModelAPI_AttributeEvalMessage::eventId(); - aLoop->registerListener(this, kEvaluationEvent, NULL, true); - const Events_ID kObjectRenamedEvent = ModelAPI_ObjectRenamedMessage::eventId(); - aLoop->registerListener(this, kObjectRenamedEvent, NULL, true); + + Events_ID anEvents_IDs[] = { + ModelAPI_AttributeEvalMessage::eventId(), + ModelAPI_ObjectRenamedMessage::eventId(), + ModelAPI_ReplaceParameterMessage::eventId() + }; + + for (int i = 0; i < sizeof(anEvents_IDs)/sizeof(anEvents_IDs[0]); ++i) + aLoop->registerListener(this, anEvents_IDs[i], NULL, true); myInterp = std::shared_ptr(new ParametersPlugin_PyInterp()); myInterp->initialize(); @@ -53,10 +75,14 @@ void ParametersPlugin_EvalListener::processEvent( const Events_ID kEvaluationEvent = ModelAPI_AttributeEvalMessage::eventId(); const Events_ID kObjectRenamedEvent = ModelAPI_ObjectRenamedMessage::eventId(); + const Events_ID kReplaceParameterEvent = ModelAPI_ReplaceParameterMessage::eventId(); + if (theMessage->eventID() == kEvaluationEvent) { processEvaluationEvent(theMessage); } else if (theMessage->eventID() == kObjectRenamedEvent) { processObjectRenamedEvent(theMessage); + } else if (theMessage->eventID() == kReplaceParameterEvent) { + processReplaceParameterEvent(theMessage); } else { Events_Error::send(std::string("ParametersPlugin python interpreter, unhandled message caught: ") + theMessage->eventID().eventText()); @@ -76,10 +102,7 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression, // If variable does not exist python interpreter will generate an error. It is OK. if (!ModelAPI_Tools::findVariable(*it, aValue, aParamRes, theDocument)) continue; - std::ostringstream sstream; - sstream << aValue; - std::string aParamValue = sstream.str(); - aContext.push_back(*it + "=" + aParamValue); + aContext.push_back(*it + "=" + toStdString(aValue)); } myInterp->extendLocalContext(aContext); double result = myInterp->evaluate(theExpression, theError); @@ -87,11 +110,6 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression, return result; } -std::set toSet(const std::list& theContainer) -{ - return std::set(theContainer.begin(), theContainer.end()); -} - void ParametersPlugin_EvalListener::processEvaluationEvent( const std::shared_ptr& theMessage) { @@ -261,6 +279,37 @@ void ParametersPlugin_EvalListener::renameInAttribute( } } +void ParametersPlugin_EvalListener::renameInDependants(std::shared_ptr theResultParameter, + const std::string& theNewName) +{ + // get parameter feature for the result + std::shared_ptr aParameter = + std::dynamic_pointer_cast( + ModelAPI_Feature::feature(theResultParameter)); + if (!aParameter.get()) + return; + + std::string anOldName = aParameter->string(ParametersPlugin_Parameter::VARIABLE_ID())->value(); + + std::set > anAttributes = + theResultParameter->data()->refsToMe(); + std::set >::const_iterator anAttributeIt = + anAttributes.cbegin(); + for (; anAttributeIt != anAttributes.cend(); ++anAttributeIt) { + const AttributePtr& anAttribute = *anAttributeIt; + if (anAttribute->attributeType() == ModelAPI_AttributeRefList::typeId()) { + std::shared_ptr aParameter = + std::dynamic_pointer_cast( + anAttribute->owner()); + if (aParameter.get()) + // Rename + renameInParameter(aParameter, anOldName, theNewName); + } else + // Rename + renameInAttribute(anAttribute, anOldName, theNewName); + } +} + bool isValidAttribute(const AttributePtr& theAttribute) { std::string aValidator, anError; @@ -317,24 +366,30 @@ void ParametersPlugin_EvalListener::processObjectRenamedEvent( return; } - std::set > anAttributes = - aResultParameter->data()->refsToMe(); - std::set >::const_iterator anAttributeIt = - anAttributes.cbegin(); - for (; anAttributeIt != anAttributes.cend(); ++anAttributeIt) { - const AttributePtr& anAttribute = *anAttributeIt; - AttributeRefListPtr anAttributeRefList = - std::dynamic_pointer_cast(anAttribute); - if (anAttributeRefList.get()) { - std::shared_ptr aParameter = - std::dynamic_pointer_cast( - anAttributeRefList->owner()); - if (aParameter.get()) - // Rename - renameInParameter(aParameter, aMessage->oldName(), aMessage->newName()); - } else - // Rename - renameInAttribute(anAttribute, aMessage->oldName(), aMessage->newName()); - } + renameInDependants(aResultParameter, aMessage->newName()); } +void ParametersPlugin_EvalListener::processReplaceParameterEvent( + const std::shared_ptr& theMessage) +{ + std::shared_ptr aMessage = + std::dynamic_pointer_cast(theMessage); + + // get parameter feature for the object + std::shared_ptr aParameter = + std::dynamic_pointer_cast( + ModelAPI_Feature::feature(aMessage->object())); + if (!aParameter.get()) + return; + + ResultParameterPtr aResultParameter = + std::dynamic_pointer_cast( + aParameter->firstResult()); + if (!aResultParameter.get()) + return; + + double aRealValue = aResultParameter->data()->real(ModelAPI_ResultParameter::VALUE())->value(); + std::string aValue = toStdString(aRealValue); + + renameInDependants(aResultParameter, aValue); +} diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.h b/src/ParametersPlugin/ParametersPlugin_EvalListener.h index 02b5e6c52..56bb88dd4 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.h +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.h @@ -13,6 +13,7 @@ class ModelAPI_Attribute; class ModelAPI_Document; +class ModelAPI_ResultParameter; class ParametersPlugin_Parameter; class ParametersPlugin_PyInterp; @@ -30,6 +31,7 @@ class ParametersPlugin_EvalListener : public Events_Listener void processEvaluationEvent(const std::shared_ptr& theMessage); void processObjectRenamedEvent(const std::shared_ptr& theMessage); + void processReplaceParameterEvent(const std::shared_ptr& theMessage); std::string renameInPythonExpression(const std::string& theExpression, const std::string& theOldName, @@ -40,6 +42,8 @@ class ParametersPlugin_EvalListener : public Events_Listener void renameInAttribute(std::shared_ptr theAttribute, const std::string& theOldName, const std::string& theNewName); + void renameInDependants(std::shared_ptr theResultParameter, + const std::string& theNewName); private: std::shared_ptr myInterp; diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 5d0e12c5d..4638e3890 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -1218,50 +1218,83 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, std::inserter(aDifference, aDifference.begin())); aIndirectRefFeatures = aDifference; } + + bool doDeleteReferences = true; + // 2. warn about the references remove, break the delete operation if the user chose it if (theAskAboutDeleteReferences && !aDirectRefFeatures.empty()) { QStringList aDirectRefNames; - foreach(const FeaturePtr& aFeature, aDirectRefFeatures) + foreach (const FeaturePtr& aFeature, aDirectRefFeatures) aDirectRefNames.append(aFeature->name().c_str()); QString aDirectNames = aDirectRefNames.join(", "); QStringList aIndirectRefNames; - foreach(const FeaturePtr& aFeature, aIndirectRefFeatures) + foreach (const FeaturePtr& aFeature, aIndirectRefFeatures) aIndirectRefNames.append(aFeature->name().c_str()); QString aIndirectNames = aIndirectRefNames.join(", "); - QMessageBox::StandardButton aRes = QMessageBox::warning( - theParent, tr("Delete features"), - QString(tr("Selected features are used in the following features: %1.\ - These features will be deleted.\n%2Would you like to continue?")).arg(aDirectNames) - .arg(aIndirectNames.isEmpty() ? QString() : QString("Also these features will be deleted: %1.\n").arg(aIndirectNames)), - QMessageBox::No | QMessageBox::Yes, QMessageBox::No); - if (aRes != QMessageBox::Yes) + bool canReplaceParameters = true; + foreach (ObjectPtr aObj, theList) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); + if (aFeature->getKind() != "Parameter") { + canReplaceParameters = false; + break; + } + } + + QMessageBox aMessageBox(theParent); + aMessageBox.setWindowTitle(tr("Delete features")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + QString aText; + if (canReplaceParameters) { + aText = QString(tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\n%2Or parameters could be replaced with its values.\nWould you like to continue?")) + .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames)); + QPushButton *aReplaceButton = aMessageBox.addButton(tr("Replace"), QMessageBox::ActionRole); + } else { + aText = QString(tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n%2Would you like to continue?")) + .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("Also these features will be deleted: %1.\n")).arg(aIndirectNames)); + } + aMessageBox.setText(aText); + aMessageBox.exec(); + QMessageBox::ButtonRole aButtonRole = aMessageBox.buttonRole(aMessageBox.clickedButton()); + + if (aButtonRole == QMessageBox::NoRole) return false; + + if (aButtonRole == QMessageBox::ActionRole) { + foreach (ObjectPtr aObj, theList) + ModelAPI_ReplaceParameterMessage::send(aObj, this); + doDeleteReferences = false; + } } // 3. remove referenced features - std::set aFeaturesToDelete = aDirectRefFeatures; - aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); - std::set::const_iterator anIt = aFeaturesToDelete.begin(), - aLast = aFeaturesToDelete.end(); + if (doDeleteReferences) { + std::set aFeaturesToDelete = aDirectRefFeatures; + aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); + std::set::const_iterator anIt = aFeaturesToDelete.begin(), + aLast = aFeaturesToDelete.end(); #ifdef DEBUG_DELETE - QStringList anInfo; + QStringList anInfo; #endif - for (; anIt != aLast; anIt++) { - FeaturePtr aFeature = (*anIt); - DocumentPtr aDoc = aFeature->document(); - if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { - aDoc->removeFeature(aFeature); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = (*anIt); + DocumentPtr aDoc = aFeature->document(); + if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { + aDoc->removeFeature(aFeature); #ifdef DEBUG_DELETE - anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str()); + anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str()); #endif + } } - } #ifdef DEBUG_DELETE - qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str()); - anInfo.clear(); + qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str()); + anInfo.clear(); #endif + } QString anActionId = "DELETE_CMD"; QString anId = QString::fromStdString(anActionId.toStdString().c_str()); -- 2.39.2