Salome HOME
Issue #588: Renaming a parameter used in an expression
authorspo <sergey.pokhodenko@opencascade.com>
Thu, 2 Jul 2015 12:27:44 +0000 (15:27 +0300)
committerspo <sergey.pokhodenko@opencascade.com>
Fri, 3 Jul 2015 07:46:37 +0000 (10:46 +0300)
src/Model/Model_Data.cpp
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ParametersPlugin/ParametersPlugin_EvalListener.cpp
src/ParametersPlugin/ParametersPlugin_EvalListener.h
src/ParametersPlugin/ParametersPlugin_PyInterp.cpp
src/ParametersPlugin/ParametersPlugin_PyInterp.h

index 12f79ae5db1f0b6c324579d7f02cabb1a97f6c58..36f01202816dbde5185156484f15d7f882539882 100644 (file)
@@ -77,6 +77,7 @@ std::string Model_Data::name()
 void Model_Data::setName(const std::string& theName)
 {
   bool isModified = false;
+  std::string anOldName = name();
   Handle(TDataStd_Name) aName;
   if (!myLab.FindAttribute(TDataStd_Name::GetID(), aName)) {
     TDataStd_Name::Set(myLab, theName.c_str());
@@ -86,6 +87,8 @@ void Model_Data::setName(const std::string& theName)
     if (isModified)
       aName->Set(theName.c_str());
   }
+  if (isModified)
+    ModelAPI_ObjectRenamedMessage::send(myObject, anOldName, theName, this);
 }
 
 AttributePtr Model_Data::addAttribute(const std::string& theID, const std::string theAttrType)
index dbd088755502206ef3ce57e1cf4390110422115d..2260ce1fb2ae925fc94028915f88ee53d93e4109 100644 (file)
@@ -128,3 +128,58 @@ void ModelAPI_AttributeEvalMessage::setAttribute(AttributePtr theDocument)
 {
   myAttribute = theDocument;
 }
+
+ModelAPI_ObjectRenamedMessage::ModelAPI_ObjectRenamedMessage(const Events_ID theID,
+                                                             const void* theSender)
+: Events_Message(theID, theSender)
+{
+
+}
+
+ModelAPI_ObjectRenamedMessage::~ModelAPI_ObjectRenamedMessage()
+{
+
+}
+
+void ModelAPI_ObjectRenamedMessage::send(ObjectPtr theObject,
+                                         const std::string& theOldName,
+                                         const std::string& theNewName,
+                                         const void* theSender)
+{
+  std::shared_ptr<ModelAPI_ObjectRenamedMessage> aMessage(
+    new ModelAPI_ObjectRenamedMessage(eventId(), theSender));
+  aMessage->setObject(theObject);
+  aMessage->setOldName(theOldName);
+  aMessage->setNewName(theNewName);
+  Events_Loop::loop()->send(aMessage);
+}
+
+ObjectPtr ModelAPI_ObjectRenamedMessage::object() const
+{
+  return myObject;
+}
+
+void ModelAPI_ObjectRenamedMessage::setObject(ObjectPtr theObject)
+{
+  myObject = theObject;
+}
+
+std::string ModelAPI_ObjectRenamedMessage::oldName() const
+{
+  return myOldName;
+}
+
+void ModelAPI_ObjectRenamedMessage::setOldName(const std::string& theOldName)
+{
+  myOldName = theOldName;
+}
+
+std::string ModelAPI_ObjectRenamedMessage::newName() const
+{
+  return myNewName;
+}
+
+void ModelAPI_ObjectRenamedMessage::setNewName(const std::string& theNewName)
+{
+  myNewName = theNewName;
+}
index 741aa0a8b00465a03a8f6220a16a21c38870cc46..bcb50be1e84850b491f0026ab1c0839ebb8adecb 100644 (file)
@@ -28,6 +28,8 @@ static const char * EVENT_OBJECT_CREATED = "ObjectCreated";
 static const char * EVENT_OBJECT_UPDATED = "ObjectUpdated";
 /// Event ID that data of feature is deleted (comes with Model_ObjectDeletedMessage)
 static const char * EVENT_OBJECT_DELETED = "ObjectDeleted";
