plcopen/plcopen.py
changeset 566 6014ef82a98a
parent 557 0f591ac019f3
child 576 3f2024f30553
--- a/plcopen/plcopen.py	Fri Sep 30 17:16:02 2011 +0200
+++ b/plcopen/plcopen.py	Sun Oct 09 19:51:14 2011 +0200
@@ -34,6 +34,12 @@
             "Output" : "outputVars", "InOut" : "inOutVars", "External" : "externalVars",
             "Global" : "globalVars", "Access" : "accessVars"}
 
+searchResultVarTypes = {
+    "inputVars": "var_input",
+    "outputVars": "var_output",
+    "inOutVars": "var_inout"
+}
+
 """
 Define in which order var types must be displayed
 """
@@ -96,7 +102,25 @@
         if self.y_min is not None and self.y_max is not None:
             height = self.y_max - self.y_min
         return self.x_min, self.y_min, width, height
-            
+
+def TextLenInRowColumn(text):
+    if text == "":
+        return (0, 0)
+    lines = text.split("\n")
+    return len(lines) - 1, len(lines[-1])
+
+def TestTextElement(text, criteria):
+    lines = text.splitlines()
+    if not criteria["case_sensitive"]:
+        text = text.upper()
+    test_result = []
+    result = criteria["pattern"].search(text)
+    while result is not None:
+        start = TextLenInRowColumn(text[:result.start()])
+        end = TextLenInRowColumn(text[:result.end() - 1])
+        test_result.append((start, end, "\n".join(lines[start[0]:end[0] + 1])))
+        result = criteria["pattern"].search(text, result.end())
+    return test_result
 
 PLCOpenClasses = GenerateClassesFromXSD(os.path.join(os.path.split(__file__)[0], "tc6_xml_v201.xsd"))
 
@@ -127,6 +151,10 @@
             result = address_model.search(self.text, startpos)
     setattr(cls, "updateElementAddress", updateElementAddress)
     
+    def Search(self, criteria, parent_infos):
+        return [(tuple(parent_infos),) + result for result in TestTextElement(self.gettext(), criteria)]
+    setattr(cls, "Search", Search)
+    
 cls = PLCOpenClasses.get("project", None)
 if cls:
     cls.singleLineAttributes = False
@@ -677,6 +705,13 @@
         return True
     setattr(cls, "IsLocatableType", IsLocatableType)
 
+    def Search(self, criteria, parent_infos=[]):
+        result = self.types.Search(criteria, parent_infos)
+        for configuration in self.instances.configurations.getconfiguration():
+            result.extend(configuration.Search(criteria, parent_infos))
+        return result
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("project_fileHeader", None)
 if cls:
     cls.singleLineAttributes = False
@@ -746,61 +781,99 @@
         return 0, 0
     setattr(cls, "getscaling", getscaling)
 
+def _Search(attributes, criteria, parent_infos):
+    search_result = []
+    for attr, value in attributes:
+        if value is not None:
+            search_result.extend([(tuple(parent_infos + [attr]),) + result for result in TestTextElement(value, criteria)])
+    return search_result
+
+def _updateConfigurationResourceElementName(self, old_name, new_name):
+    for varlist in self.getglobalVars():
+        for var in varlist.getvariable():
+            var_address = var.getaddress()
+            if var_address is not None:
+                if var_address == old_name:
+                    var.setaddress(new_name)
+                if var.getname() == old_name:
+                    var.setname(new_name)
+
+def _updateConfigurationResourceElementAddress(self, address_model, new_leading):
+    for varlist in self.getglobalVars():
+        for var in varlist.getvariable():
+            var_address = var.getaddress()
+            if var_address is not None:
+                var.setaddress(update_address(var_address, address_model, new_leading))
+
+def _removeConfigurationResourceVariableByAddress(self, address):
+    for varlist in self.getglobalVars():
+        variables = varlist.getvariable()
+        for i in xrange(len(variables)-1, -1, -1):
+            if variables[i].getaddress() == address:
+                variables.pop(i)
+
+def _removeConfigurationResourceVariableByFilter(self, address_model):
+    for varlist in self.getglobalVars():
+        variables = varlist.getvariable()
+        for i in xrange(len(variables)-1, -1, -1):
+            var_address = variables[i].getaddress()
+            if var_address is not None:
+                result = address_model.match(var_address)
+                if result is not None:
+                    variables.pop(i)
+
+def _SearchInConfigurationResource(self, criteria, parent_infos=[]):
+    search_result = []
+    for result in TestTextElement(self.getname(), criteria):
+        search_result.append((tuple(parent_infos + ["name"]),) + result)
+    var_number = 0
+    for varlist in self.getglobalVars():
+        variable_type = searchResultVarTypes.get("globalVars", "var_local")
+        variables = varlist.getvariable()
+        for modifier, has_modifier in [("constant", varlist.getconstant()),
+                                       ("retain", varlist.getretain()),
+                                       ("non_retain", varlist.getnonretain())]:
+            if has_modifier:
+                for result in TestTextElement(modifier, criteria):
+                    search_result.append((tuple(parent_infos + [variable_type, (var_number, var_number + len(variables)), modifier]),) + result)
+                break
+        for variable in variables:
+            search_result.extend(variable.Search(criteria, parent_infos + [variable_type, var_number]))
+            var_number += 1
+    return search_result
+
 cls = PLCOpenClasses.get("configurations_configuration", None)
 if cls:
     def updateElementName(self, old_name, new_name):
