From accd372f85e4c22be316348c94192ebb43fb4add Mon Sep 17 00:00:00 2001 From: Alexey Kondratyev Date: Mon, 11 Oct 2021 10:33:06 +0300 Subject: [PATCH] bos #26444 Improve treatment of parameters Add python function to import parameters from file. Add test for checking importing parameters. Add "Import file" button in parameter manager to import parameters. Update documentation. --- .../InitializationPlugin_EvalListener.cpp | 11 +++ src/ModelAPI/ModelAPI_Events.cpp | 21 ++++++ src/ModelAPI/ModelAPI_Events.h | 38 +++++++++++ src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 9 ++- src/ModelHighAPI/ModelHighAPI_Tools.cpp | 7 ++ src/ModelHighAPI/ModelHighAPI_Tools.h | 5 ++ src/ParametersAPI/ParametersAPI.i | 15 ++++ src/ParametersAPI/ParametersAPI_Parameter.cpp | 14 +++- src/ParametersAPI/ParametersAPI_Parameter.h | 4 +- src/ParametersPlugin/CMakeLists.txt | 1 + .../ParametersPlugin_WidgetParamsMgr.cpp | 42 ++++++++++-- .../ParametersPlugin_WidgetParamsMgr.h | 6 +- .../Test/TestImportInvalidParameters.py | 36 ++++++++++ .../Test/TestImportParameters.py | 40 +++++++++++ .../Test/TestParameterCreationError.py | 35 ++++++++++ .../Test/TestParameterErrorMsg.py | 24 ++++--- .../Test/data/invalid_parameters.txt | 5 ++ src/ParametersPlugin/Test/data/parameters.txt | 5 ++ .../doc/TUI_parameterFeature.rst | 1 + src/ParametersPlugin/doc/examples/File.txt | 3 + .../doc/examples/parameter.py | 1 + src/ParametersPlugin/doc/images/Manager.png | Bin 8135 -> 12950 bytes .../doc/images/parameters.png | Bin 23390 -> 12852 bytes src/ParametersPlugin/doc/managerFeature.rst | 16 +++++ src/ParametersPlugin/doc/parameterFeature.rst | 5 ++ src/ParametersPlugin/tests.set | 2 + src/PartSet/PartSet_Module.cpp | 20 ++++++ src/PythonAPI/model/parameter/__init__.py | 4 +- .../model/parameter/import_parameter.py | 64 ++++++++++++++++++ 29 files changed, 412 insertions(+), 22 deletions(-) create mode 100644 src/ParametersPlugin/Test/TestImportInvalidParameters.py create mode 100644 src/ParametersPlugin/Test/TestImportParameters.py create mode 100644 src/ParametersPlugin/Test/TestParameterCreationError.py create mode 100644 src/ParametersPlugin/Test/data/invalid_parameters.txt create mode 100644 src/ParametersPlugin/Test/data/parameters.txt create mode 100644 src/ParametersPlugin/doc/examples/File.txt create mode 100644 src/PythonAPI/model/parameter/import_parameter.py diff --git a/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp index 76a388ee5..26126b8f5 100644 --- a/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp +++ b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp @@ -78,6 +78,7 @@ InitializationPlugin_EvalListener::InitializationPlugin_EvalListener() aLoop->registerListener(this, ModelAPI_ParameterEvalMessage::eventId(), NULL, true); aLoop->registerListener(this, ModelAPI_BuildEvalMessage::eventId(), NULL, true); aLoop->registerListener(this, ModelAPI_ComputePositionsMessage::eventId(), NULL, true); + aLoop->registerListener(this, ModelAPI_ImportParametersMessage::eventId(), NULL, true); myInterp = std::shared_ptr(new InitializationPlugin_PyInterp()); myInterp->initialize(); @@ -179,6 +180,16 @@ void InitializationPlugin_EvalListener::processEvent( } aMsg->setResults(aParamsList, anError); } + else if (theMessage->eventID() == ModelAPI_ImportParametersMessage::eventId()) + { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + std::string anImportScript("from salome.shaper import model;"); + std::string aDocScript("doc = model.activeDocument();"); + std::string anParamImpScript("model.importParameters(doc, \""); + std::string aPath = aMsg->filename(); + myInterp->runString(anImportScript + aDocScript + anParamImpScript + aPath + "\")"); + } } //================================================================================================= diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index 6b0ea3ef5..506b26189 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -188,6 +188,27 @@ const std::string& ModelAPI_ParameterEvalMessage::error() const return myError; } +/// Creates an empty message +ModelAPI_ImportParametersMessage::ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender) + :Events_Message(theID, theSender) +{ + +} + +ModelAPI_ImportParametersMessage::~ModelAPI_ImportParametersMessage() +{ +} + +std::string ModelAPI_ImportParametersMessage::filename() const +{ + return myFilename; +} + +void ModelAPI_ImportParametersMessage::setFilename(std::string theFilename) +{ + myFilename = theFilename; +} + ModelAPI_BuildEvalMessage::ModelAPI_BuildEvalMessage( const Events_ID theID, const void* theSender) : Events_Message(theID, theSender), myIsProcessed(false) diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index a5dc0dde9..2ebd25b0f 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -352,6 +352,44 @@ class ModelAPI_ParameterEvalMessage : public Events_Message MODELAPI_EXPORT const std::string& error() const; }; +class ModelAPI_ImportParametersMessage : public Events_Message +{ + std::string myFilename; ///< filename where where parameters are stored + std::string myError; ///< error of processing, empty if there is no error + +public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char* MY_PARAMETER_EVALUATION_EVENT_ID("ImportParametersMessage"); + static Events_ID anId = Events_Loop::eventByName(MY_PARAMETER_EVALUATION_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the event. + /// Returns the message, processed, with the resulting fields filled. + MODELAPI_EXPORT static std::shared_ptr + send(std::string theParameter, const void* theSender) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ImportParametersMessage(eventId(), theSender)); + aMessage->setFilename(theParameter); + Events_Loop::loop()->send(aMessage); + return aMessage; + } + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ImportParametersMessage(); + + /// Returns a filename stored in the message + MODELAPI_EXPORT std::string filename() const; + /// Sets a filename to the message + MODELAPI_EXPORT void setFilename(std::string theFilename); +}; + class ModelAPI_BuildEvalMessage : public Events_Message { FeaturePtr myParam; ///< parameters that should be evaluated diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 6110bf89e..09900d6b8 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -1275,7 +1275,14 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrStr) { - *myDumpStorage << "\"" << theAttrStr->value() << "\""; + // escaping the quote sign in the string under dumping + std::string aStr = theAttrStr->value(); + size_t aPos = aStr.find("\""); + while (aPos != std::string::npos) { + aStr.insert(aPos, "\\"); + aPos = aStr.find("\"", aPos + 2); + } + *myDumpStorage << "'" << aStr << "'"; return *this; } diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.cpp b/src/ModelHighAPI/ModelHighAPI_Tools.cpp index 8208eba76..14ab98878 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Tools.cpp @@ -224,6 +224,13 @@ void fillAttribute(const std::string & theValue, theAttribute->setValue(theValue); } +//-------------------------------------------------------------------------------------- +void fillAttribute(const std::wstring & theValue, + const std::shared_ptr & theAttribute) +{ + theAttribute->setValue(theValue); +} + //-------------------------------------------------------------------------------------- void fillAttribute(const char * theValue, const std::shared_ptr & theAttribute) diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.h b/src/ModelHighAPI/ModelHighAPI_Tools.h index 7f0e1c896..a476721a6 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.h +++ b/src/ModelHighAPI/ModelHighAPI_Tools.h @@ -136,6 +136,11 @@ void fillAttribute(const std::list & theValue, MODELHIGHAPI_EXPORT void fillAttribute(const std::string & theValue, const std::shared_ptr & theAttribute); + +MODELHIGHAPI_EXPORT +void fillAttribute(const std::wstring & theValue, + const std::shared_ptr & theAttribute); + MODELHIGHAPI_EXPORT void fillAttribute(const char * theValue, const std::shared_ptr & theAttribute); diff --git a/src/ParametersAPI/ParametersAPI.i b/src/ParametersAPI/ParametersAPI.i index 6922c1f96..66ba5fb3d 100644 --- a/src/ParametersAPI/ParametersAPI.i +++ b/src/ParametersAPI/ParametersAPI.i @@ -23,6 +23,11 @@ %{ #include "ParametersAPI_swig.h" + + // fix for SWIG v2.0.4 + #define SWIGPY_SLICE_ARG(obj) ((PyObject*)(obj)) + + #define SWIGPY_UNICODE_ARG(obj) ((PyObject*) (obj)) %} %include "doxyhelp.i" @@ -40,5 +45,15 @@ // shared pointers %shared_ptr(ParametersAPI_Parameter) +// exception handler +%exception addParameter { + try { + $action + } catch (const std::string& str) { + PyErr_SetString(PyExc_SyntaxError, str.c_str()); + return NULL; + } +} + // all supported interfaces %include "ParametersAPI_Parameter.h" diff --git a/src/ParametersAPI/ParametersAPI_Parameter.cpp b/src/ParametersAPI/ParametersAPI_Parameter.cpp index 27c687ad3..5c2c7130c 100644 --- a/src/ParametersAPI/ParametersAPI_Parameter.cpp +++ b/src/ParametersAPI/ParametersAPI_Parameter.cpp @@ -35,7 +35,7 @@ ParametersAPI_Parameter::ParametersAPI_Parameter( const std::shared_ptr & theFeature, const std::string & theName, const std::string & theExpression, - const std::string & theComment) + const std::wstring & theComment) : ModelHighAPI_Interface(theFeature) { if (initialize()) { @@ -87,10 +87,18 @@ void ParametersAPI_Parameter::dump(ModelHighAPI_Dumper& theDumper) const ParameterPtr addParameter(const std::shared_ptr & thePart, const std::string & theName, const std::string & theExpression, - const std::string & theComment) + const std::wstring & theComment) { std::shared_ptr aFeature = thePart->addFeature(ParametersAPI_Parameter::ID()); - return ParameterPtr(new ParametersAPI_Parameter(aFeature, theName, theExpression, theComment)); + ParameterPtr aParam(new ParametersAPI_Parameter(aFeature, theName, theExpression, theComment)); + + if (!aParam->feature()->error().empty()) + { + std::string anError("Error with parameter \""); + anError += theName + "\": " + aParam->feature()->error(); + throw anError; + } + return aParam; } //-------------------------------------------------------------------------------------- diff --git a/src/ParametersAPI/ParametersAPI_Parameter.h b/src/ParametersAPI/ParametersAPI_Parameter.h index 50bb1d3b8..8295db3cc 100644 --- a/src/ParametersAPI/ParametersAPI_Parameter.h +++ b/src/ParametersAPI/ParametersAPI_Parameter.h @@ -45,7 +45,7 @@ public: explicit ParametersAPI_Parameter(const std::shared_ptr & theFeature, const std::string & theName, const std::string & theExpression, - const std::string & theComment = std::string()); + const std::wstring & theComment = std::wstring()); /// Destructor PARAMETERSAPI_EXPORT virtual ~ParametersAPI_Parameter(); @@ -80,7 +80,7 @@ PARAMETERSAPI_EXPORT ParameterPtr addParameter(const std::shared_ptr & thePart, const std::string & theName, const std::string & theExpression, - const std::string & theComment = std::string()); + const std::wstring & theComment = std::wstring()); /**\ingroup CPPHighAPI * \brief Remove Parameter feature and substitute it by the value in referred features diff --git a/src/ParametersPlugin/CMakeLists.txt b/src/ParametersPlugin/CMakeLists.txt index 9f1140baa..bd37033bd 100644 --- a/src/ParametersPlugin/CMakeLists.txt +++ b/src/ParametersPlugin/CMakeLists.txt @@ -137,4 +137,5 @@ if(${HAVE_SALOME}) endforeach(tfile ${TEST_NAMES}) install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY}) + install(DIRECTORY Test/data DESTINATION ${TEST_INSTALL_DIRECTORY}) endif(${HAVE_SALOME}) diff --git a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp index 62a432a8b..6cad00013 100644 --- a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp +++ b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp @@ -54,6 +54,7 @@ #include #include #include +#include enum ColumnType { Col_Name, @@ -253,6 +254,10 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP connect(myInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert())); aBtnLayout->addWidget(myInsertBtn); + myImportBtn = new QPushButton(translate("Import file"), this); + connect(myImportBtn, SIGNAL(clicked(bool)), SLOT(onImport())); + aBtnLayout->addWidget(myImportBtn); + myRemoveBtn = new QPushButton(translate("Remove"), this); connect(myRemoveBtn, SIGNAL(clicked(bool)), SLOT(onRemove())); aBtnLayout->addWidget(myRemoveBtn); @@ -484,6 +489,7 @@ void ParametersPlugin_WidgetParamsMgr::onCloseEditor(QWidget* theEditor, FeaturePtr aFeature = myParametersList.at(myDelegate->editIndex().row()); QTreeWidgetItem* aItem = myParameters->child(myDelegate->editIndex().row()); int aColumn = myDelegate->editIndex().column(); + int aRow = myDelegate->editIndex().row(); QString aText = aItem->text(aColumn); bool isModified = false; @@ -495,7 +501,7 @@ void ParametersPlugin_WidgetParamsMgr::onCloseEditor(QWidget* theEditor, while (aText.indexOf(" ") != -1) { aText.replace(" ", ""); } - if (hasName(aText)) { + if (hasName(aText, aRow)) { myMessage = translate("Name '%1' already exists.").arg(aText); QTimer::singleShot(50, this, SLOT(sendWarning())); return; @@ -521,7 +527,7 @@ void ParametersPlugin_WidgetParamsMgr::onCloseEditor(QWidget* theEditor, case Col_Comment: { AttributeStringPtr aStringAttr = aFeature->string(ParametersPlugin_Parameter::COMMENT_ID()); - aStringAttr->setValue(aText.toStdString()); + aStringAttr->setValue(aText.toStdWString()); isModified = true; } break; @@ -691,6 +697,27 @@ void ParametersPlugin_WidgetParamsMgr::onRemove() } } +void ParametersPlugin_WidgetParamsMgr::onImport() +{ + std::string aWinText("Select txt file"); + std::string aFileType("Text files (*.txt);;All files (*.*)"); + QString aQPath = QFileDialog::getOpenFileName(nullptr, + aWinText.c_str(), "", + aFileType.c_str()); + if (aQPath.size() == 0) + return; + + std::string aPath(aQPath.toStdString()); + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ImportParametersMessage(ModelAPI_ImportParametersMessage::eventId())); + aMessage->setFilename(aPath); + Events_Loop::loop()->send(aMessage); + + updateParametersFeatures(); + updateParametersPart(); +} + void ParametersPlugin_WidgetParamsMgr::onUp() { QTreeWidgetItem* aCurrentItem = selectedItem(); @@ -764,12 +791,11 @@ void ParametersPlugin_WidgetParamsMgr::onDown() } -bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName) const +bool ParametersPlugin_WidgetParamsMgr::hasName(const QString& theName, int theIndex) const { - int aCurrent = myDelegate->editIndex().row(); int i = 0; foreach(FeaturePtr aFeature, myParametersList) { - if ((i != aCurrent) && (aFeature->data()->name() == theName.toStdWString())) + if ((i != theIndex) && (aFeature->data()->name() == theName.toStdWString())) return true; i++; } @@ -800,11 +826,13 @@ void ParametersPlugin_WidgetParamsMgr::onSelectionChanged() //myRemoveBtn->setEnabled(isParameter); myUpBtn->setEnabled(isParameter); myDownBtn->setEnabled(isParameter); + myImportBtn->setEnabled(true); } else { myInsertBtn->setEnabled(false); //myRemoveBtn->setEnabled(false); myUpBtn->setEnabled(false); myDownBtn->setEnabled(false); + myImportBtn->setEnabled(false); } myRemoveBtn->setEnabled(!aItemsList.isEmpty()); } @@ -819,6 +847,7 @@ void ParametersPlugin_WidgetParamsMgr::enableButtons(bool theEnable) //myRemoveBtn->setEnabled(theEnable); myUpBtn->setEnabled(theEnable); myDownBtn->setEnabled(theEnable); + myImportBtn->setEnabled(theEnable); } myOkCancelBtn->button(QDialogButtonBox::Ok)->setEnabled(theEnable); } @@ -830,7 +859,8 @@ bool ParametersPlugin_WidgetParamsMgr::isValid() aItem = myParameters->child(i); if ((aItem->text(Col_Name) == NoName) || (aItem->text(Col_Equation) == translate(NoValue)) || - (!ModelAPI_Expression::isVariable(aItem->text(Col_Name).toStdString())) ) { + (!ModelAPI_Expression::isVariable(aItem->text(Col_Name).toStdString())) || + (hasName(aItem->text(Col_Name), i)) ) { return false; } } diff --git a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h index 58f717e45..6cc543d0d 100644 --- a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h +++ b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h @@ -109,6 +109,9 @@ private slots: /// Slot for reaction on remove parameter void onRemove(); + /// Slot for reaction on import parameter + void onImport(); + /// Slot for reaction on shift up void onUp(); @@ -148,7 +151,7 @@ private: bool isValid(); /// Returns true if parameter with the given name already exists - bool hasName(const QString& theName) const; + bool hasName(const QString& theName, int theIndex) const; /// Enable or disable buttons for parameters managemnt void enableButtons(bool theEnable); @@ -173,6 +176,7 @@ private: QPushButton* myAddBtn; QPushButton* myInsertBtn; QPushButton* myRemoveBtn; + QPushButton* myImportBtn; QToolButton* myUpBtn; QToolButton* myDownBtn; diff --git a/src/ParametersPlugin/Test/TestImportInvalidParameters.py b/src/ParametersPlugin/Test/TestImportInvalidParameters.py new file mode 100644 index 000000000..61b9751d1 --- /dev/null +++ b/src/ParametersPlugin/Test/TestImportInvalidParameters.py @@ -0,0 +1,36 @@ +# Copyright (C) 2014-2021 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 +# + +from salome.shaper import model +import inspect, os + +data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data") + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +nameFile = "invalid_parameters.txt" + +aDir = os.path.join(data_dir, nameFile) + +aListOfParameters = model.importParameters(Part_1_doc, aDir) + +assert(len(aListOfParameters) == 0) diff --git a/src/ParametersPlugin/Test/TestImportParameters.py b/src/ParametersPlugin/Test/TestImportParameters.py new file mode 100644 index 000000000..29fbf7f68 --- /dev/null +++ b/src/ParametersPlugin/Test/TestImportParameters.py @@ -0,0 +1,40 @@ +# Copyright (C) 2014-2021 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 +# + +from salome.shaper import model +import inspect, os + +data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data") + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +nameFile = "parameters.txt" + +aDir = os.path.join(data_dir, nameFile) + +aListOfParameters = model.importParameters(Part_1_doc, aDir) + +Box_1 = model.addBox(Part_1_doc, "Longueur", "Largeur", "Hauteur") + +assert(len(Box_1.feature().error()) == 0) +assert(len(aListOfParameters) == 5) +assert(model.checkPythonDump()) diff --git a/src/ParametersPlugin/Test/TestParameterCreationError.py b/src/ParametersPlugin/Test/TestParameterCreationError.py new file mode 100644 index 000000000..45da43336 --- /dev/null +++ b/src/ParametersPlugin/Test/TestParameterCreationError.py @@ -0,0 +1,35 @@ +# Copyright (C) 2014-2021 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 +# + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +aPart1 = model.addParameter(Part_1_doc, "Doing", "123", "Longueur de la pièce") +try: + aPart2 = model.addParameter(Part_1_doc, "Doing", "323", "Long") +except SyntaxError as anError: + assert(anError != "") + assert(str(anError).find("Variable name is not unique.") != -1) + +model.end() diff --git a/src/ParametersPlugin/Test/TestParameterErrorMsg.py b/src/ParametersPlugin/Test/TestParameterErrorMsg.py index bc7443528..d21b360de 100644 --- a/src/ParametersPlugin/Test/TestParameterErrorMsg.py +++ b/src/ParametersPlugin/Test/TestParameterErrorMsg.py @@ -22,15 +22,23 @@ from salome.shaper import model model.begin() partSet = model.moduleDocument() # check error on empty name -Param1 = model.addParameter(partSet, "", "100") -assert(Param1.feature().error() != "") +try: + Param1 = model.addParameter(partSet, "", "100") +except SyntaxError as anError: + assert(str(anError).find("Attribute \"variable\" value is empty.") != -1) # check error on empty value -Param2 = model.addParameter(partSet, "L", "") -assert(Param2.feature().error() != "") +try: + Param2 = model.addParameter(partSet, "L", "") +except SyntaxError as anError: + assert(str(anError).find("Expression is empty.") != -1) # check error if name is not variable -Param3 = model.addParameter(partSet, "100", "100") -assert(Param3.feature().error() != "") +try: + Param3 = model.addParameter(partSet, "100", "100") +except SyntaxError as anError: + assert(str(anError).find("Incorrect variable name.") != -1) # check error on wrong value expression -Param4 = model.addParameter(partSet, "N", "+-.so&@") -assert(Param4.feature().error() != "") +try: + Param4 = model.addParameter(partSet, "N", "+-.so&@") +except SyntaxError as anError: + assert(str(anError).find("invalid syntax") != -1) model.end() diff --git a/src/ParametersPlugin/Test/data/invalid_parameters.txt b/src/ParametersPlugin/Test/data/invalid_parameters.txt new file mode 100644 index 000000000..c119a86f8 --- /dev/null +++ b/src/ParametersPlugin/Test/data/invalid_parameters.txt @@ -0,0 +1,5 @@ +Hauteur Longueur*Largeur + +Largeur3 #Comment +# Comment + # Comm diff --git a/src/ParametersPlugin/Test/data/parameters.txt b/src/ParametersPlugin/Test/data/parameters.txt new file mode 100644 index 000000000..ca3185fdb --- /dev/null +++ b/src/ParametersPlugin/Test/data/parameters.txt @@ -0,0 +1,5 @@ +Longueur 36. # "Longueur de la pièce" +Largeur 24. # Largeur de la pièce +Hauteur Longueur*Largeur +A12 5. * 5. +Longueur2 36. #\"Comment\" #Comm #Comm \ No newline at end of file diff --git a/src/ParametersPlugin/doc/TUI_parameterFeature.rst b/src/ParametersPlugin/doc/TUI_parameterFeature.rst index bf120a891..04480ce43 100644 --- a/src/ParametersPlugin/doc/TUI_parameterFeature.rst +++ b/src/ParametersPlugin/doc/TUI_parameterFeature.rst @@ -9,4 +9,5 @@ Create Parameter :language: python :download:`Download this script ` +:download:`Download parameters file sample ` diff --git a/src/ParametersPlugin/doc/examples/File.txt b/src/ParametersPlugin/doc/examples/File.txt new file mode 100644 index 000000000..5ab7e7825 --- /dev/null +++ b/src/ParametersPlugin/doc/examples/File.txt @@ -0,0 +1,3 @@ +Width 10.0 #Width of square +Height 15.0 # Height of square +Area Width*Height # Area of square \ No newline at end of file diff --git a/src/ParametersPlugin/doc/examples/parameter.py b/src/ParametersPlugin/doc/examples/parameter.py index dc269a6e0..39d6fdb45 100644 --- a/src/ParametersPlugin/doc/examples/parameter.py +++ b/src/ParametersPlugin/doc/examples/parameter.py @@ -3,4 +3,5 @@ from salome.shaper import model model.begin() partSet = model.moduleDocument() model.addParameter(partSet, "angle", "60*3.141/180", "main angle") +model.importParameters(partSet, "File.txt") model.end() diff --git a/src/ParametersPlugin/doc/images/Manager.png b/src/ParametersPlugin/doc/images/Manager.png index a7e812d67852329a9df31b0d9d22b4759e575cef..99d0c1e69ec59d6f14cb4e046070d8bf4f8db4ae 100644 GIT binary patch literal 12950 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 diff --git a/src/ParametersPlugin/doc/images/parameters.png b/src/ParametersPlugin/doc/images/parameters.png index 4f1e1f66cc80635ef95641819a1f9fc8788fbcd4..fbf1d7b57ff9fd40954837567b899c2407f8b4a9 100755 GIT binary patch literal 12852 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 literal 23390 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