+/// Event ID that name of feature is changed (comes with Model_ObjectRenamedMessage)
+static const char * EVENT_OBJECT_RENAMED = "ObjectRenamed";
 /// Event ID that data of feature is updated (comes with ModelAPI_ObjectUpdatedMessage)
 static const char * EVENT_OBJECT_MOVED = "ObjectsMoved";
 /// Event ID that visualization must be redisplayed (comes with ModelAPI_ObjectUpdatedMessage)
@@ -199,4 +201,45 @@ class ModelAPI_AttributeEvalMessage : public Events_Message
   MODELAPI_EXPORT void setAttribute(AttributePtr theAttribute);
 };
 
+/// Message that the object is renamed
+class ModelAPI_ObjectRenamedMessage : public Events_Message
+{
+  ObjectPtr myObject;
+  std::string myOldName;
+  std::string myNewName;
+
+ public:
+  /// Static. Returns EventID of the message.
+  MODELAPI_EXPORT static Events_ID& eventId()
+  {
+    static const char * MY_OBJECT_RENAMED_EVENT_ID("ObjectRenamed");
+    static Events_ID anId = Events_Loop::eventByName(MY_OBJECT_RENAMED_EVENT_ID);
+    return anId;
+  }
+
+  /// Useful method that creates and sends the AttributeEvalMessage event
+  MODELAPI_EXPORT static void send(ObjectPtr theObject,
+                                   const std::string& theOldName,
+                                   const std::string& theNewName,
+                                   const void* theSender);
+
+  /// Creates an empty message
+  MODELAPI_EXPORT ModelAPI_ObjectRenamedMessage(const Events_ID theID, const void* theSender = 0);
+  /// The virtual destructor
+  MODELAPI_EXPORT virtual ~ModelAPI_ObjectRenamedMessage();
+
+  /// Returns an object
+  MODELAPI_EXPORT ObjectPtr object() const;
+  /// Sets an object
+  MODELAPI_EXPORT void setObject(ObjectPtr theObject);
+  /// Returns an old name
+  MODELAPI_EXPORT std::string oldName() const;
+  /// Sets an old name
+  MODELAPI_EXPORT void setOldName(const std::string& theOldName);
+  /// Returns a new name
+  MODELAPI_EXPORT std::string newName() const;
+  /// Sets a new name
+  MODELAPI_EXPORT void setNewName(const std::string& theNewName);
+};
+
 #endif
index 968c167696992d9599da1d20a57756b88352eff9..96e280436c70b86974115529e986bb812e6362dc 100644 (file)
@@ -8,12 +8,17 @@
 #include <pyconfig.h>
 
 #include <ParametersPlugin_EvalListener.h>
+#include <ParametersPlugin_Parameter.h>
 #include <ParametersPlugin_PyInterp.h>
 
 #include <Events_Error.h>
 
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Document.h>
 #include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
 #include <ModelAPI_Tools.h>
+
 #include <ModelAPI_AttributeDouble.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
@@ -26,6 +31,8 @@ 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);
 
   myInterp = std::shared_ptr<ParametersPlugin_PyInterp>(new ParametersPlugin_PyInterp());
   myInterp->initialize();
@@ -35,77 +42,18 @@ ParametersPlugin_EvalListener::~ParametersPlugin_EvalListener()
 {
 }
 