-        for varlist in self.getglobalVars():
-            for var in varlist.getvariable():
-                var_address = var.getaddress()
-                if var_address is not None:
-                    if var_address == old_name:
-                        var.setaddress(new_name)
-                    if var.getname() == old_name:
-                        var.setname(new_name)
+        _updateConfigurationResourceElementName(self, old_name, new_name)
         for resource in self.getresource():
             resource.updateElementName(old_name, new_name)
     setattr(cls, "updateElementName", updateElementName)
 
     def updateElementAddress(self, address_model, new_leading):
-        for varlist in self.getglobalVars():
-            for var in varlist.getvariable():
-                var_address = var.getaddress()
-                if var_address is not None:
-                    var.setaddress(update_address(var_address, address_model, new_leading))
+        _updateConfigurationResourceElementAddress(self, address_model, new_leading)
         for resource in self.getresource():
             resource.updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
-    def removeVariableByAddress(self, address):
-        for varlist in self.getglobalVars():
-            variables = varlist.getvariable()
-            for i in xrange(len(variables)-1, -1, -1):
-                if variables[i].getaddress() == address:
-                    variables.pop(i)
-    setattr(cls, "removeVariableByAddress", removeVariableByAddress)
-
-    def removeVariableByFilter(self, address_model):
-        for varlist in self.getglobalVars():
-            variables = varlist.getvariable()
-            for i in xrange(len(variables)-1, -1, -1):
-                var_address = variables[i].getaddress()
-                if var_address is not None:
-                    result = address_model.match(var_address)
-                    if result is not None:
-                        variables.pop(i)
-    setattr(cls, "removeVariableByFilter", removeVariableByFilter)
-
+    setattr(cls, "removeVariableByAddress", _removeConfigurationResourceVariableByAddress)
+    setattr(cls, "removeVariableByFilter", _removeConfigurationResourceVariableByFilter)
+
+    def Search(self, criteria, parent_infos=[]):
+        search_result = []
+        parent_infos = parent_infos + ["C::%s" % self.getname()]
+        filter = criteria["filter"]
+        if filter == "all" or "configuration" in filter:
+            search_result = _SearchInConfigurationResource(self, criteria, parent_infos)
+            for resource in self.getresource():
+                search_result.extend(resource.Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
+    
 cls = PLCOpenClasses.get("configuration_resource", None)
 if cls:
     def updateElementName(self, old_name, new_name):
-        for varlist in self.getglobalVars():
-            for var in varlist.getvariable():
-                var_address = var.getaddress()
-                if var_address is not None:
-                    if var_address == old_name:
-                        var.setaddress(new_name)
-                    if var.getname() == old_name:
-                        var.setname(new_name)
+        _updateConfigurationResourceElementName(self, old_name, new_name)
         for instance in self.getpouInstance():
             instance.updateElementName(old_name, new_name)
         for task in self.gettask():
@@ -808,33 +881,35 @@
     setattr(cls, "updateElementName", updateElementName)
 
     def updateElementAddress(self, address_model, new_leading):
-        for varlist in self.getglobalVars():
-            for var in varlist.getvariable():
-                var_address = var.getaddress()
-                if var_address is not None:
-                    var.setaddress(update_address(var_address, address_model, new_leading))
+        _updateConfigurationResourceElementAddress(self, address_model, new_leading)
         for task in self.gettask():
             task.updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
-    def removeVariableByAddress(self, address):
-        for varlist in self.getglobalVars():
-            variables = varlist.getvariable()
-            for i in xrange(len(variables)-1, -1, -1):
-                if variables[i].getaddress() == address:
-                    variables.pop(i)
-    setattr(cls, "removeVariableByAddress", removeVariableByAddress)
-
-    def removeVariableByFilter(self, address_model):
-        for varlist in self.getglobalVars():
-            variables = varlist.getvariable()
-            for i in xrange(len(variables)-1, -1, -1):
-                var_address = variables[i].getaddress()
-                if var_address is not None:
-                    result = address_model.match(var_address)
-                    if result is not None:
-                        variables.pop(i)
-    setattr(cls, "removeVariableByFilter", removeVariableByFilter)
+    setattr(cls, "removeVariableByAddress", _removeConfigurationResourceVariableByAddress)
+    setattr(cls, "removeVariableByFilter", _removeConfigurationResourceVariableByFilter)
+
+    def Search(self, criteria, parent_infos=[]):
+        parent_infos = parent_infos[:-1] + ["R::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
+        search_result = _SearchInConfigurationResource(self, criteria, parent_infos)
+        task_number = 0
+        instance_number = 0
+        for task in self.gettask():
+            results = TestTextElement(task.getname(), criteria)
+            for result in results:
+                search_result.append((tuple(parent_infos + ["task", task_number, "name"]),) + result)
+            search_result.extend(task.Search(criteria, parent_infos + ["task", task_number]))
+            task_number += 1
+            for instance in task.getpouInstance():
+                search_result.extend(task.Search(criteria, parent_infos + ["instance", instance_number]))
+                for result in results:
+                    search_result.append((tuple(parent_infos + ["instance", instance_number, "task"]),) + result)
+                instance_number += 1
+        for instance in self.getpouInstance():
+            search_result.extend(instance.Search(criteria, parent_infos + ["instance", instance_number]))
+            instance_number += 1
+        return search_result
+    setattr(cls, "Search", Search)
 
 cls = PLCOpenClasses.get("resource_task", None)
 if cls:
@@ -878,6 +953,13 @@
             self.interval = update_address(self.interval, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        return _Search([("single", self.getsingle()), 
+                        ("interval", self.getinterval()),
+                        ("priority", str(self.getpriority()))],
+                       criteria, parent_infos)
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("pouInstance", None)
 if cls:
     def compatibility(self, tree):
@@ -890,6 +972,53 @@
             self.typeName = new_name
     setattr(cls, "updateElementName", updateElementName)
 
+    def Search(self, criteria, parent_infos=[]):
+        return _Search([("name", self.getname()), 
+                        ("type", self.gettypeName())],
+                       criteria, parent_infos)
+    setattr(cls, "Search", Search)
+
+cls = PLCOpenClasses.get("varListPlain_variable", None)
+if cls:
+    def gettypeAsText(self):
+        vartype_content = self.gettype().getcontent()
+        # Variable type is a user data type
+        if vartype_content["name"] == "derived":
+            return vartype_content["value"].getname()
+        # Variable type is a string type
+        elif vartype_content["name"] in ["string", "wstring"]:
+            return vartype_content["name"].upper()
+        # Variable type is an array
+        elif vartype_content["name"] == "array":
+            base_type = vartype_content["value"].baseType.getcontent()
+            # Array derived directly from a user defined type 
+            if base_type["name"] == "derived":
+                basetype_name = base_type["value"].getname()
+            # Array derived directly from a string type 
+            elif base_type["name"] in ["string", "wstring"]:
+                basetype_name = base_type["name"].upper()
+            # Array derived directly from an elementary type 
+            else:
+                basetype_name = base_type["name"]
+            return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (x.getlower(), x.getupper()), vartype_content["value"].getdimension())), basetype_name)
+        # Variable type is an elementary type
+        return vartype_content["name"]
+    setattr(cls, "gettypeAsText", gettypeAsText)
+    
+    def Search(self, criteria, parent_infos=[]):
+        search_result = _Search([("name", self.getname()), 
+                                 ("type", self.gettypeAsText()),
+                                 ("address", self.getaddress())],
+                                criteria, parent_infos)
+        initial = self.getinitialValue()
+        if initial is not None:
+            search_result.extend(_Search([("initial", initial.getvalue())], criteria, parent_infos))
+        doc = self.getdocumentation()
+        if doc is not None:
+            search_result.extend(doc.Search(criterias, parent_infos + ["documentation"]))
+        return search_result
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("project_types", None)
 if cls:
     def getdataTypeElements(self):