72HY`ZEpbbUX_nHP0Qivmz=y)?~nKFv+{C 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, **Expression** is ** - **Insert** button adds a new empty string before the selected parameter; - **Delete** button removes the selected parameter from the table; +- **Import** button import parameters from .txt files. Parameters must be written in file in separate lines like example: **Name** **Expression** #**Comment** +Sample.txt: +''Longueur 36. # Longueur de la pièce'' +''Largeur 24 #Largeur de la pièce'' +''Hauteur Longueur * Largeur'' - **Modify parameter position** button moves the selected parameter | |param_up| one string higher in the table, | |param_down| one string lower in the table. +**TUI Command**: + +.. py:function:: model.importParameters(Part_doc, filename) + + :param part: The current part object + :param filename: The txt file with parameters + :return: Created objects. + +**See Also** a sample TUI Script of a :ref:`tui_parameterFeature` operation. **See Also** :ref:`parameter` operation. diff --git a/src/ParametersPlugin/doc/parameterFeature.rst b/src/ParametersPlugin/doc/parameterFeature.rst index 757a023f0..24e6bc06a 100644 --- a/src/ParametersPlugin/doc/parameterFeature.rst +++ b/src/ParametersPlugin/doc/parameterFeature.rst @@ -41,6 +41,11 @@ The property panel checks validity of the expression. For an invalid expression :param string: The parameter comment :return: Created object. +Write error in Python console if: +- parameter name is empty. +- parameter don't have unique name. +- parameter expression is empty or incorrect. + **See Also** a sample TUI Script of a :ref:`tui_parameterFeature` operation. Result diff --git a/src/ParametersPlugin/tests.set b/src/ParametersPlugin/tests.set index 48514ff6b..668f4668f 100644 --- a/src/ParametersPlugin/tests.set +++ b/src/ParametersPlugin/tests.set @@ -28,4 +28,6 @@ SET(TEST_NAMES Test2392.py Test2474.py Test19036.py + TestImportParameters.py + TestImportInvalidParameters.py ) diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index a3095a374..c648cc072 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -83,6 +83,7 @@ #include #include #include +#include #include #include @@ -1739,6 +1740,25 @@ void PartSet_Module::onTreeViewDoubleClick(const QModelIndex& theIndex) if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) { aPart = std::dynamic_pointer_cast(aPartFeature->firstResult()); } + if (aObj.get()) + { + if (!aPart.get() && aObj->groupName() == ModelAPI_ResultParameter::group()) + { + QObjectPtrList aObjects = aWorkshop->objectBrowser()->selectedObjects(); + FeaturePtr aFeature; + ResultParameterPtr aParam; + foreach(ObjectPtr aObj, aObjects) { + aParam = std::dynamic_pointer_cast(aObj); + if (aParam.get()) + break; + } + if (aParam.get()) + aFeature = ModelAPI_Feature::feature(aParam); + + if (aFeature.get()) + editFeature(aFeature); + } + } } if (aPart.get()) { // if this is a part if (aPart->partDoc() == aMgr->activeDocument()) { diff --git a/src/PythonAPI/model/parameter/__init__.py b/src/PythonAPI/model/parameter/__init__.py index f0c7b22e8..0f0f64a18 100644 --- a/src/PythonAPI/model/parameter/__init__.py +++ b/src/PythonAPI/model/parameter/__init__.py @@ -19,4 +19,6 @@ """Package for Parameter plugin for the Parametric Geometry API of the Modeler. """ -from ParametersAPI import addParameter, removeParameter \ No newline at end of file +from ParametersAPI import addParameter, removeParameter + +from .import_parameter import * diff --git a/src/PythonAPI/model/parameter/import_parameter.py b/src/PythonAPI/model/parameter/import_parameter.py new file mode 100644 index 000000000..3b2a25c06 --- /dev/null +++ b/src/PythonAPI/model/parameter/import_parameter.py @@ -0,0 +1,64 @@ +# Copyright (C) 2014-2021 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 +# + +from salome.shaper import model +import codecs, sys + +def changeTab(theLine): + aResult = theLine.split("#")[0].replace("\t"," ") + aResult += theLine[len(aResult):] + return aResult + +def importParameters(theDocument, theFileName): + + aResult = [] + try: + aFile = codecs.open(theFileName, 'r', encoding = 'utf_8_sig') + except IOError: + return aResult + + for aLine in aFile: + aLine = aLine.rstrip("\n") + aLine = changeTab(aLine) + + aName = "" + aParameter = "" + aComment = "" + + aFirstText = aLine.split(" ")[0] + + aName = aFirstText.split("#")[0].strip() + + aLine = aLine.lstrip(aName) + + aParameter = aLine.split("#")[0] + + aLine = aLine.lstrip(aParameter) + aLine = aLine.lstrip("#") + + aComment = aLine + + if(len(aName) > 0): + try: + aResult.append(model.addParameter(theDocument, aName, aParameter.strip(), aComment.strip())) + except SyntaxError as anError: + print(anError, file = sys.stderr) + + aFile.close() + return aResult -- 2.39.2