-void ParametersPlugin_EvalListener::processEvent(const std::shared_ptr<Events_Message>& theMessage)
+void ParametersPlugin_EvalListener::processEvent(
+    const std::shared_ptr<Events_Message>& theMessage)
 {
   if (!theMessage.get())
     return;
 
   const Events_ID kEvaluationEvent = ModelAPI_AttributeEvalMessage::eventId();
+  const Events_ID kObjectRenamedEvent = ModelAPI_ObjectRenamedMessage::eventId();
   if (theMessage->eventID() == kEvaluationEvent) {
-    std::shared_ptr<ModelAPI_AttributeEvalMessage> aMessage =
-        std::dynamic_pointer_cast<ModelAPI_AttributeEvalMessage>(theMessage);
-
-    // Double
-    AttributeDoublePtr aDoubleAttribute =
-        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(aMessage->attribute());
-    if (aDoubleAttribute.get()) {
-      std::string anError;
-      double aValue = evaluate(aDoubleAttribute->text(), anError);
-      if (anError.empty()) {
-        aDoubleAttribute->setValue(aValue);
-        aDoubleAttribute->setExpressionInvalid(false);
-      } else { // set feature as invalid-parameter arguments
-        aDoubleAttribute->setExpressionInvalid(true);
-      }
-    }
-
-    // Point
-    AttributePointPtr aPointAttribute =
-        std::dynamic_pointer_cast<GeomDataAPI_Point>(aMessage->attribute());
-    if (aPointAttribute.get()) {
-      std::string anError[3];
-      double aValue[3] = {
-          evaluate(aPointAttribute->textX(), anError[0]),
-          evaluate(aPointAttribute->textY(), anError[1]),
-          evaluate(aPointAttribute->textZ(), anError[2])
-      };
-      bool isValid[3] = {
-          anError[0].empty(),
-          anError[1].empty(),
-          anError[2].empty()
-      };
-      aPointAttribute->setExpressionInvalid(0, !isValid[0]);
-      aPointAttribute->setExpressionInvalid(1, !isValid[1]);
-      aPointAttribute->setExpressionInvalid(2, !isValid[2]);
-
-      aPointAttribute->setValue(
-          isValid[0] ? aValue[0] : aPointAttribute->x(),
-          isValid[1] ? aValue[1] : aPointAttribute->y(),
-          isValid[2] ? aValue[2] : aPointAttribute->z()
-      );
-    }
-
-    // Point2D
-    AttributePoint2DPtr aPoint2DAttribute =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMessage->attribute());
-    if (aPoint2DAttribute.get()) {
-      std::string anError[2];
-      double aValue[2] = {
-          evaluate(aPoint2DAttribute->textX(), anError[0]),
-          evaluate(aPoint2DAttribute->textY(), anError[1])
-      };
-      bool isValid[2] = {
-          anError[0].empty(),
-          anError[1].empty()
-      };
-      aPoint2DAttribute->setExpressionInvalid(0, !isValid[0]);
-      aPoint2DAttribute->setExpressionInvalid(1, !isValid[1]);
-
-      aPoint2DAttribute->setValue(
-          isValid[0] ? aValue[0] : aPoint2DAttribute->x(),
-          isValid[1] ? aValue[1] : aPoint2DAttribute->y()
-      );
-    }
+    processEvaluationEvent(theMessage);
+  } else if (theMessage->eventID() == kObjectRenamedEvent) {
+    processObjectRenamedEvent(theMessage);
   } else {
     Events_Error::send(std::string("ParametersPlugin python interpreter, unhandled message caught: ")
                        + theMessage->eventID().eventText());
@@ -134,3 +82,262 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression,
   myInterp->clearLocalContext();
   return result;
 }