@@ -965,6 +1094,17 @@
             raise ValueError, _("\"%s\" POU doesn't exist !!!")%name
     setattr(cls, "removepouElement", removepouElement)
 
+    def Search(self, criteria, parent_infos=[]):
+        search_result = []
+        filter = criteria["filter"]
+        #if filter == "all" or "datatype" in filter:
+        #    for datatype in self.dataTypes.getdataType():
+        #        search_result.extend(datatype.Search(criteria, parent_infos))
+        for pou in self.pous.getpou():
+            search_result.extend(pou.Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("pous_pou", None)
 if cls:
     
@@ -1287,6 +1427,37 @@
                         if result is not None:
                             variables.pop(i)
     setattr(cls, "removeVariableByFilter", removeVariableByFilter)
+    
+    def Search(self, criteria, parent_infos=[]):
+        search_result = []
+        filter = criteria["filter"]
+        if filter == "all" or self.getpouType() in filter:
+            parent_infos = parent_infos + ["P::%s" % self.getname()]
+            for result in TestTextElement(self.getname(), criteria):
+                search_result.append((tuple(parent_infos + ["name"]),) + result)
+            if self.interface is not None:
+                var_number = 0
+                for content in self.interface.getcontent():
+                    variable_type = searchResultVarTypes.get(content["value"], "var_local")
+                    variables = content["value"].getvariable()
+                    for modifier, has_modifier in [("constant", content["value"].getconstant()),
+                                                   ("retain", content["value"].getretain()),
+                                                   ("non_retain", content["value"].getnonretain())]:
+                        if has_modifier:
+                            for result in TestTextElement(modifier, criteria):
+                                search_result.append((tuple(parent_infos + [variable_type, (var_number, var_number + len(variables)), modifier]),) + result)
+                            break
+                    for variable in variables:
+                        search_result.extend(variable.Search(criteria, parent_infos + [variable_type, var_number]))
+                        var_number += 1
+            if len(self.body) > 0:
+                search_result.extend(self.body[0].Search(criteria, parent_infos))
+            for action in self.getactionList():
+                search_result.extend(action.Search(criteria, parent_infos))
+            for transition in self.gettransitionList():
+                search_result.extend(transition.Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
 
 def setbodyType(self, type):
     if type == "IL":
@@ -1370,6 +1541,15 @@
         return False
     setattr(cls, "hasblock", hasblock)
 
+    def Search(self, criteria, parent_infos):
+        search_result = []
+        parent_infos = parent_infos[:-1] + ["T::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
+        for result in TestTextElement(self.getname(), criteria):
+            search_result.append((tuple(parent_infos + ["name"]),) + result)
+        search_result.extend(self.body.Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("actions_action", None)
 if cls:
     setattr(cls, "setbodyType", setbodyType)
@@ -1402,6 +1582,15 @@
         return False
     setattr(cls, "hasblock", hasblock)
 
+    def Search(self, criteria, parent_infos):
+        search_result = []
+        parent_infos = parent_infos[:-1] + ["A::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
+        for result in TestTextElement(self.getname(), criteria):
+            search_result.append((tuple(parent_infos + ["name"]),) + result)
+        search_result.extend(self.body.Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("body", None)
 if cls:
     cls.currentExecutionOrderId = 0
@@ -1569,6 +1758,16 @@
                 element["value"].updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        if self.content["name"] in ["IL", "ST"]:
+            search_result = self.content["value"].Search(criteria, parent_infos + ["body", 0])
+        else:
+            search_result = []
+            for element in self.content["value"].getcontent():
+                search_result.extend(element["value"].Search(criteria, parent_infos))
+        return search_result
+    setattr(cls, "Search", Search)
+
 def getx(self):
     return self.position.getx()
 
@@ -1681,6 +1880,9 @@
 def _updateElementAddress(self, address_model, new_leading):
     pass
 
+def _SearchInElement(self, criteria, parent_infos=[]):
+    return []
+
 _connectionsFunctions = {
     "bbox": {"none": _getBoundingBox,
              "single": _getBoundingBoxSingle,
@@ -1693,7 +1895,7 @@
                "multiple": _filterConnectionsMultiple},
     "update": {"none": lambda self, translation: {},
                "single": _updateConnectionsIdSingle,
-               "multiple": _updateConnectionsIdMultiple}
+               "multiple": _updateConnectionsIdMultiple},
 }
 
 def _initElementClass(name, classname, connectionPointInType="none"):
@@ -1710,6 +1912,7 @@
         setattr(cls, "translate", _connectionsFunctions["translate"][connectionPointInType])
         setattr(cls, "filterConnections", _connectionsFunctions["filter"][connectionPointInType])
         setattr(cls, "updateConnectionsId", _connectionsFunctions["update"][connectionPointInType])
+        setattr(cls, "Search", _SearchInElement)
     return cls
 
 def _getexecutionOrder(instance, specific_values):
@@ -1867,6 +2070,10 @@
         self.content.updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        return self.content.Search(criteria, parent_infos + ["comment", self.getlocalId(), "content"])
+    setattr(cls, "Search", Search)
+
 cls = _initElementClass("block", "fbdObjects_block")
 if cls:
     def getBoundingBox(self):
@@ -1912,6 +2119,20 @@
             _translateConnections(input.connectionPointIn, dx, dy)
     setattr(cls, "translate", translate)
 
+    def Search(self, criteria, parent_infos=[]):
+        parent_infos = parent_infos + ["block", self.getlocalId()]
+        search_result = _Search([("name", self.getinstanceName()),
+                                 ("type", self.gettypeName())],
+                                criteria, parent_infos)
+        for i, variable in enumerate(self.inputVariables.getvariable()):
+            for result in TestTextElement(variable.getformalParameter(), criteria):
+                search_result.append((tuple(parent_infos + ["input", i]),) + result)
+        for i, variable in enumerate(self.outputVariables.getvariable()):
+            for result in TestTextElement(variable.getformalParameter(), criteria):
+                search_result.append((tuple(parent_infos + ["output", i]),) + result)
+        return search_result
+    setattr(cls, "Search", Search)
+
 cls = _initElementClass("leftPowerRail", "ldObjects_leftPowerRail")
 if cls:
     setattr(cls, "getinfos", _getpowerrailinfosFunction("leftPowerRail"))
@@ -1933,6 +2154,10 @@
         self.variable = update_address(self.variable, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
     
+    def Search(self, criteria, parent_infos=[]):
+        return _Search([("reference", self.getvariable())], criteria, parent_infos + ["contact", self.getlocalId()])
+    setattr(cls, "Search", Search)
+
 cls = _initElementClass("coil", "ldObjects_coil", "single")
 if cls:
     setattr(cls, "getinfos", _getldelementinfosFunction("coil"))
@@ -1946,6 +2171,10 @@
         self.variable = update_address(self.variable, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        return _Search([("reference", self.getvariable())], criteria, parent_infos + ["coil", self.getlocalId()])
+    setattr(cls, "Search", Search)
+
 cls = _initElementClass("step", "sfcObjects_step", "single")
 if cls:
     def getinfos(self):
@@ -1963,6 +2192,10 @@
         return infos
     setattr(cls, "getinfos", getinfos)
 
+    def Search(self, criteria, parent_infos=[]):
+        return _Search([("name", self.getname())], criteria, parent_infos + ["step", self.getlocalId()])
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("transition_condition", None)
 if cls:
     def compatibility(self, tree):
@@ -2058,6 +2291,17 @@
                 return content["value"].getconnections()
     setattr(cls, "getconnections", getconnections)
     
+    def Search(self, criteria, parent_infos=[]):
+        parent_infos = parent_infos + ["transition", self.getlocalId()]
+        search_result = []
+        content = self.condition.getcontent()
+        if content["name"] == "reference":
+            search_result.extend(_Search([("reference", content["value"].getname())], criteria, parent_infos))
+        elif content["name"] == "inline":
+            search_result.extend(content["value"].Search(criteria, parent_infos + ["inline"]))
+        return search_result
+    setattr(cls, "Search", Search)
+    
 cls = _initElementClass("selectionDivergence", "sfcObjects_selectionDivergence", "single")
 if cls:
     setattr(cls, "getinfos", _getdivergenceinfosFunction(True, False))
@@ -2084,6 +2328,10 @@
         return infos
     setattr(cls, "getinfos", getinfos)
 
+    def Search(self, criteria, parent_infos):
+        return _Search([("target", self.gettargetName())], criteria, parent_infos + ["jump", self.getlocalId()])
+    setattr(cls, "Search", Search)
+
 cls = PLCOpenClasses.get("actionBlock_action", None)
 if cls:
     def compatibility(self, tree):
@@ -2134,6 +2382,18 @@
             self.inline.updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        qualifier = self.getqualifier()
+        if qualifier is None:
+            qualifier = "N"
+        return _Search([("inline", self.getinlineContent()),
+                        ("reference", self.getreferenceName()), 
+                        ("qualifier", qualifier),
+                        ("duration", self.getduration()),
+                        ("indicator", self.getindicator())],
+                       criteria, parent_infos)
+    setattr(cls, "Search", Search)
+
 cls = _initElementClass("actionBlock", "commonObjects_actionBlock", "single")
 if cls:
     def compatibility(self, tree):
@@ -2201,6 +2461,17 @@
             action.updateElementAddress(address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    def Search(self, criteria, parent_infos=[]):
+        parent_infos = parent_infos + ["action_block", self.getlocalId()]
+        search_result = []
+        for idx, action in enumerate(self.action):
+            search_result.extend(action.Search(criteria, parent_infos + ["action", idx]))
+        return search_result
+    setattr(cls, "Search", Search)
+
+def _SearchInIOVariable(self, criteria, parent_infos=[]):
+    return _Search([("expression", self.getexpression())], criteria, parent_infos + ["io_variable", self.getlocalId()])
+
 cls = _initElementClass("inVariable", "fbdObjects_inVariable")
 if cls:
     setattr(cls, "getinfos", _getvariableinfosFunction("input", False, True))
@@ -2214,6 +2485,8 @@
         self.expression = update_address(self.expression, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    setattr(cls, "Search", _SearchInIOVariable)
+
 cls = _initElementClass("outVariable", "fbdObjects_outVariable", "single")
 if cls:
     setattr(cls, "getinfos", _getvariableinfosFunction("output", True, False))
@@ -2227,6 +2500,8 @@
         self.expression = update_address(self.expression, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    setattr(cls, "Search", _SearchInIOVariable)
+
 cls = _initElementClass("inOutVariable", "fbdObjects_inOutVariable", "single")
 if cls:
     setattr(cls, "getinfos", _getvariableinfosFunction("inout", True, True))
@@ -2240,13 +2515,21 @@
         self.expression = update_address(self.expression, address_model, new_leading)
     setattr(cls, "updateElementAddress", updateElementAddress)
 
+    setattr(cls, "Search", _SearchInIOVariable)
+
+
+def _SearchInConnector(self, criteria, parent_infos=[]):
+    return _Search([("name", self.getname())], criteria, parent_infos + ["connector", self.getlocalId()])
+
 cls = _initElementClass("continuation", "commonObjects_continuation")
 if cls:
     setattr(cls, "getinfos", _getconnectorinfosFunction("continuation"))
+    setattr(cls, "Search", _SearchInConnector)
 
 cls = _initElementClass("connector", "commonObjects_connector", "single")
 if cls:
     setattr(cls, "getinfos", _getconnectorinfosFunction("connector"))
+    setattr(cls, "Search", _SearchInConnector)
 
 cls = PLCOpenClasses.get("connection", None)
 if cls: