Salome HOME
bos #26444 Improve treatment of parameters
authorAlexey Kondratyev <alexey.kondratyev@opencascade.com>
Mon, 11 Oct 2021 07:33:06 +0000 (10:33 +0300)
committervsr <vsr@opencascade.com>
Mon, 8 Nov 2021 08:25:24 +0000 (11:25 +0300)
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.

29 files changed:
src/InitializationPlugin/InitializationPlugin_EvalListener.cpp
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/ModelHighAPI/ModelHighAPI_Tools.cpp
src/ModelHighAPI/ModelHighAPI_Tools.h
src/ParametersAPI/ParametersAPI.i
src/ParametersAPI/ParametersAPI_Parameter.cpp
src/ParametersAPI/ParametersAPI_Parameter.h
src/ParametersPlugin/CMakeLists.txt
src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp
src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h
src/ParametersPlugin/Test/TestImportInvalidParameters.py [new file with mode: 0644]
src/ParametersPlugin/Test/TestImportParameters.py [new file with mode: 0644]
src/ParametersPlugin/Test/TestParameterCreationError.py [new file with mode: 0644]
src/ParametersPlugin/Test/TestParameterErrorMsg.py
src/ParametersPlugin/Test/data/invalid_parameters.txt [new file with mode: 0644]
src/ParametersPlugin/Test/data/parameters.txt [new file with mode: 0644]
src/ParametersPlugin/doc/TUI_parameterFeature.rst
src/ParametersPlugin/doc/examples/File.txt [new file with mode: 0644]
src/ParametersPlugin/doc/examples/parameter.py
src/ParametersPlugin/doc/images/Manager.png
src/ParametersPlugin/doc/images/parameters.png
src/ParametersPlugin/doc/managerFeature.rst
src/ParametersPlugin/doc/parameterFeature.rst
src/ParametersPlugin/tests.set
src/PartSet/PartSet_Module.cpp
src/PythonAPI/model/parameter/__init__.py
src/PythonAPI/model/parameter/import_parameter.py [new file with mode: 0644]

index 76a388ee5faa9197d57babd4e3444fa1f5146bc8..26126b8f53c6f7f174bd07f079f5b35457f0baf0 100644 (file)
@@ -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<InitializationPlugin_PyInterp>(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<ModelAPI_ImportParametersMessage> aMsg =
+      std::dynamic_pointer_cast<ModelAPI_ImportParametersMessage>(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 + "\")");
+  }
 }
 
 //=================================================================================================