+
+void ParametersPlugin_EvalListener::processEvaluationEvent(
+    const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::shared_ptr<ModelAPI_AttributeEvalMessage> aMessage =
+      std::dynamic_pointer_cast<ModelAPI_AttributeEvalMessage>(theMessage);
+
+  // Double
+  AttributeDoublePtr aDoubleAttribute =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(aMessage->attribute());
+  if (aDoubleAttribute.get()) {
+    std::string anError;
+    double aValue = evaluate(aDoubleAttribute->text(), anError);
+    if (anError.empty()) {
+      aDoubleAttribute->setValue(aValue);
+      aDoubleAttribute->setExpressionInvalid(false);
+    } else { // set feature as invalid-parameter arguments
+      aDoubleAttribute->setExpressionInvalid(true);
+    }
+  }
+
+  // Point
+  AttributePointPtr aPointAttribute =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(aMessage->attribute());
+  if (aPointAttribute.get()) {
+    std::string anError[3];
+    double aValue[3] = {
+        evaluate(aPointAttribute->textX(), anError[0]),
+        evaluate(aPointAttribute->textY(), anError[1]),
+        evaluate(aPointAttribute->textZ(), anError[2])
+    };
+    bool isValid[3] = {
+        anError[0].empty(),
+        anError[1].empty(),
+        anError[2].empty()
+    };
+    aPointAttribute->setExpressionInvalid(0, !isValid[0]);
+    aPointAttribute->setExpressionInvalid(1, !isValid[1]);
+    aPointAttribute->setExpressionInvalid(2, !isValid[2]);
+
+    aPointAttribute->setValue(
+        isValid[0] ? aValue[0] : aPointAttribute->x(),
+        isValid[1] ? aValue[1] : aPointAttribute->y(),
+        isValid[2] ? aValue[2] : aPointAttribute->z()
+    );
+  }
+
+  // Point2D
+  AttributePoint2DPtr aPoint2DAttribute =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMessage->attribute());
+  if (aPoint2DAttribute.get()) {
+    std::string anError[2];
+    double aValue[2] = {
+        evaluate(aPoint2DAttribute->textX(), anError[0]),
+        evaluate(aPoint2DAttribute->textY(), anError[1])
+    };
+    bool isValid[2] = {
+        anError[0].empty(),
+        anError[1].empty()
+    };
+    aPoint2DAttribute->setExpressionInvalid(0, !isValid[0]);
+    aPoint2DAttribute->setExpressionInvalid(1, !isValid[1]);
+
+    aPoint2DAttribute->setValue(
+        isValid[0] ? aValue[0] : aPoint2DAttribute->x(),
+        isValid[1] ? aValue[1] : aPoint2DAttribute->y()
+    );
+  }
+}
+
+std::string ParametersPlugin_EvalListener::renameInPythonExpression(
+    const std::string& theExpression,
+    const std::string& theOldName,
+    const std::string& theNewName)
+{
+  std::string anExpressionString = theExpression;
+
+  std::list<std::pair<int, int> > aPositions =
+      myInterp->positions(anExpressionString, theOldName);
+
+  if (aPositions.empty())
+    return anExpressionString;
+
+  std::map<int, std::list<int> > aLines;
+  std::list<std::pair<int, int> >::const_iterator it = aPositions.begin();
+  for (; it != aPositions.end(); ++it)
+    aLines[it->first].push_back(it->second);
+
+  // Start renaming from the end to keep indexes if theNewName is longer then theOldName
+  std::map<int, std::list<int> >::const_reverse_iterator ritLine = aLines.rbegin();
+  for (; ritLine != aLines.rend(); ++ritLine) {
+    // Calculate the start of the line (find the aLineNo occurrence of "\n" )
+    int aLineNo = ritLine->first - 1;
+    size_t aLineStart = 0;
+    for (int i = 0; i < aLineNo; ++i)
+      aLineStart = anExpressionString.find("\n", aLineStart) + 1;
+
+    const std::list<int>& aColOffsets = ritLine->second;
+    std::list<int>::const_reverse_iterator ritOffset = aColOffsets.rbegin();
+    for (; ritOffset != aColOffsets.rend(); ++ritOffset) {
+      int anOffset = *ritOffset;
+      anExpressionString.replace(aLineStart + anOffset, theOldName.size(), theNewName);
+    }
+  }
+
+  return anExpressionString;
+}
+
+void ParametersPlugin_EvalListener::renameInParameter(
+    std::shared_ptr<ParametersPlugin_Parameter> theParameter,
+    const std::string& theOldName,
+    const std::string& theNewName)
+{
+  std::shared_ptr<ModelAPI_AttributeString> anExpressionAttribute =
+      theParameter->string(ParametersPlugin_Parameter::EXPRESSION_ID());
+
+  std::string anExpressionString = anExpressionAttribute->value();
+  anExpressionString = renameInPythonExpression(anExpressionString,
+                                                theOldName,
+                                                theNewName);
+  anExpressionAttribute->setValue(anExpressionString);
+}
+
+void ParametersPlugin_EvalListener::renameInAttribute(
+    std::shared_ptr<ModelAPI_Attribute> theAttribute,
+    const std::string& theOldName,
+    const std::string& theNewName)
+{
+  // Double
+  AttributeDoublePtr aDoubleAttribute =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+  if (aDoubleAttribute.get()) {
+    std::string anExpressionString = aDoubleAttribute->text();
+    anExpressionString = renameInPythonExpression(anExpressionString,
+                                                  theOldName,
+                                                  theNewName);
+    aDoubleAttribute->setText(anExpressionString);
+  }
+
+  // Point
+  AttributePointPtr aPointAttribute =
+      std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+  if (aPointAttribute.get()) {
+    std::string anExpressionString[3] = {
+      aPointAttribute->textX(),
+      aPointAttribute->textY(),
+      aPointAttribute->textZ()
+    };
+    for (int i = 0; i < 3; ++i)
+      anExpressionString[i] = renameInPythonExpression(anExpressionString[i],
+                                                       theOldName,
+                                                       theNewName);
+    aPointAttribute->setText(anExpressionString[0],
+                             anExpressionString[1],
+                             anExpressionString[2]);
+  }
+
+  // Point2D
+  AttributePoint2DPtr aPoint2DAttribute =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  if (aPoint2DAttribute.get()) {
+    std::string anExpressionString[2] = {
+      aPoint2DAttribute->textX(),
+      aPoint2DAttribute->textY()
+    };
+    for (int i = 0; i < 2; ++i)
+      anExpressionString[i] = renameInPythonExpression(anExpressionString[i],
+                                                       theOldName,
+                                                       theNewName);
+    aPoint2DAttribute->setText(anExpressionString[0],
+                               anExpressionString[1]);
+  }
+}
+
+void ParametersPlugin_EvalListener::processObjectRenamedEvent(
+    const std::shared_ptr<Events_Message>& theMessage)
+{
+  std::shared_ptr<ModelAPI_ObjectRenamedMessage> aMessage =
+      std::dynamic_pointer_cast<ModelAPI_ObjectRenamedMessage>(theMessage);
+
+  if (!aMessage.get() || aMessage->oldName().empty() || aMessage->newName().empty())
+    return;
+
+  // check that the renamed object is a result 
+  std::shared_ptr<ModelAPI_ResultParameter> aResultParameter =
+      std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aMessage->object());
+  if (!aResultParameter.get()) 
+    return;
+  
+  // get parameter feature for the result
+  std::shared_ptr<ModelAPI_Feature> aFeature = aResultParameter->document()->feature(aResultParameter);
+  std::shared_ptr<ParametersPlugin_Parameter> aParameter =
+      std::dynamic_pointer_cast<ParametersPlugin_Parameter>(aFeature);
+  if (!aParameter.get())
+    return;
+
+  // rename a parameter attributes
+  // short way:
+  //aParameter->string(ParametersPlugin_Parameter::VARIABLE_ID())->setValue(aMessage->newName());
+  //aParameter->execute();
+  // manual way:
+  aParameter->data()->setName(aMessage->newName());
+  aParameter->string(ParametersPlugin_Parameter::VARIABLE_ID())->setValue(aMessage->newName());
+
+  // List of documents to process
+  std::list<DocumentPtr> aDocList;
+  SessionPtr aSession = ModelAPI_Session::get();
+  DocumentPtr aDocument = aSession->activeDocument();
+  DocumentPtr aRootDocument = aSession->moduleDocument();
+  aDocList.push_back(aDocument);
+  if (aDocument != aRootDocument) {
+    aDocList.push_back(aRootDocument);
+  }
+
+  // Find parameters and rename in its expressions
+  for (std::list<DocumentPtr>::const_iterator aDicumentIt = aDocList.begin(); 
+       aDicumentIt != aDocList.end(); ++aDicumentIt) {
+    const DocumentPtr& aDocument = *aDicumentIt;
+    const int aSize = aDocument->size(ModelAPI_ResultParameter::group());
+    for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+      ResultParameterPtr aResultParameter =
+          std::dynamic_pointer_cast<ModelAPI_ResultParameter>(
+              aDocument->object(ModelAPI_ResultParameter::group(), anIndex));
+      if (!aResultParameter.get())
+        continue;
+
+      std::shared_ptr<ParametersPlugin_Parameter> aParameter =
+          std::dynamic_pointer_cast<ParametersPlugin_Parameter>(
+              aDocument->feature(aResultParameter));
+      if (!aParameter.get())
+        continue;
+
+      // Rename
+      renameInParameter(aParameter, aMessage->oldName(), aMessage->newName());
+    }
+  }
+
+  // Find all features
+  for (std::list<DocumentPtr>::const_iterator aDicumentIt = aDocList.begin(); 
+       aDicumentIt != aDocList.end(); ++aDicumentIt) {
+    const DocumentPtr& aDocument = *aDicumentIt;
+    std::list<FeaturePtr> aFeatures = aDocument->allFeatures();
+    std::list<FeaturePtr>::iterator aFeatureIt = aFeatures.begin();
+    for (; aFeatureIt != aFeatures.end(); ++aFeatureIt) {
+      const FeaturePtr& aFeature = *aFeatureIt;
+      
+      // Find all attributes
+      std::list<AttributePtr> anAttributes = aFeature->data()->attributes(std::string());
+      std::list<AttributePtr>::const_iterator anAttributeIt = anAttributes.begin();
+      for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
+        const AttributePtr& anAttribute = *anAttributeIt;
+
+        // Rename
+        renameInAttribute(anAttribute, aMessage->oldName(), aMessage->newName());
+      }
+    }
+  }
+}
+
index 50c5727f2e195f097f48642872c0adea63b6aefc..bd9e6385fd9a34b7be362dff2253ca0486fdd2b1 100644 (file)
@@ -11,6 +11,8 @@
 #include <ParametersPlugin.h>
 #include <Events_Loop.h>
 
