PLCControler.py
changeset 226 6a2f7ddd2e50
parent 210 17ce08b81775
child 229 a5087e346baa
--- a/PLCControler.py	Tue Aug 12 16:28:55 2008 +0200
+++ b/PLCControler.py	Tue Aug 12 16:30:39 2008 +0200
@@ -162,16 +162,13 @@
         self.Buffering = False
         self.FilePath = ""
         self.FileName = ""
+        self.ProgramChunks = []
+        self.PluginTypes = []
         self.ProgramFilePath = ""
-        self.RefreshDataTypeUsingTree()
-        self.RefreshDataTypes()
-        self.RefreshPouUsingTree()
-        self.RefreshBlockTypes()
-
+        
     def GetQualifierTypes(self):
         return plcopen.QualifierList
 
-
 #-------------------------------------------------------------------------------
 #                         Project management functions
 #-------------------------------------------------------------------------------
@@ -269,41 +266,54 @@
     # Return project informations
     def GetProjectInfos(self):
         if self.Project:
-            infos = {"name": self.Project.getname(), "type": ITEM_PROJECT}
-            datatypes = {"name": "Data Types", "type": ITEM_DATATYPES, "values":[]}
+            infos = {"name": self.Project.getname(), "type": ITEM_PROJECT, "tagname": ""}
+            datatypes = {"name": "Data Types", "type": ITEM_DATATYPES, "tagname": "", "values":[]}
             for datatype in self.Project.getdataTypes():
-                datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, "values": []})
-            pou_types = {"function": {"name": "Functions", "type": ITEM_FUNCTION, "values":[]},
-                         "functionBlock": {"name": "Function Blocks", "type": ITEM_FUNCTIONBLOCK, "values":[]},
-                         "program": {"name": "Programs", "type": ITEM_PROGRAM, "values":[]}}
+                datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, 
+                    "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []})
+            pou_types = {"function": {"name": "Functions", "type": ITEM_FUNCTION, "tagname": "", "values":[]},
+                         "functionBlock": {"name": "Function Blocks", "type": ITEM_FUNCTIONBLOCK, "tagname": "", "values":[]},
+                         "program": {"name": "Programs", "type": ITEM_PROGRAM, "tagname": "", "values":[]}}
             for pou in self.Project.getpous():
                 pou_type = pou.getpouType()
-                pou_infos = {"name": pou.getname(), "type": ITEM_POU}
+                pou_infos = {"name": pou.getname(), "type": ITEM_POU,
+                             "tagname": self.ComputePouName(pou.getname())}
                 pou_values = []
                 if pou.getbodyType() == "SFC":
                     transitions = []
                     for transition in pou.gettransitionList():
-                        transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, "values": []})
-                    pou_values.append({"name": "Transitions", "type": ITEM_TRANSITIONS, "values": transitions})
+                        transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, 
+                            "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), 
+                            "values": []})
+                    pou_values.append({"name": "Transitions", "type": ITEM_TRANSITIONS, 
+                                       "tagname": "", "values": transitions})
                     actions = []
                     for action in pou.getactionList():
-                        actions.append({"name": action.getname(), "type": ITEM_ACTION, "values": []})
-                    pou_values.append({"name": "Actions", "type": ITEM_ACTIONS, "values": actions})
+                        actions.append({"name": action.getname(), "type": ITEM_ACTION, 
+                            "tagname": self.ComputePouActionName(pou.getname(), action.getname()), 
+                            "values": []})
+                    pou_values.append({"name": "Actions", "type": ITEM_ACTIONS, 
+                                       "tagname": "", "values": actions})
                 if pou_type in pou_types:
                     pou_infos["values"] = pou_values
                     pou_types[pou_type]["values"].append(pou_infos)
-            configurations = {"name": "Configurations", "type": ITEM_CONFIGURATIONS, "values": []}
+            configurations = {"name": "Configurations", "type": ITEM_CONFIGURATIONS, 
+                              "tagname": "", "values": []}
             for config in self.Project.getconfigurations():
                 config_name = config.getname()
-                config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []}
-                resources = {"name": "Resources", "type": ITEM_RESOURCES, "values": []}
+                config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, 
+                    "tagname": self.ComputeConfigurationName(config.getname()), 
+                    "values": []}
+                resources = {"name": "Resources", "type": ITEM_RESOURCES, "tagname": "", "values": []}
                 for resource in config.getresource():
                     resource_name = resource.getname()
-                    resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []}
+                    resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, 
+                        "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()), 
+                        "values": []}
                     resources["values"].append(resource_infos)
                 config_infos["values"] = [resources]
                 configurations["values"].append(config_infos)
-            infos["values"] = [{"name": "Properties", "type": ITEM_PROPERTIES, "values": []},
+            infos["values"] = [{"name": "Properties", "type": ITEM_PROPERTIES, "tagname": "", "values": []},
                                datatypes, pou_types["function"], pou_types["functionBlock"], 
                                pou_types["program"], configurations]
             return infos
@@ -379,7 +389,7 @@
                                 pou_infos["values"].append({"name" : "%s(%s)"%(variable.getname(), vartype_content["name"]), 
                                                                "type" : ITEM_VARIABLE, "values" : []})
                 return pou_infos
-            block_infos = GetBlockType(type)
+            block_infos = self.GetBlockType(type)
             if block_infos is not None and block_infos["type"] != "function":
                 pou_infos = {"name" : "%s(%s)"%(name, type), "type" : ITEM_POU, "values" : []}
                 for varname, vartype, varmodifier in block_infos["inputs"]:
@@ -392,126 +402,26 @@
                 return {"name" : "%s(%s)"%(name, type), "type" : ITEM_VARIABLE, "values" : []}
                 
         return None
-        
-    # Refresh the tree of user-defined data type cross-use
-    def RefreshDataTypeUsingTree(self):
-        # Reset the tree of user-defined pou cross-use
-        self.DataTypeUsingTree = {}
-        if self.Project:
-            datatypes = self.Project.getdataTypes()
-            # Reference all the user-defined data type names and initialize the tree of 
-            # user-defined data type cross-use
-            datatypenames = [datatype.getname() for datatype in datatypes]
-            for name in datatypenames:
-                self.DataTypeUsingTree[name] = []
-            # Analyze each data type
-            for datatype in datatypes:
-                name = datatype.getname()
-                basetype_content = datatype.getbaseType().getcontent()
-                if basetype_content["name"] == "derived":
-                    basetype_name = basetype_content["value"].getname()
-                    if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
-                        self.DataTypeUsingTree[basetype_name].append(name)
-                elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned", "array"]:
-                    base_type = basetype_content["value"].baseType.getcontent()
-                    if base_type["value"] is not None:
-                        basetype_name = base_type["value"].getname()
-                        if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
-                            self.DataTypeUsingTree[basetype_name].append(name)
-    
-    # Refresh the tree of user-defined pou cross-use
-    def RefreshPouUsingTree(self):
-        # Reset the tree of user-defined pou cross-use
-        self.PouUsingTree = {}
-        if self.Project:
-            pous = self.Project.getpous()
-            # Reference all the user-defined pou names and initialize the tree of 
-            # user-defined pou cross-use
-            pounames = [pou.getname() for pou in pous]
-            for name in pounames:
-                self.PouUsingTree[name] = []
-            # Analyze each pou 
-            for pou in pous:
-                name = pou.getname()
-                if pou.interface:
-                    # Extract variables from every varLists
-                    for type, varlist in pou.getvars():
-                        for var in varlist.getvariable():
-                            vartype_content = var.gettype().getcontent()
-                            if vartype_content["name"] == "derived":
-                                typename = vartype_content["value"].getname()
-                                if typename in pounames and name not in self.PouUsingTree[typename]:
-                                    self.PouUsingTree[typename].append(name)
-                bodytype = pou.getbodyType()
-                # If pou is written in a graphical language
-                if bodytype in ["FBD","LD","SFC"]:
-                    # Analyze each instance of the pou
-                    for instance in pou.getinstances():
-                        if isinstance(instance, plcopen.fbdObjects_block):
-                            typename = instance.gettypeName()
-                            # Update tree if there is a cross-use
-                            if typename in pounames and name not in self.PouUsingTree[typename]:
-                                 self.PouUsingTree[typename].append(name)
-                # If pou is written in a textual language
-                elif bodytype in ["IL", "ST"]:
-                    text = pou.gettext()
-                    # Search if each pou is mentioned in the pou text
-                    for typename in pounames:
-                        typename_model = re.compile("[ \t\n]%s[ \t\n]"%typename)
-                        # Update tree if there is a cross-use
-                        if typename != name and typename_model.search(text):
-                            self.PouUsingTree[typename].append(name)
 
     # Return if data type given by name is used by another data type or pou
     def DataTypeIsUsed(self, name):
-        if name in self.DataTypeUsingTree:
-            return len(self.DataTypeUsingTree[name]) > 0
-        return False
+        return self.Project.ElementIsUsed(name) or self.Project.DataTypeIsDerived(name)
 
     # Return if pou given by name is used by another pou
     def PouIsUsed(self, name):
-        if name in self.PouUsingTree:
-            return len(self.PouUsingTree[name]) > 0
-        return False
-
-    # Return if data type given by name is directly or undirectly used by the reference data type
-    def DataTypeIsUsedBy(self, name, reference):
-        if name in self.DataTypeUsingTree:
-            list = self.DataTypeUsingTree[name]
-            # Test if data type is directly used by reference
-            if reference in list:
-                return True
-            else:
-                # Test if data type is undirectly used by reference, by testing if data types 
-                # that directly use data type is directly or undirectly used by reference
-                used = False
-                for element in list:
-                    used |= self.DataTypeIsUsedBy(element, reference)
-                return used
-        return False
+        return self.Project.ElementIsUsed(name)
 
     # Return if pou given by name is directly or undirectly used by the reference pou
     def PouIsUsedBy(self, name, reference):
-        if name in self.PouUsingTree:
-            list = self.PouUsingTree[name]
-            # Test if pou is directly used by reference
-            if reference in list:
-                return True
-            else:
-                # Test if pou is undirectly used by reference, by testing if pous 
-                # that directly use pou is directly or undirectly used by reference
-                used = False
-                for element in list:
-                    used |= self.PouIsUsedBy(element, reference)
-                return used
-        return False
+        return self.Project.ElementIsUsedBy(name, reference)
 
     def GenerateProgram(self, filepath):
         if self.Project:
             try:
-                program = GenerateCurrentProgram(self.Project)
+                self.ProgramChunks = GenerateCurrentProgram(self, self.Project)
+                program_text = "".join([item[0] for item in self.ProgramChunks])
                 programfile = open(filepath, "w")
-                programfile.write(program)
+                programfile.write(program_text)
                 programfile.close()
                 self.ProgramFilePath = filepath
                 return None
@@ -519,6 +429,23 @@
                 return e.message
         return "No project opened"
 
+    def GetChunkInfos(self, from_location, to_location):
+        row = col = 1
+        infos = []
+        for chunk, chunk_infos in self.ProgramChunks:
+            lines = chunk.split("\n")
+            if len(lines) > 1:
+                next_row = row + len(lines) - 1
+                next_col = len(lines[-1]) + 1
+            else:
+                next_col = col + len(chunk)
+            if next_row >= from_location[0] and next_col >= from_location[1] and len(chunk_infos) > 0:
+                infos.append((chunk_infos, (row, col)))
+            if next_row == to_location[0] and next_col > to_location[1] or next_row > to_location[0]:
+                return infos
+            row, col = next_row, next_col
+        return infos
+        
 #-------------------------------------------------------------------------------
 #                        Project Pous management functions
 #-------------------------------------------------------------------------------
@@ -527,15 +454,11 @@
     def ProjectAddDataType(self, datatype_name):
         # Add the pou to project
         self.Project.appenddataType(datatype_name)
-        self.RefreshDataTypeUsingTree()
-        self.RefreshDataTypes()
         self.BufferProject()
     
     # Remove a Data Type from project
     def ProjectRemoveDataType(self, datatype_name):
         self.Project.removedataType(datatype_name)
-        self.RefreshDataTypeUsingTree()
-        self.RefreshDataTypes()
         self.BufferProject()
     
     # Add a Pou to Project
@@ -544,15 +467,11 @@
         self.Project.appendpou(pou_name, pou_type, body_type)
         if pou_type == "function":
             self.SetPouInterfaceReturnType(pou_name, "BOOL")
-        self.RefreshPouUsingTree()
-        self.RefreshBlockTypes()
         self.BufferProject()
     
     # Remove a Pou from project
     def ProjectRemovePou(self, pou_name):
         self.Project.removepou(pou_name)
-        self.RefreshPouUsingTree()
-        self.RefreshBlockTypes()
         self.BufferProject()
     
     # Add a configuration to Project
@@ -618,8 +537,8 @@
         pou = self.Project.getpou(old_name)
         pou.setname(new_name)
         self.Project.updateElementName(old_name, new_name)
-        self.RefreshPouUsingTree()
-        self.RefreshBlockTypes()
+        self.Project.RefreshElementUsingTree()
+        self.Project.RefreshCustomBlockTypes()
         self.BufferProject()
     
     # Change the name of a pou transition
@@ -648,7 +567,7 @@
             for var in varlist.getvariable():
                 if var.getname() == old_name:
                     var.setname(new_name)
-        self.RefreshBlockTypes()
+        self.Project.RefreshCustomBlockTypes()
         self.BufferProject()
         
     # Change the name of a configuration
@@ -784,7 +703,6 @@
             configuration.setglobalVars([])
             for vartype, varlist in self.ExtractVarLists(vars):
                 configuration.globalVars.append(varlist)
-        self.RefreshBlockTypes()
     
     # Return the configuration globalvars
     def GetConfigurationGlobalVars(self, name):
@@ -834,7 +752,6 @@
             resource.setglobalVars([])
             for vartype, varlist in self.ExtractVarLists(vars):
                 resource.globalVars.append(varlist)
-        self.RefreshBlockTypes()
     
     # Return the resource globalvars
     def GetConfigurationResourceGlobalVars(self, config_name, name):
@@ -928,8 +845,8 @@
             pou.interface = plcopen.pou_interface()
         # Set Pou interface
         pou.setvars(self.ExtractVarLists(vars))
-        self.RefreshPouUsingTree()
-        self.RefreshBlockTypes()
+        self.Project.RefreshElementUsingTree()
+        self.Project.RefreshCustomBlockTypes()
     
     # Replace the return type of the pou given by its name (only for functions)
     def SetPouInterfaceReturnType(self, name, type):
@@ -953,7 +870,8 @@
             derived_type = plcopen.derivedTypes_derived()
             derived_type.setname(type)
             return_type.setcontent({"name" : "derived", "value" : derived_type})
-        self.RefreshBlockTypes()
+        self.Project.RefreshElementUsingTree()
+        self.Project.RefreshCustomBlockTypes()
     
     def UpdateProjectUsedPous(self, old_name, new_name):
         if self.Project:
@@ -984,108 +902,43 @@
                 else:
                     return returntype_content["name"]
         return None
-    
-    # Update data types with user-defined data types added
-    def RefreshDataTypes(self):
-        ResetTypeHierarchy()
-        ResetEnumeratedDataValues()
+
+    # Function that add a new plugin to the plugin list
+    def AddPluginBlockList(self, blocklist):
+        self.PluginTypes.extend(blocklist)
+        
+    # Function that clear the plugin list
+    def ClearPluginTypes(self):
+        for i in xrange(len(self.PluginTypes)):
+            self.PluginTypes.pop(0)
+
+    # Function that returns the block definition associated to the block type given
+    def GetBlockType(self, type, inputs = None):
+        for category in BlockTypes + self.PluginTypes:
+            for blocktype in category["list"]:
+                if inputs:
+                    block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
+                    same_inputs = inputs == block_inputs
+                else:
+                    same_inputs = True
+                if blocktype["name"] == type and same_inputs:
+                    return blocktype
         if self.Project:
-            for datatype in self.Project.getdataTypes():
-                name = datatype.getname()
-                basetype_content = datatype.getbaseType().getcontent()
-                if basetype_content["value"] is None:
-                    AddDataTypeHierarchy(name, basetype_content["name"])
-                elif basetype_content["name"] in ["string", "wstring"]:
-                    AddDataTypeHierarchy(name, basetype_content["name"].upper())
-                elif basetype_content["name"] == "derived":
-                    AddDataTypeHierarchy(name, basetype_content["value"].getname())
-                elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
-                    base_type = basetype_content["value"].baseType.getcontent()
-                    if base_type["value"] is None:
-                        AddDataTypeHierarchy(name, base_type["name"])
-                    else:
-                        AddDataTypeHierarchy(name, base_type["value"].getname())
-                else:
-                    if basetype_content["name"] == "enum":
-                        values = []
-                        for value in basetype_content["value"].values.getvalue():
-                            values.append(value.getname())
-                        AddEnumeratedDataValues(values)
-                    AddDataTypeHierarchy(name, "ANY_DERIVED")
-    
-    # Update Block types with user-defined pou added
-    def RefreshBlockTypes(self):
-        if BlockTypes[-1]["name"] == "User-defined POUs":
-            BlockTypes[-1]["list"] = []
-        else:
-            BlockTypes.append({"name" : "User-defined POUs", "list": []})
-        if self.Project:
-            for pou in self.Project.getpous():
-                pou_name = pou.getname()
-                pou_type = pou.getpouType()
-                if pou_type != "program":
-                    block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
-                                   "inputs" : [], "outputs" : [], "comment" : "",
-                                   "generate" : generate_block, "initialise" : initialise_block }
-                    if pou.getinterface():
-                        for type, varlist in pou.getvars():
-                            if type == "InOut":
-                                for var in varlist.getvariable():
-                                    var_type = var.type.getcontent()
-                                    if var_type["name"] == "derived":
-                                        block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
-                                        block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none"))
-                                    elif var_type["name"] in ["string", "wstring"]:
-                                        block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none"))
-                                        block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none"))
-                                    else:
-                                        block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
-                                        block_infos["outputs"].append((var.getname(), var_type["name"], "none"))
-                            elif type == "Input":
-                                for var in varlist.getvariable():
-                                    var_type = var.type.getcontent()
-                                    if var_type["name"] == "derived":
-                                        block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
-                                    elif var_type["name"] in ["string", "wstring"]:
-                                        block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none"))
-                                    else:
-                                        block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
-                            elif type == "Output":
-                                for var in varlist.getvariable():
-                                    var_type = var.type.getcontent()
-                                    if var_type["name"] == "derived":
-                                        block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none"))
-                                    elif var_type["name"] in ["string", "wstring"]:
-                                        block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none"))
-                                    else:
-                                        block_infos["outputs"].append((var.getname(), var_type["name"], "none"))    
-                        return_type = pou.interface.getreturnType()
-                        if return_type:
-                            var_type = return_type.getcontent()
-                            if var_type["name"] == "derived":
-                                block_infos["outputs"].append(("", var_type["value"].getname(), "none"))
-                            elif var_type["name"] in ["string", "wstring"]:
-                                block_infos["outputs"].append(("", var_type["name"].upper(), "none"))
-                            else:
-                                block_infos["outputs"].append(("", var_type["name"], "none"))
-                    if pou.getbodyType() in ["FBD","LD","SFC"]:
-                        for instance in pou.getinstances():
-                            if isinstance(instance, plcopen.commonObjects_comment):
-                                block_infos["comment"] = instance.getcontentText()
-                    BlockTypes[-1]["list"].append(block_infos)
-    
+            return self.Project.GetCustomBlockType(type, inputs)
+        return None
+
     # Return Block types checking for recursion
     def GetBlockTypes(self, tagname = ""):
-        name = ""
         type = None
         if self.Project:
+            name = ""
             words = tagname.split("::")
             if words[0] in ["P","T","A"]:
                 name = words[1]
                 type = self.GetPouType(name)
         if type == "function":
             blocktypes = []
-            for category in BlockTypes[:-1] + PluginTypes:
+            for category in BlockTypes + self.PluginTypes:
                 cat = {"name" : category["name"], "list" : []}
                 for block in category["list"]:
                     if block["type"] == "function":
@@ -1093,32 +946,24 @@
                 if len(cat["list"]) > 0:
                     blocktypes.append(cat)
         else:
-            blocktypes = [category for category in BlockTypes[:-1] + PluginTypes]
+            blocktypes = [category for category in BlockTypes + self.PluginTypes]
         if self.Project:
-            blocktypes.append({"name" : "User-defined POUs", "list": []})
-            for blocktype in BlockTypes[-1]["list"]:
-                if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
-                    blocktypes[-1]["list"].append(blocktype)
+            blocktypes.append({"name" : "User-defined POUs", "list": self.Project.GetCustomBlockTypes(name)})
         return blocktypes
 
     # Return Function Block types checking for recursion
     def GetFunctionBlockTypes(self, tagname = ""):
-        name = ""
-        type = None
-        if self.Project:
-            words = tagname.split("::")
-            if words[0] in ["P","T","A"]:
-                name = words[1]
-                type = self.GetPouType(name)
         blocktypes = []
