From: spo Date: Fri, 5 Jun 2015 10:45:13 +0000 (+0300) Subject: Issue #588: Renaming a parameter used in an expression X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=5a66c19049fef6412d2c12b229720057c1476fd3;p=modules%2Fshaper.git Issue #588: Renaming a parameter used in an expression --- diff --git a/src/Model/Model_Data.cpp b/src/Model/Model_Data.cpp index 05b276c97..1c6e6660e 100644 --- a/src/Model/Model_Data.cpp +++ b/src/Model/Model_Data.cpp @@ -75,6 +75,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()); @@ -84,6 +85,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) diff --git a/src/Model/Model_Update.cpp b/src/Model/Model_Update.cpp index e937f38ef..de514b6bf 100644 --- a/src/Model/Model_Update.cpp +++ b/src/Model/Model_Update.cpp @@ -277,13 +277,13 @@ void Model_Update::updateArguments(FeaturePtr theFeature) { theFeature->data()->attributes(ModelAPI_AttributeDouble::typeId()); std::list::iterator aDoubleIter = aDoubles.begin(); for(; aDoubleIter != aDoubles.end(); aDoubleIter++) { - AttributeDoublePtr aDouble = + AttributeDoublePtr aDoubleAttribute = std::dynamic_pointer_cast(*aDoubleIter); - if (aDouble.get() && !aDouble->text().empty()) { + if (aDoubleAttribute.get() && !aDoubleAttribute->text().empty()) { if (myIsParamUpdated) { - ModelAPI_AttributeEvalMessage::send(aDouble, this); + ModelAPI_AttributeEvalMessage::send(aDoubleAttribute, this); } - if (aDouble->expressionInvalid()) { + if (aDoubleAttribute->expressionInvalid()) { aState = ModelAPI_StateInvalidArgument; } } diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index dbd088755..7c81efe53 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -108,7 +108,7 @@ void ModelAPI_DocumentCreatedMessage::setDocument(DocumentPtr theDocument) } ModelAPI_AttributeEvalMessage::ModelAPI_AttributeEvalMessage(const Events_ID theID, - const void* theSender) + const void* theSender) : Events_Message(theID, theSender) { @@ -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 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; +} diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index e41c0999f..8b880e227 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -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) @@ -112,7 +114,7 @@ public: // TODO(sbh): Move this message into a separate package, like "GuiAPI" /// Contains the state information about the feature: is it enabled or disabled. -class ModelAPI_FeatureStateMessage : public Events_Message +class MODELAPI_EXPORT ModelAPI_FeatureStateMessage : public Events_Message { public: /// Creates an empty message @@ -142,7 +144,7 @@ public: }; /// Message that document (Part, PartSet) was created -class ModelAPI_DocumentCreatedMessage : public Events_Message +class MODELAPI_EXPORT ModelAPI_DocumentCreatedMessage : public Events_Message { DocumentPtr myDocument; @@ -165,7 +167,7 @@ class ModelAPI_DocumentCreatedMessage : public Events_Message }; /// Message that attribute text should be evaluated in the attribute value -class ModelAPI_AttributeEvalMessage : public Events_Message +class MODELAPI_EXPORT ModelAPI_AttributeEvalMessage : public Events_Message { AttributePtr myAttribute; @@ -181,8 +183,7 @@ class ModelAPI_AttributeEvalMessage : public Events_Message /// Useful method that creates and sends the AttributeEvalMessage event MODELAPI_EXPORT static void send(AttributePtr theAttribute, const void* theSender) { - std::shared_ptr aMessage = - std::shared_ptr( + std::shared_ptr aMessage( new ModelAPI_AttributeEvalMessage(eventId(), theSender)); aMessage->setAttribute(theAttribute); Events_Loop::loop()->send(aMessage); @@ -199,4 +200,45 @@ class ModelAPI_AttributeEvalMessage : public Events_Message MODELAPI_EXPORT void setAttribute(AttributePtr theAttribute); }; +/// Message that the object is renamed +class MODELAPI_EXPORT 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 diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index 9bea2d9cd..7b1f26bb0 100644 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -23,8 +23,9 @@ MODELAPI_EXPORT std::shared_ptr shape(const ResultPtr& theResult) * in the root document (PartSet). If found, set it value in the \param outValue * and returns true. */ -MODELAPI_EXPORT bool findVariable(const std::string& theName, double& outValue, - ResultParameterPtr& theParam); +MODELAPI_EXPORT bool findVariable(const std::string& theName, + double& outValue, + ResultParameterPtr& theParam); /*! * Returns the values of the next random color. The values are in range [0, 255] diff --git a/src/NewGeom/NewGeom_Module.cpp b/src/NewGeom/NewGeom_Module.cpp index 8265e654c..e398f96ce 100644 --- a/src/NewGeom/NewGeom_Module.cpp +++ b/src/NewGeom/NewGeom_Module.cpp @@ -49,7 +49,7 @@ NewGeom_EXPORT CAM_Module* createModule() return new NewGeom_Module(); } -NewGeom_EXPORT char* getModuleVersion() +NewGeom_EXPORT const char* getModuleVersion() { return "0.0"; } diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp index 968c16769..ae849a983 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp @@ -8,24 +8,35 @@ #include #include +#include #include #include +#include +#include #include +#include #include + #include #include #include #include #include +#include + +//debug +#include 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(new ParametersPlugin_PyInterp()); myInterp->initialize(); @@ -35,77 +46,18 @@ ParametersPlugin_EvalListener::~ParametersPlugin_EvalListener() { } -void ParametersPlugin_EvalListener::processEvent(const std::shared_ptr& theMessage) +void ParametersPlugin_EvalListener::processEvent( + const std::shared_ptr& 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 aMessage = - std::dynamic_pointer_cast(theMessage); - - // Double - AttributeDoublePtr aDoubleAttribute = - std::dynamic_pointer_cast(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(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(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 +86,207 @@ double ParametersPlugin_EvalListener::evaluate(const std::string& theExpression, myInterp->clearLocalContext(); return result; } + +void ParametersPlugin_EvalListener::processEvaluationEvent( + const std::shared_ptr& theMessage) +{ + std::shared_ptr aMessage = + std::dynamic_pointer_cast(theMessage); + + // Double + AttributeDoublePtr aDoubleAttribute = + std::dynamic_pointer_cast(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(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(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 > aPositions = + myInterp->positions(anExpressionString, theOldName); + + if (aPositions.empty()) + return anExpressionString; + + std::map > aLines; + std::list >::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 >::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& aColOffsets = ritLine->second; + std::list::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 theParameter, + const std::string& theOldName, + const std::string& theNewName) +{ + std::shared_ptr anExpressionAttribute = + theParameter->string(ParametersPlugin_Parameter::EXPRESSION_ID()); + + std::string anExpressionString = anExpressionAttribute->value(); + anExpressionString = renameInPythonExpression(anExpressionString, + theOldName, + theNewName); + anExpressionAttribute->setValue(anExpressionString); +} + +void renameInAttribute(std::shared_ptr theAttribute, + const std::string& theOldName, + const std::string& theNewName) +{ + // TODO: implement + + // dynamic_cast(attribute) + // rename(attribute) +} + +void ParametersPlugin_EvalListener::processObjectRenamedEvent( + const std::shared_ptr& theMessage) +{ + std::shared_ptr aMessage = + std::dynamic_pointer_cast(theMessage); + + // List of documents to process + std::list 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 + for (std::list::const_iterator it = aDocList.begin(); it != aDocList.end(); ++it) { + DocumentPtr aDocument = *it; + + for (int anIndex = 0, aSize = aDocument->size(ModelAPI_ResultParameter::group()); + anIndex < aSize; ++anIndex) { + std::shared_ptr aResultParameter = + std::dynamic_pointer_cast( + aDocument->object(ModelAPI_ResultParameter::group(), anIndex)); + if (!aResultParameter.get()) + continue; + + std::shared_ptr aParameter = + std::dynamic_pointer_cast( + aDocument->feature(aResultParameter)); + if (!aParameter.get()) + continue; + +// std::cout << "Rename expression of parameter " << aParameter->string(ParametersPlugin_Parameter::VARIABLE_ID())->value() +// << " (" << aMessage->oldName() << ", " << aMessage->newName() << ")" << std::endl; + + // Rename + renameInParameter(aParameter, aMessage->oldName(), aMessage->newName()); + } + } +// TODO: implement renaming in attributes for the next version +/* + // Find features + for (std::list::const_iterator it = aDocList.begin(); it != aDocList.end(); ++it) { + DocumentPtr aDocument = *it; + for (int anIndex = 0, aSize = aDocument->size(ModelAPI_Feature::group()); + anIndex < aSize; ++anIndex) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast( + aDocument->object(ModelAPI_Feature::group(), anIndex)); + if (!aFeature.get()) + continue; + + std::list > anAttributes = + aFeature->data()->attributes(std::string()); + + std::list >::const_iterator it = + anAttributes.begin(); + for (; it != anAttributes.end(); ++it) { + + std::cout << "Rename expression of attribute " << aFeature->data()->id(*it) + << " (" << aMessage->oldName() << ", " << aMessage->newName() << ")" << std::endl; + + // Rename + renameInAttribute(*it, aMessage->oldName(), aMessage->newName()); + } + } + } +*/ +} + diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.h b/src/ParametersPlugin/ParametersPlugin_EvalListener.h index 50c5727f2..cc754a0d8 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.h +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.h @@ -11,6 +11,7 @@ #include #include +class ParametersPlugin_Parameter; class ParametersPlugin_PyInterp; class PARAMETERSPLUGIN_EXPORT ParametersPlugin_EvalListener : public Events_Listener @@ -22,8 +23,17 @@ class PARAMETERSPLUGIN_EXPORT ParametersPlugin_EvalListener : public Events_List virtual void processEvent(const std::shared_ptr& 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& theMessage); + void processObjectRenamedEvent(const std::shared_ptr& theMessage); + + std::string renameInPythonExpression(const std::string& theExpression, + const std::string& theOldName, + const std::string& theNewName); + void renameInParameter(std::shared_ptr theParameter, + const std::string& theOldName, + const std::string& theNewName); private: std::shared_ptr myInterp; diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp index 9d64cef32..dcf69dda6 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp @@ -48,7 +48,7 @@ void ParametersPlugin_Parameter::attributeChanged(const std::string& theID) if (theID == EXPRESSION_ID()) { // recompute only on change of the expression ResultParameterPtr aParam = document()->createParameter(data()); - std::string anExpression = string(EXPRESSION_ID())->value(); + std::string anExpression = this->string(EXPRESSION_ID())->value(); if(anExpression.empty()) { // clear error/result if the expression is empty setError("", false); @@ -57,7 +57,7 @@ void ParametersPlugin_Parameter::attributeChanged(const std::string& theID) std::string outErrorMessage; double aValue = evaluate(anExpression, outErrorMessage); // Name - std::string aName = string(VARIABLE_ID())->value(); + std::string aName = this->string(VARIABLE_ID())->value(); std::ostringstream sstream; sstream << aValue; std::string aParamValue = sstream.str(); @@ -88,7 +88,6 @@ void ParametersPlugin_Parameter::execute() double ParametersPlugin_Parameter::evaluate(const std::string& theExpression, std::string& theError) { - std::list anExprParams = myInterp->compile(theExpression); // find expression's params in the model std::list aContext; diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp index 53659f23f..ae82e5dfc 100644 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp +++ b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp @@ -10,6 +10,8 @@ #include #include +#include + ParametersPlugin_PyInterp::ParametersPlugin_PyInterp() : PyInterp_Interp() { @@ -19,6 +21,54 @@ 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 > +ParametersPlugin_PyInterp::positions(const std::string& theExpression, + const std::string& theName) +{ + PyLockWrapper lck; // Acquire GIL until the end of the method + + std::list > aResult; + + PyObject* aContext = PyDict_New(); + + PyObject* aBuiltinModule = PyImport_AddModule("__builtin__"); + PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule); + Py_DECREF(aBuiltinModule); + + PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str())); + PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str())); + PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]")); + + PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext); + Py_XDECREF(aExecResult); + + 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)PyInt_AsLong(aLineNo), + (int)PyInt_AsLong(aColOffset))); + } + + Py_DECREF(aContext); + + return aResult; +} + + std::list ParametersPlugin_PyInterp::compile(const std::string& theExpression) { PyLockWrapper lck; // Acquire GIL until the end of the method diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.h b/src/ParametersPlugin/ParametersPlugin_PyInterp.h index 0a631f6e2..32b5c6d31 100644 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.h +++ b/src/ParametersPlugin/ParametersPlugin_PyInterp.h @@ -13,6 +13,7 @@ #include #include +#include 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 > positions(const std::string& theExpression, + const std::string& theName); std::list compile(const std::string&); void extendLocalContext(const std::list&); void clearLocalContext();