+class ModelAPI_Attribute;
+class ParametersPlugin_Parameter;
 class ParametersPlugin_PyInterp;
 
 class PARAMETERSPLUGIN_EXPORT ParametersPlugin_EvalListener : public Events_Listener
@@ -22,8 +24,20 @@ class PARAMETERSPLUGIN_EXPORT ParametersPlugin_EvalListener : public Events_List
   virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
  protected:
-  double evaluate(const std::string& theExpression,
-                  std::string& theError) ;
+  double evaluate(const std::string& theExpression, std::string& theError);
+
+  void processEvaluationEvent(const std::shared_ptr<Events_Message>& theMessage);
+  void processObjectRenamedEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  std::string renameInPythonExpression(const std::string& theExpression,
+                                       const std::string& theOldName,
+                                       const std::string& theNewName);
+  void renameInParameter(std::shared_ptr<ParametersPlugin_Parameter> theParameter,
+                         const std::string& theOldName,
+                         const std::string& theNewName);
+  void renameInAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute,
+                         const std::string& theOldName,
+                         const std::string& theNewName);
 
  private:
   std::shared_ptr<ParametersPlugin_PyInterp> myInterp;
index 53659f23fdbd89ab61bc1438f5a380aa2575e536..021f285527d64c30a06933c345433a28eeff2c68 100644 (file)
@@ -19,6 +19,57 @@ ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp()
 {
 }
 