index 6b0ea3ef5e639662996e847d78467e593973f101..506b261893205208fa443108f8f31811df5be0df 100644 (file)
@@ -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)
index a5dc0dde9cad1da4da11ea5ac6b6747c022e0025..2ebd25b0f37d1f7f6f9ab529d1152ea87d86692b 100644 (file)
@@ -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<ModelAPI_ImportParametersMessage>
+    send(std::string theParameter, const void* theSender)
+  {
+    std::shared_ptr<ModelAPI_ImportParametersMessage> aMessage =
+      std::shared_ptr<ModelAPI_ImportParametersMessage>(
+        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
index 6110bf89eaf54bc0d38b66806e523f489470aa09..09900d6b8ce84ee5fc33821ba52d8041693bf884 100644 (file)
@@ -1275,7 +1275,14 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     const std::shared_ptr<ModelAPI_AttributeString>& 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;
 }
 
index 8208eba768f06f201a0e2b8913e94a15c7161aff..14ab9887894f1c487822341e04a9d81b46a10bc9 100644 (file)
@@ -224,6 +224,13 @@ void fillAttribute(const std::string & theValue,
   theAttribute->setValue(theValue);
 }
 
+//--------------------------------------------------------------------------------------
+void fillAttribute(const std::wstring & theValue,
+  const std::shared_ptr<ModelAPI_AttributeString> & theAttribute)
+{
+  theAttribute->setValue(theValue);
+}
+
 //--------------------------------------------------------------------------------------
 void fillAttribute(const char * theValue,
                    const std::shared_ptr<ModelAPI_AttributeString> & theAttribute)
index 7f0e1c8962d7bbcc248a7e8a4092a0135525162c..a476721a65141b860ef62b879bf094dab566ae4a 100644 (file)
@@ -136,6 +136,11 @@ void fillAttribute(const std::list<ModelHighAPI_Selection> & theValue,
 MODELHIGHAPI_EXPORT
 void fillAttribute(const std::string & theValue,
                    const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
+
+MODELHIGHAPI_EXPORT
+void fillAttribute(const std::wstring & theValue,
+  const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
+
 MODELHIGHAPI_EXPORT
 void fillAttribute(const char * theValue,
                    const std::shared_ptr<ModelAPI_AttributeString> & theAttribute);
index 6922c1f968a0db3e3ddc936a71bf4273927f762e..66ba5fb3db11e4048f73dbc70ea7bc08de68f2b4 100644 (file)
 
 %{
   #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"
 // 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"
index 27c687ad349886bdd3f3e85b985d1a851cb3dffb..5c2c7130c6c830df98a6103e206f2c11f2a1b5ab 100644 (file)
@@ -35,7 +35,7 @@ ParametersAPI_Parameter::ParametersAPI_Parameter(
     const std::shared_ptr<ModelAPI_Feature> & 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<ModelAPI_Document> & thePart,
                           const std::string & theName,
                           const std::string & theExpression,
-                          const std::string & theComment)
+                          const std::wstring & theComment)
 {
   std::shared_ptr<ModelAPI_Feature> 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;
 }
 
 //--------------------------------------------------------------------------------------
index 50bb1d3b8f4f2eb279959a83fdb2298581d186b5..8295db3ccf47e0d0f7d0b7365923ca1c735b70d4 100644 (file)
@@ -45,7 +45,7 @@ public:
   explicit ParametersAPI_Parameter(const  std::shared_ptr<ModelAPI_Feature> & 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<ModelAPI_Document> & 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
index 9f1140baa77df1f6d3ded84059b632f87af81ee2..bd37033bd251a2f6737fe6fcddb1df3125d13647 100644 (file)
@@ -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})
index 62a432a8b95cd06c72969d2843b5290e2d00c267..6cad0001346eed4bf21036eaf307754850b8a097 100644 (file)
@@ -54,6 +54,7 @@
 #include <QKeyEvent>
 #include <QDialogButtonBox>
 #include <QShortcut>
+#include <QFileDialog>
 
 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<ModelAPI_ImportParametersMessage> aMessage =
+    std::shared_ptr<ModelAPI_ImportParametersMessage>(
+      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;
     }
   }
index 58f717e45903db31fd8a32318398c5988b8ebc8d..6cc543d0ddcdb5e8a82a8645b5646252faecd6d7 100644 (file)
@@ -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 (file)
index 0000000..61b9751
--- /dev/null
@@ -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 (file)
index 0000000..29fbf7f
--- /dev/null
@@ -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 (file)
index 0000000..45da433
--- /dev/null
@@ -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()
index bc74435283db558ad2318a56b33e83fc80f3948f..d21b360de47bab3f3703cd107c531d449d4c390f 100644 (file)
@@ -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 (file)
index 0000000..c119a86
--- /dev/null
@@ -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 (file)
index 0000000..ca3185f
--- /dev/null
@@ -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
index bf120a891755e331839bc0bd8a5d5c95def596f3..04480ce43cec9d4d282b58fcc43056379a9652c5 100644 (file)
@@ -9,4 +9,5 @@ Create Parameter
     :language: python
 
 :download:`Download this script <examples/parameter.py>` 
+:download:`Download parameters file sample <examples/File.txt>`
    
diff --git a/src/ParametersPlugin/doc/examples/File.txt b/src/ParametersPlugin/doc/examples/File.txt
new file mode 100644 (file)
index 0000000..5ab7e78
--- /dev/null
@@ -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
index dc269a6e0ab5ba5568c171e74d99a3e74374e579..39d6fdb45bb83831fa6ed6adf5e3f25496b7f3cc 100644 (file)
@@ -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()
index a7e812d67852329a9df31b0d9d22b4759e575cef..99d0c1e69ec59d6f14cb4e046070d8bf4f8db4ae 100644 (file)
Binary files a/src/ParametersPlugin/doc/images/Manager.png and b/src/ParametersPlugin/doc/images/Manager.png differ
index 4f1e1f66cc80635ef95641819a1f9fc8788fbcd4..fbf1d7b57ff9fd40954837567b899c2407f8b4a9 100755 (executable)
Binary files a/src/ParametersPlugin/doc/images/parameters.png and b/src/ParametersPlugin/doc/images/parameters.png differ
index 7575ee81e7e09b6a2797e1fe389959ceb52676a5..fe1ed998d574c3785e1638da4a0fe6e808cb3b85 100644 (file)
@@ -20,6 +20,8 @@ The following dialog box with parameter table appears:
 .. |param_up| image:: images/parameters_up.png
 .. |param_down| image:: images/parameters_down.png
 
+To edit a parameter, double-click on parameter in object browser.
+
 **Input fields**:
 
 - **Name** defines parameter name. Name follows the naming rules of the python language for variables;
@@ -29,9 +31,23 @@ The following dialog box with parameter table appears:
 - **Add** button adds a new empty string in the end of table. Default  **Name** is *<NoName>*, **Expression** is   *<NoValue>* 
 - **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.
index 757a023f0dc150e9a2974edb431a02361d8d1e92..24e6bc06a80673b4b160d679198ecae523394880 100644 (file)
@@ -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
index 48514ff6bc151d82a4c84896c229c03b22ec43ba..668f4668f7dc1ec70cf97b4ab4e50b3794ea668a 100644 (file)
@@ -28,4 +28,6 @@ SET(TEST_NAMES
                Test2392.py
                Test2474.py
                Test19036.py
+               TestImportParameters.py
+               TestImportInvalidParameters.py
 )
index a3095a374c5735baed2d52c0136cd790d74e6518..c648cc072f2dc444cb8f3bc612a6d35ef0bc995f 100644 (file)
@@ -83,6 +83,7 @@
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_ResultParameter.h>
 
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Point.h>
@@ -1739,6 +1740,25 @@ void PartSet_Module::onTreeViewDoubleClick(const QModelIndex& theIndex)
     if (aPartFeature.get() && (aPartFeature->getKind() == PartSetPlugin_Part::ID())) {
       aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(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<ModelAPI_ResultParameter>(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()) {
index f0c7b22e8414a409859c3ab92c217ed204122a69..0f0f64a18f6f803c72aba265117f941cb52d35d0 100644 (file)
@@ -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 (file)
index 0000000..3b2a25c
--- /dev/null
@@ -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