-        for category in BlockTypes[:-1]:
+        for category in BlockTypes + self.PluginTypes:
             for block in category["list"]:
                 if block["type"] != "function":
                     blocktypes.append(block["name"])
         if self.Project:
-            for blocktype in BlockTypes[-1]["list"]:
-                if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
-                    blocktypes.append(blocktype["name"])
+            name = ""
+            words = tagname.split("::")
+            if words[0] in ["P","T","A"]:
+                name = words[1]
+            blocktypes.extend(self.Project.GetCustomFunctionBlockTypes(name))
         return blocktypes
 
     # Return Block types checking for recursion
@@ -1129,9 +974,7 @@
                 if blocktype["type"] == "program":
                     blocktypes.append(blocktype["name"])
         if self.Project:
-            for pou in self.Project.getpous():
-                if pou.getpouType() == "program":
-                    blocktypes.append(pou.getname())
+            blocktypes.extend(self.Project.GetCustomBlockResource())
         return blocktypes
 
     # Return Data Types checking for recursion
@@ -1141,32 +984,58 @@
         else:
             datatypes = []
         if self.Project:
+            name = ""
             words = tagname.split("::")
             if words[0] in ["D"]:
                 name = words[1]
-            else:
-                name = ""
-            for datatype in self.Project.getdataTypes():
-                datatype_name = datatype.getname()
-                if datatype_name != name and not self.DataTypeIsUsedBy(name, datatype_name):
-                    datatypes.append(datatype_name)
+            datatypes.extend(self.Project.GetCustomDataTypes(name))
         return datatypes
 
     # Return Base Type of given possible derived type
     def GetBaseType(self, type):