+const char* aSearchCode =
+  "import ast\n"
+  "class FindName(ast.NodeVisitor):\n"
+  "    def __init__(self, name):\n"
+  "        self.name = name\n"
+  "    def visit_Name(self, node):\n"
+  "        if node.id == self.name:\n"
+  "            positions.append((node.lineno, node.col_offset))\n"
+  "FindName(name).visit(ast.parse(expression))";
+
+std::list<std::pair<int, int> >
+ParametersPlugin_PyInterp::positions(const std::string& theExpression,
+                                     const std::string& theName)
+{
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+
+  std::list<std::pair<int, int> > aResult;
+
+  // prepare a context
+  PyObject* aContext = PyDict_New();
+  PyObject* aBuiltinModule = PyImport_AddModule("__builtin__");
+  PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule);
+
+  // extend aContext with variables 
+  PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str()));
+  PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str()));
+  PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]"));
+
+  // run the search code
+  PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext);
+  Py_XDECREF(aExecResult);
+
+  // receive results from context
+  PyObject* aPositions = PyDict_GetItemString(aContext, "positions");
+  for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) {
+    PyObject* aPosition = PyList_GetItem(aPositions, anIndex);
+    PyObject* aLineNo = PyTuple_GetItem(aPosition, 0);
+    PyObject* aColOffset = PyTuple_GetItem(aPosition, 1);
+
+    aResult.push_back(
+        std::pair<int, int>((int)PyInt_AsLong(aLineNo),
+                            (int)PyInt_AsLong(aColOffset)));
+  }
+
+  // TODO(spo): after this refCount of the variable is not 0. Is there memory leak?
+  Py_DECREF(aContext);
+
+  return aResult;
+}
+
+
 std::list<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
 {
   PyLockWrapper lck; // Acquire GIL until the end of the method
index 0a631f6e22f42ce3e30251ad9869bc29efd3f12a..32b5c6d31a7fc19de72e355af8290405a7ad7722 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <list>
 #include <string>
+#include <utility>
 
 class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp
 {
@@ -20,6 +21,8 @@ class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp
   ParametersPlugin_PyInterp();
   virtual ~ParametersPlugin_PyInterp();
 
+  std::list<std::pair<int, int> > positions(const std::string& theExpression,
+                                            const std::string& theName);
   std::list<std::string> compile(const std::string&);
   void extendLocalContext(const std::list<std::string>&);
   void clearLocalContext();