Adding support for loading datatypes defined in plugins to allow to use them in PLC program
authorlaurent
Tue, 24 Jan 2012 21:42:21 +0100
changeset 630 9d7e38e271cb
parent 629 ddf363817ffa
child 631 e4dd5bf1f1db
Adding support for loading datatypes defined in plugins to allow to use them in PLC program
PLCControler.py
controls/VariablePanel.py
plcopen/plcopen.py
--- a/PLCControler.py	Tue Jan 17 20:06:07 2012 +0100
+++ b/PLCControler.py	Tue Jan 24 21:42:21 2012 +0100
@@ -1125,6 +1125,8 @@
                     tree.insert(0, ("EN", "BOOL", ([], [])))
                 return tree, []
             datatype = project.getdataType(typename)
+            if datatype is None:
+                datatype = self.GetPluginDataType(typename)
             if datatype is not None:
                 tree = []
                 basetype_content = datatype.baseType.getcontent()
@@ -1247,21 +1249,38 @@
         return None
 
     # Function that add a new plugin to the plugin list
-    def AddPluginBlockList(self, blocklist):
-        self.PluginTypes.extend(blocklist)
+    def AddPluginTypesList(self, typeslist):
+        self.PluginTypes.extend(typeslist)
         
     # Function that clear the plugin list
     def ClearPluginTypes(self):
         for i in xrange(len(self.PluginTypes)):
             self.PluginTypes.pop(0)
 
+    def GetPluginBlockTypes(self):
+        return [{"name": _("%s POUs") % plugintypes["name"],
+                 "list": plugintypes["types"].GetCustomBlockTypes()}
+                for plugintypes in self.PluginTypes]
+        
+    def GetPluginDataTypes(self, exclude = ""):
+        return [{"name": _("%s Data Types") % plugintypes["name"],
+                 "list": [datatype["name"] for datatype in plugintypes["types"].GetCustomDataTypes(exclude, True)]}
+                for plugintypes in self.PluginTypes]
+    
+    def GetPluginDataType(self, type):
+        for plugintype in self.PluginTypes:
+            datatype = plugintype["types"].getdataType(type)
+            if datatype is not None:
+                return datatype
+        return None
+    
     def GetVariableLocationTree(self):
         return []
 
     # Function that returns the block definition associated to the block type given
     def GetBlockType(self, type, inputs = None, debug = False):
         result_blocktype = None
-        for category in BlockTypes + self.PluginTypes:
+        for category in BlockTypes + self.GetPluginBlockTypes():
             for blocktype in category["list"]:
                 if blocktype["name"] == type:
                     if inputs is not None and inputs != "undefined":
@@ -1295,7 +1314,7 @@
                 type = self.GetPouType(name, debug)
         if type == "function" or words[0] == "T":
             blocktypes = []
-            for category in BlockTypes + self.PluginTypes:
+            for category in BlockTypes + self.GetPluginBlockTypes():
                 cat = {"name" : category["name"], "list" : []}
                 for block in category["list"]:
                     if block["type"] == "function":
@@ -1303,7 +1322,7 @@
                 if len(cat["list"]) > 0:
                     blocktypes.append(cat)
         else:
-            blocktypes = [category for category in BlockTypes + self.PluginTypes]
+            blocktypes = [category for category in BlockTypes + self.GetPluginBlockTypes()]
         project = self.GetProject(debug)
         if project is not None:
             blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")})
@@ -1312,7 +1331,7 @@
     # Return Function Block types checking for recursion
     def GetFunctionBlockTypes(self, tagname = "", debug = False):
         blocktypes = []
-        for category in BlockTypes + self.PluginTypes:
+        for category in BlockTypes + self.GetPluginBlockTypes():
             for block in category["list"]:
                 if block["type"] == "functionBlock":
                     blocktypes.append(block["name"])
@@ -1349,14 +1368,20 @@
             words = tagname.split("::")
             if words[0] in ["D"]:
                 name = words[1]
-            datatypes.extend(project.GetCustomDataTypes(name, only_locatables))
+            datatypes.extend([datatype["name"] for datatype in project.GetCustomDataTypes(name, only_locatables)])
         return datatypes
 
     # Return Base Type of given possible derived type
     def GetBaseType(self, type, debug = False):
         project = self.GetProject(debug)
         if project is not None:
-            return project.GetBaseType(type)
+            result = project.GetBaseType(type)
+            if result is not None:
+                return result
+        for plugintype in self.PluginTypes:
+            result = plugintype["types"].GetBaseType(type)
+            if result is not None:
+                return result
         return None
 
     def GetBaseTypes(self):
@@ -1368,17 +1393,20 @@
         return [x for x,y in TypeHierarchy_list if not x.startswith("ANY")]
 
     def IsOfType(self, type, reference, debug = False):
-        project = self.GetProject(debug)
-        if project is not None:
-            return project.IsOfType(type, reference)
-        elif reference is None:
+        if reference is None:
             return True
         elif type == reference:
             return True
+        elif type in TypeHierarchy:
+            return self.IsOfType(TypeHierarchy[type], reference)
         else:
-            if type in TypeHierarchy:
-                return self.IsOfType(TypeHierarchy[type], reference)
-        return None
+            project = self.GetProject(debug)
+            if project is not None and project.IsOfType(type, reference):
+                return True
+            for plugintype in self.PluginTypes:
+                if plugintype["types"].IsOfType(type, reference):
+                    return True
+        return False
     
     def IsEndType(self, type):
         if type is not None:
@@ -1391,6 +1419,8 @@
         project = self.GetProject(debug)
         if project is not None:
             datatype = project.getdataType(type)
+            if datatype is None:
+                datatype = self.GetPluginDataType(type)
             if datatype is not None:
                 return project.IsLocatableType(datatype)
         return True
@@ -1399,32 +1429,51 @@
         project = self.GetProject(debug)
         if project is not None:
             datatype = project.getdataType(type)
+            if datatype is None:
+                datatype = self.GetPluginDataType(type)
             if datatype is not None:
                 basetype_content = datatype.baseType.getcontent()
                 return basetype_content["name"] == "enum"
         return False
 
     def GetDataTypeRange(self, type, debug = False):
-        project = self.GetProject(debug)
-        if project is not None:
-            return project.GetDataTypeRange(type)
-        elif type in DataTypeRange:
+        if type in DataTypeRange:
             return DataTypeRange[type]
+        else:
+            project = self.GetProject(debug)
+            if project is not None:
+                result = project.GetDataTypeRange(type)
+                if result is not None:
+                    return result
+            for plugintype in self.PluginTypes:
+                result = plugintype["types"].GetDataTypeRange(type)
+                if result is not None:
+                    return result
         return None
     
     # Return Subrange types
     def GetSubrangeBaseTypes(self, exclude, debug = False):
-        project = self.GetProject(debug)
-        if project is not None:
-            return project.GetSubrangeBaseTypes(exclude)
-        return []
+        subrange_basetypes = []
+        project = self.GetProject(debug)
+        if project is not None:
+            subrange_basetypes.extend(project.GetSubrangeBaseTypes(exclude))
+        for plugintype in self.PluginTypes:
+            subrange_basetypes.extend(plugintype["types"].GetSubrangeBaseTypes(exclude))
+        return DataTypeRange.keys() + subrange_basetypes
     
     # Return Enumerated Values
     def GetEnumeratedDataValues(self, type = None, debug = False):
-        project = self.GetProject(debug)
-        if project is not None:
-            return project.GetEnumeratedDataTypeValues(type)
-        return []
+        values = []
+        project = self.GetProject(debug)
+        if project is not None:
+            values.extend(project.GetEnumeratedDataTypeValues(type))
+            if type is None and len(values) > 0:
+                return values
+        for plugintype in self.PluginTypes:
+            values.extend(plugintype["types"].GetEnumeratedDataTypeValues(type))
+            if type is None and len(values) > 0:
+                return values
+        return values
 
 #-------------------------------------------------------------------------------
 #                   Project Element tag name computation functions
--- a/controls/VariablePanel.py	Tue Jan 17 20:06:07 2012 +0100
+++ b/controls/VariablePanel.py	Tue Jan 24 21:42:21 2012 +0100
@@ -729,8 +729,6 @@
 
             # build a submenu containing user-defined types
             datatype_menu = wx.Menu(title='')
-            
-            # TODO : remove complextypes argument when matiec can manage complex types in pou interface
             datatypes = self.Controler.GetDataTypes(basetypes = False)
             for datatype in datatypes:
                 new_id = wx.NewId()
@@ -738,6 +736,18 @@
                 self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
 
             type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu)
+            
+            for category in self.Controler.GetPluginDataTypes():
+               
+               if len(category["list"]) > 0:
+                   # build a submenu containing plugin types
+                   plugin_datatype_menu = wx.Menu(title='')
+                   for datatype in category["list"]:
+                       new_id = wx.NewId()
+                       AppendMenu(plugin_datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
+                       self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
+                   
+                   type_menu.AppendMenu(wx.NewId(), category["name"], plugin_datatype_menu)
 
             # build a submenu containing function block types
             bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
--- a/plcopen/plcopen.py	Tue Jan 17 20:06:07 2012 +0100
+++ b/plcopen/plcopen.py	Tue Jan 24 21:42:21 2012 +0100
@@ -558,7 +558,7 @@
                 if self.IsOfType(type, base_type) and not self.IsOfType(type, exclude):
                     derived.append(type)
                     break
-        return DataTypeRange.keys() + derived
+        return derived
     setattr(cls, "GetSubrangeBaseTypes", GetSubrangeBaseTypes)
 
     """
@@ -679,7 +679,7 @@
             if not only_locatable or self.IsLocatableType(customdatatype):
                 customdatatype_name = customdatatype.getname()
                 if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name):
-                    customdatatypes.append(customdatatype_name)
+                    customdatatypes.append({"name": customdatatype_name, "infos": customdatatype})
         return customdatatypes
     setattr(cls, "GetCustomDataTypes", GetCustomDataTypes)