-        return GetBaseType(type)
+        if self.Project:
+            return self.Project.GetBaseType(type)
+        return None
 
     # Return Base Types
     def GetBaseTypes(self):
-        return [value for value, parent in TypeHierarchy_list if not value.startswith("ANY")]
-
+        return [value for value in TypeHierarchy.keys() if not value.startswith("ANY")]
+
+    def IsOfType(self, type, reference):
+        if self.Project:
+            return self.Project.IsOfType(type, reference)
+        elif reference is None:
+            return True
+        elif type == reference:
+            return True
+        else:
+            if type in TypeHierarchy:
+                return self.IsOfType(TypeHierarchy[type], reference)
+        return None
+    
+    def IsEndType(self, type):
+        if type is not None:
+            return not type.startswith("ANY")
+        return True
+
+    def GetDataTypeRange(self, type):
+        if self.Project:
+            return self.Project.GetDataTypeRange(type)
+        elif type in DataTypeRange:
+            return DataTypeRange[type]
+        return None
+    
     # Return Subrange types
-    def GetSubrangeTypes(self):
-        return [value for value, range in DataTypeRange_list]
-
+    def GetSubrangeBaseTypes(self, exclude):
+        if self.Project:
+            return self.Project.GetSubrangeBaseTypes(exclude)
+        return []
+    
     # Return Enumerated Values
     def GetEnumeratedDataValues(self):
-        return EnumeratedDataValues
+        if self.Project:
+            return self.Project.GetEnumeratedDataTypeValues()
+        return []
 
 #-------------------------------------------------------------------------------
 #                   Project Element tag name computation functions
@@ -1196,6 +1065,12 @@
     def ComputeConfigurationResourceName(self, config, resource):
         return "R::%s::%s" % (config, resource)
 
+    def GetElementType(self, tagname):
+        words = tagname.split("::")
+        return {"D" : ITEM_DATATYPE, "P" : ITEM_POU, 
+                "T" : ITEM_TRANSITION, "A" : ITEM_ACTION,
+                "C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]]
+
 #-------------------------------------------------------------------------------
 #                    Project opened Data types management functions
 #-------------------------------------------------------------------------------
@@ -1314,8 +1189,7 @@
                 datatype.initialValue.setvalue(infos["initial"])
             else:
                 datatype.initialValue = None
-            self.RefreshDataTypeUsingTree()
-            self.RefreshDataTypes()
+            self.Project.RefreshDataTypeHierarchy()
             self.BufferProject()
     
 #-------------------------------------------------------------------------------
@@ -1325,9 +1199,11 @@
     # Return edited element
     def GetEditedElement(self, tagname):
         words = tagname.split("::")
-        if words[0] == "P":
+        if words[0] == "D":
+            return self.Project.getdataType(words[1])
+        elif words[0] == "P":
             return self.Project.getpou(words[1])
-        if words[0] in ['T', 'A']:
+        elif words[0] in ['T', 'A']:
             pou = self.Project.getpou(words[1])
             if words[0] == 'T':
                 return pou.gettransition(words[2])
@@ -1342,7 +1218,7 @@
     # Return edited element name
     def GetEditedElementName(self, tagname):
         words = tagname.split("::")
-        if words[0] in ["P","C"]:
+        if words[0] in ["P","C","D"]:
             return words[1]
         else:
             return words[2]
@@ -1790,7 +1666,7 @@
             block = plcopen.fbdObjects_block()
             block.setlocalId(id)
             block.settypeName(blocktype)
-            blocktype_infos = GetBlockType(blocktype)
+            blocktype_infos = self.GetBlockType(blocktype)
             if blocktype_infos["type"] != "function" and blockname is not None:
                 block.setinstanceName(blockname)
                 self.AddEditedElementPouVar(tagname, blocktype, blockname)
@@ -1807,8 +1683,8 @@
             old_type = block.gettypeName()
             new_name = infos.get("name", old_name)
             new_type = infos.get("type", old_type)
-            old_typeinfos = GetBlockType(old_type)
-            new_typeinfos = GetBlockType(new_type)
+            old_typeinfos = self.GetBlockType(old_type)
+            new_typeinfos = self.GetBlockType(new_type)
             if new_typeinfos["type"] != old_typeinfos["type"]:
                 if new_typeinfos["type"] == "function":
                     self.RemoveEditedElementPouVar(tagname, old_type, old_name)
@@ -2463,14 +2339,13 @@
             if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project":
                 self.Project.loadXMLTree(child, ["xmlns", "xmlns:xhtml", "xmlns:xsi", "xsi:schemaLocation"])
                 self.SetFilePath(filepath)
+                self.Project.RefreshElementUsingTree()
+                self.Project.RefreshDataTypeHierarchy()
+                self.Project.RefreshCustomBlockTypes()
                 self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), True)
                 self.Buffering = False
                 self.ElementsOpened = []
                 self.CurrentElementEditing = None
-                self.RefreshDataTypeUsingTree()
-                self.RefreshDataTypes()
-                self.RefreshPouUsingTree()
-                self.RefreshBlockTypes()
                 return None
         return "No PLC project found"