PLCControler.py
changeset 226 6a2f7ddd2e50
parent 210 17ce08b81775
child 229 a5087e346baa
equal deleted inserted replaced
225:7726c8ffda42 226:6a2f7ddd2e50
   160         self.Project = None
   160         self.Project = None
   161         self.ProjectBuffer = None
   161         self.ProjectBuffer = None
   162         self.Buffering = False
   162         self.Buffering = False
   163         self.FilePath = ""
   163         self.FilePath = ""
   164         self.FileName = ""
   164         self.FileName = ""
       
   165         self.ProgramChunks = []
       
   166         self.PluginTypes = []
   165         self.ProgramFilePath = ""
   167         self.ProgramFilePath = ""
   166         self.RefreshDataTypeUsingTree()
   168         
   167         self.RefreshDataTypes()
       
   168         self.RefreshPouUsingTree()
       
   169         self.RefreshBlockTypes()
       
   170 
       
   171     def GetQualifierTypes(self):
   169     def GetQualifierTypes(self):
   172         return plcopen.QualifierList
   170         return plcopen.QualifierList
   173 
       
   174 
   171 
   175 #-------------------------------------------------------------------------------
   172 #-------------------------------------------------------------------------------
   176 #                         Project management functions
   173 #                         Project management functions
   177 #-------------------------------------------------------------------------------
   174 #-------------------------------------------------------------------------------
   178 
   175 
   267         return properties
   264         return properties
   268     
   265     
   269     # Return project informations
   266     # Return project informations
   270     def GetProjectInfos(self):
   267     def GetProjectInfos(self):
   271         if self.Project:
   268         if self.Project:
   272             infos = {"name": self.Project.getname(), "type": ITEM_PROJECT}
   269             infos = {"name": self.Project.getname(), "type": ITEM_PROJECT, "tagname": ""}
   273             datatypes = {"name": "Data Types", "type": ITEM_DATATYPES, "values":[]}
   270             datatypes = {"name": "Data Types", "type": ITEM_DATATYPES, "tagname": "", "values":[]}
   274             for datatype in self.Project.getdataTypes():
   271             for datatype in self.Project.getdataTypes():
   275                 datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, "values": []})
   272                 datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, 
   276             pou_types = {"function": {"name": "Functions", "type": ITEM_FUNCTION, "values":[]},
   273                     "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []})
   277                          "functionBlock": {"name": "Function Blocks", "type": ITEM_FUNCTIONBLOCK, "values":[]},
   274             pou_types = {"function": {"name": "Functions", "type": ITEM_FUNCTION, "tagname": "", "values":[]},
   278                          "program": {"name": "Programs", "type": ITEM_PROGRAM, "values":[]}}
   275                          "functionBlock": {"name": "Function Blocks", "type": ITEM_FUNCTIONBLOCK, "tagname": "", "values":[]},
       
   276                          "program": {"name": "Programs", "type": ITEM_PROGRAM, "tagname": "", "values":[]}}
   279             for pou in self.Project.getpous():
   277             for pou in self.Project.getpous():
   280                 pou_type = pou.getpouType()
   278                 pou_type = pou.getpouType()
   281                 pou_infos = {"name": pou.getname(), "type": ITEM_POU}
   279                 pou_infos = {"name": pou.getname(), "type": ITEM_POU,
       
   280                              "tagname": self.ComputePouName(pou.getname())}
   282                 pou_values = []
   281                 pou_values = []
   283                 if pou.getbodyType() == "SFC":
   282                 if pou.getbodyType() == "SFC":
   284                     transitions = []
   283                     transitions = []
   285                     for transition in pou.gettransitionList():
   284                     for transition in pou.gettransitionList():
   286                         transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, "values": []})
   285                         transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION, 
   287                     pou_values.append({"name": "Transitions", "type": ITEM_TRANSITIONS, "values": transitions})
   286                             "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), 
       
   287                             "values": []})
       
   288                     pou_values.append({"name": "Transitions", "type": ITEM_TRANSITIONS, 
       
   289                                        "tagname": "", "values": transitions})
   288                     actions = []
   290                     actions = []
   289                     for action in pou.getactionList():
   291                     for action in pou.getactionList():
   290                         actions.append({"name": action.getname(), "type": ITEM_ACTION, "values": []})
   292                         actions.append({"name": action.getname(), "type": ITEM_ACTION, 
   291                     pou_values.append({"name": "Actions", "type": ITEM_ACTIONS, "values": actions})
   293                             "tagname": self.ComputePouActionName(pou.getname(), action.getname()), 
       
   294                             "values": []})
       
   295                     pou_values.append({"name": "Actions", "type": ITEM_ACTIONS, 
       
   296                                        "tagname": "", "values": actions})
   292                 if pou_type in pou_types:
   297                 if pou_type in pou_types:
   293                     pou_infos["values"] = pou_values
   298                     pou_infos["values"] = pou_values
   294                     pou_types[pou_type]["values"].append(pou_infos)
   299                     pou_types[pou_type]["values"].append(pou_infos)
   295             configurations = {"name": "Configurations", "type": ITEM_CONFIGURATIONS, "values": []}
   300             configurations = {"name": "Configurations", "type": ITEM_CONFIGURATIONS, 
       
   301                               "tagname": "", "values": []}
   296             for config in self.Project.getconfigurations():
   302             for config in self.Project.getconfigurations():
   297                 config_name = config.getname()
   303                 config_name = config.getname()
   298                 config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []}
   304                 config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, 
   299                 resources = {"name": "Resources", "type": ITEM_RESOURCES, "values": []}
   305                     "tagname": self.ComputeConfigurationName(config.getname()), 
       
   306                     "values": []}
       
   307                 resources = {"name": "Resources", "type": ITEM_RESOURCES, "tagname": "", "values": []}
   300                 for resource in config.getresource():
   308                 for resource in config.getresource():
   301                     resource_name = resource.getname()
   309                     resource_name = resource.getname()
   302                     resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []}
   310                     resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, 
       
   311                         "tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()), 
       
   312                         "values": []}
   303                     resources["values"].append(resource_infos)
   313                     resources["values"].append(resource_infos)
   304                 config_infos["values"] = [resources]
   314                 config_infos["values"] = [resources]
   305                 configurations["values"].append(config_infos)
   315                 configurations["values"].append(config_infos)
   306             infos["values"] = [{"name": "Properties", "type": ITEM_PROPERTIES, "values": []},
   316             infos["values"] = [{"name": "Properties", "type": ITEM_PROPERTIES, "tagname": "", "values": []},
   307                                datatypes, pou_types["function"], pou_types["functionBlock"], 
   317                                datatypes, pou_types["function"], pou_types["functionBlock"], 
   308                                pou_types["program"], configurations]
   318                                pou_types["program"], configurations]
   309             return infos
   319             return infos
   310         return None
   320         return None
   311 
   321 
   377                                                                "type" : ITEM_VARIABLE, "values" : []})
   387                                                                "type" : ITEM_VARIABLE, "values" : []})
   378                             else:
   388                             else:
   379                                 pou_infos["values"].append({"name" : "%s(%s)"%(variable.getname(), vartype_content["name"]), 
   389                                 pou_infos["values"].append({"name" : "%s(%s)"%(variable.getname(), vartype_content["name"]), 
   380                                                                "type" : ITEM_VARIABLE, "values" : []})
   390                                                                "type" : ITEM_VARIABLE, "values" : []})
   381                 return pou_infos
   391                 return pou_infos
   382             block_infos = GetBlockType(type)
   392             block_infos = self.GetBlockType(type)
   383             if block_infos is not None and block_infos["type"] != "function":
   393             if block_infos is not None and block_infos["type"] != "function":
   384                 pou_infos = {"name" : "%s(%s)"%(name, type), "type" : ITEM_POU, "values" : []}
   394                 pou_infos = {"name" : "%s(%s)"%(name, type), "type" : ITEM_POU, "values" : []}
   385                 for varname, vartype, varmodifier in block_infos["inputs"]:
   395                 for varname, vartype, varmodifier in block_infos["inputs"]:
   386                     pou_infos["values"].append({"name" : "%s(%s)"%(varname, vartype), "type" : ITEM_VARIABLE, "values" : []})
   396                     pou_infos["values"].append({"name" : "%s(%s)"%(varname, vartype), "type" : ITEM_VARIABLE, "values" : []})
   387                 for varname, vartype, varmodifier in block_infos["outputs"]:
   397                 for varname, vartype, varmodifier in block_infos["outputs"]:
   390             
   400             
   391             if type in TypeHierarchy:
   401             if type in TypeHierarchy:
   392                 return {"name" : "%s(%s)"%(name, type), "type" : ITEM_VARIABLE, "values" : []}
   402                 return {"name" : "%s(%s)"%(name, type), "type" : ITEM_VARIABLE, "values" : []}
   393                 
   403                 
   394         return None
   404         return None
   395         
       
   396     # Refresh the tree of user-defined data type cross-use
       
   397     def RefreshDataTypeUsingTree(self):
       
   398         # Reset the tree of user-defined pou cross-use
       
   399         self.DataTypeUsingTree = {}
       
   400         if self.Project:
       
   401             datatypes = self.Project.getdataTypes()
       
   402             # Reference all the user-defined data type names and initialize the tree of 
       
   403             # user-defined data type cross-use
       
   404             datatypenames = [datatype.getname() for datatype in datatypes]
       
   405             for name in datatypenames:
       
   406                 self.DataTypeUsingTree[name] = []
       
   407             # Analyze each data type
       
   408             for datatype in datatypes:
       
   409                 name = datatype.getname()
       
   410                 basetype_content = datatype.getbaseType().getcontent()
       
   411                 if basetype_content["name"] == "derived":
       
   412                     basetype_name = basetype_content["value"].getname()
       
   413                     if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
       
   414                         self.DataTypeUsingTree[basetype_name].append(name)
       
   415                 elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned", "array"]:
       
   416                     base_type = basetype_content["value"].baseType.getcontent()
       
   417                     if base_type["value"] is not None:
       
   418                         basetype_name = base_type["value"].getname()
       
   419                         if basetype_name in datatypenames and name not in self.DataTypeUsingTree[basetype_name]:
       
   420                             self.DataTypeUsingTree[basetype_name].append(name)
       
   421     
       
   422     # Refresh the tree of user-defined pou cross-use
       
   423     def RefreshPouUsingTree(self):
       
   424         # Reset the tree of user-defined pou cross-use
       
   425         self.PouUsingTree = {}
       
   426         if self.Project:
       
   427             pous = self.Project.getpous()
       
   428             # Reference all the user-defined pou names and initialize the tree of 
       
   429             # user-defined pou cross-use
       
   430             pounames = [pou.getname() for pou in pous]
       
   431             for name in pounames:
       
   432                 self.PouUsingTree[name] = []
       
   433             # Analyze each pou 
       
   434             for pou in pous:
       
   435                 name = pou.getname()
       
   436                 if pou.interface:
       
   437                     # Extract variables from every varLists
       
   438                     for type, varlist in pou.getvars():
       
   439                         for var in varlist.getvariable():
       
   440                             vartype_content = var.gettype().getcontent()
       
   441                             if vartype_content["name"] == "derived":
       
   442                                 typename = vartype_content["value"].getname()
       
   443                                 if typename in pounames and name not in self.PouUsingTree[typename]:
       
   444                                     self.PouUsingTree[typename].append(name)
       
   445                 bodytype = pou.getbodyType()
       
   446                 # If pou is written in a graphical language
       
   447                 if bodytype in ["FBD","LD","SFC"]:
       
   448                     # Analyze each instance of the pou
       
   449                     for instance in pou.getinstances():
       
   450                         if isinstance(instance, plcopen.fbdObjects_block):
       
   451                             typename = instance.gettypeName()
       
   452                             # Update tree if there is a cross-use
       
   453                             if typename in pounames and name not in self.PouUsingTree[typename]:
       
   454                                  self.PouUsingTree[typename].append(name)
       
   455                 # If pou is written in a textual language
       
   456                 elif bodytype in ["IL", "ST"]:
       
   457                     text = pou.gettext()
       
   458                     # Search if each pou is mentioned in the pou text
       
   459                     for typename in pounames:
       
   460                         typename_model = re.compile("[ \t\n]%s[ \t\n]"%typename)
       
   461                         # Update tree if there is a cross-use
       
   462                         if typename != name and typename_model.search(text):
       
   463                             self.PouUsingTree[typename].append(name)
       
   464 
   405 
   465     # Return if data type given by name is used by another data type or pou
   406     # Return if data type given by name is used by another data type or pou
   466     def DataTypeIsUsed(self, name):
   407     def DataTypeIsUsed(self, name):
   467         if name in self.DataTypeUsingTree:
   408         return self.Project.ElementIsUsed(name) or self.Project.DataTypeIsDerived(name)
   468             return len(self.DataTypeUsingTree[name]) > 0
       
   469         return False
       
   470 
   409 
   471     # Return if pou given by name is used by another pou
   410     # Return if pou given by name is used by another pou
   472     def PouIsUsed(self, name):
   411     def PouIsUsed(self, name):
   473         if name in self.PouUsingTree:
   412         return self.Project.ElementIsUsed(name)
   474             return len(self.PouUsingTree[name]) > 0
       
   475         return False
       
   476 
       
   477     # Return if data type given by name is directly or undirectly used by the reference data type
       
   478     def DataTypeIsUsedBy(self, name, reference):
       
   479         if name in self.DataTypeUsingTree:
       
   480             list = self.DataTypeUsingTree[name]
       
   481             # Test if data type is directly used by reference
       
   482             if reference in list:
       
   483                 return True
       
   484             else:
       
   485                 # Test if data type is undirectly used by reference, by testing if data types 
       
   486                 # that directly use data type is directly or undirectly used by reference
       
   487                 used = False
       
   488                 for element in list:
       
   489                     used |= self.DataTypeIsUsedBy(element, reference)
       
   490                 return used
       
   491         return False
       
   492 
   413 
   493     # Return if pou given by name is directly or undirectly used by the reference pou
   414     # Return if pou given by name is directly or undirectly used by the reference pou
   494     def PouIsUsedBy(self, name, reference):
   415     def PouIsUsedBy(self, name, reference):
   495         if name in self.PouUsingTree:
   416         return self.Project.ElementIsUsedBy(name, reference)
   496             list = self.PouUsingTree[name]
       
   497             # Test if pou is directly used by reference
       
   498             if reference in list:
       
   499                 return True
       
   500             else:
       
   501                 # Test if pou is undirectly used by reference, by testing if pous 
       
   502                 # that directly use pou is directly or undirectly used by reference
       
   503                 used = False
       
   504                 for element in list:
       
   505                     used |= self.PouIsUsedBy(element, reference)
       
   506                 return used
       
   507         return False
       
   508 
   417 
   509     def GenerateProgram(self, filepath):
   418     def GenerateProgram(self, filepath):
   510         if self.Project:
   419         if self.Project:
   511             try:
   420             try:
   512                 program = GenerateCurrentProgram(self.Project)
   421                 self.ProgramChunks = GenerateCurrentProgram(self, self.Project)
       
   422                 program_text = "".join([item[0] for item in self.ProgramChunks])
   513                 programfile = open(filepath, "w")
   423                 programfile = open(filepath, "w")
   514                 programfile.write(program)
   424                 programfile.write(program_text)
   515                 programfile.close()
   425                 programfile.close()
   516                 self.ProgramFilePath = filepath
   426                 self.ProgramFilePath = filepath
   517                 return None
   427                 return None
   518             except PLCGenException, e:
   428             except PLCGenException, e:
   519                 return e.message
   429                 return e.message
   520         return "No project opened"
   430         return "No project opened"
   521 
   431 
       
   432     def GetChunkInfos(self, from_location, to_location):
       
   433         row = col = 1
       
   434         infos = []
       
   435         for chunk, chunk_infos in self.ProgramChunks:
       
   436             lines = chunk.split("\n")
       
   437             if len(lines) > 1:
       
   438                 next_row = row + len(lines) - 1
       
   439                 next_col = len(lines[-1]) + 1
       
   440             else:
       
   441                 next_col = col + len(chunk)
       
   442             if next_row >= from_location[0] and next_col >= from_location[1] and len(chunk_infos) > 0:
       
   443                 infos.append((chunk_infos, (row, col)))
       
   444             if next_row == to_location[0] and next_col > to_location[1] or next_row > to_location[0]:
       
   445                 return infos
       
   446             row, col = next_row, next_col
       
   447         return infos
       
   448         
   522 #-------------------------------------------------------------------------------
   449 #-------------------------------------------------------------------------------
   523 #                        Project Pous management functions
   450 #                        Project Pous management functions
   524 #-------------------------------------------------------------------------------
   451 #-------------------------------------------------------------------------------
   525     
   452     
   526     # Add a Data Type to Project
   453     # Add a Data Type to Project
   527     def ProjectAddDataType(self, datatype_name):
   454     def ProjectAddDataType(self, datatype_name):
   528         # Add the pou to project
   455         # Add the pou to project
   529         self.Project.appenddataType(datatype_name)
   456         self.Project.appenddataType(datatype_name)
   530         self.RefreshDataTypeUsingTree()
       
   531         self.RefreshDataTypes()
       
   532         self.BufferProject()
   457         self.BufferProject()
   533     
   458     
   534     # Remove a Data Type from project
   459     # Remove a Data Type from project
   535     def ProjectRemoveDataType(self, datatype_name):
   460     def ProjectRemoveDataType(self, datatype_name):
   536         self.Project.removedataType(datatype_name)
   461         self.Project.removedataType(datatype_name)
   537         self.RefreshDataTypeUsingTree()
       
   538         self.RefreshDataTypes()
       
   539         self.BufferProject()
   462         self.BufferProject()
   540     
   463     
   541     # Add a Pou to Project
   464     # Add a Pou to Project
   542     def ProjectAddPou(self, pou_name, pou_type, body_type):
   465     def ProjectAddPou(self, pou_name, pou_type, body_type):
   543         # Add the pou to project
   466         # Add the pou to project
   544         self.Project.appendpou(pou_name, pou_type, body_type)
   467         self.Project.appendpou(pou_name, pou_type, body_type)
   545         if pou_type == "function":
   468         if pou_type == "function":
   546             self.SetPouInterfaceReturnType(pou_name, "BOOL")
   469             self.SetPouInterfaceReturnType(pou_name, "BOOL")
   547         self.RefreshPouUsingTree()
       
   548         self.RefreshBlockTypes()
       
   549         self.BufferProject()
   470         self.BufferProject()
   550     
   471     
   551     # Remove a Pou from project
   472     # Remove a Pou from project
   552     def ProjectRemovePou(self, pou_name):
   473     def ProjectRemovePou(self, pou_name):
   553         self.Project.removepou(pou_name)
   474         self.Project.removepou(pou_name)
   554         self.RefreshPouUsingTree()
       
   555         self.RefreshBlockTypes()
       
   556         self.BufferProject()
   475         self.BufferProject()
   557     
   476     
   558     # Add a configuration to Project
   477     # Add a configuration to Project
   559     def ProjectAddConfiguration(self, config_name):
   478     def ProjectAddConfiguration(self, config_name):
   560         self.Project.addconfiguration(config_name)
   479         self.Project.addconfiguration(config_name)
   616     def ChangePouName(self, old_name, new_name):
   535     def ChangePouName(self, old_name, new_name):
   617         # Found the pou corresponding to old name and change its name to new name
   536         # Found the pou corresponding to old name and change its name to new name
   618         pou = self.Project.getpou(old_name)
   537         pou = self.Project.getpou(old_name)
   619         pou.setname(new_name)
   538         pou.setname(new_name)
   620         self.Project.updateElementName(old_name, new_name)
   539         self.Project.updateElementName(old_name, new_name)
   621         self.RefreshPouUsingTree()
   540         self.Project.RefreshElementUsingTree()
   622         self.RefreshBlockTypes()
   541         self.Project.RefreshCustomBlockTypes()
   623         self.BufferProject()
   542         self.BufferProject()
   624     
   543     
   625     # Change the name of a pou transition
   544     # Change the name of a pou transition
   626     def ChangePouTransitionName(self, pou_name, old_name, new_name):
   545     def ChangePouTransitionName(self, pou_name, old_name, new_name):
   627         # Found the pou transition corresponding to old name and change its name to new name
   546         # Found the pou transition corresponding to old name and change its name to new name
   646         pou = self.Project.getpou(pou_name)
   565         pou = self.Project.getpou(pou_name)
   647         for type, varlist in pou.getvars():
   566         for type, varlist in pou.getvars():
   648             for var in varlist.getvariable():
   567             for var in varlist.getvariable():
   649                 if var.getname() == old_name:
   568                 if var.getname() == old_name:
   650                     var.setname(new_name)
   569                     var.setname(new_name)
   651         self.RefreshBlockTypes()
   570         self.Project.RefreshCustomBlockTypes()
   652         self.BufferProject()
   571         self.BufferProject()
   653         
   572         
   654     # Change the name of a configuration
   573     # Change the name of a configuration
   655     def ChangeConfigurationName(self, old_name, new_name):
   574     def ChangeConfigurationName(self, old_name, new_name):
   656         # Found the configuration corresponding to old name and change its name to new name
   575         # Found the configuration corresponding to old name and change its name to new name
   782         if configuration:
   701         if configuration:
   783             # Set configuration global vars
   702             # Set configuration global vars
   784             configuration.setglobalVars([])
   703             configuration.setglobalVars([])
   785             for vartype, varlist in self.ExtractVarLists(vars):
   704             for vartype, varlist in self.ExtractVarLists(vars):
   786                 configuration.globalVars.append(varlist)
   705                 configuration.globalVars.append(varlist)
   787         self.RefreshBlockTypes()
       
   788     
   706     
   789     # Return the configuration globalvars
   707     # Return the configuration globalvars
   790     def GetConfigurationGlobalVars(self, name):
   708     def GetConfigurationGlobalVars(self, name):
   791         vars = []
   709         vars = []
   792         # Found the configuration corresponding to name
   710         # Found the configuration corresponding to name
   832         # Set resource global vars
   750         # Set resource global vars
   833         if resource:
   751         if resource:
   834             resource.setglobalVars([])
   752             resource.setglobalVars([])
   835             for vartype, varlist in self.ExtractVarLists(vars):
   753             for vartype, varlist in self.ExtractVarLists(vars):
   836                 resource.globalVars.append(varlist)
   754                 resource.globalVars.append(varlist)
   837         self.RefreshBlockTypes()
       
   838     
   755     
   839     # Return the resource globalvars
   756     # Return the resource globalvars
   840     def GetConfigurationResourceGlobalVars(self, config_name, name):
   757     def GetConfigurationResourceGlobalVars(self, config_name, name):
   841         vars = []
   758         vars = []
   842         # Found the resource corresponding to name
   759         # Found the resource corresponding to name
   926         pou = self.Project.getpou(name)
   843         pou = self.Project.getpou(name)
   927         if not pou.interface:
   844         if not pou.interface:
   928             pou.interface = plcopen.pou_interface()
   845             pou.interface = plcopen.pou_interface()
   929         # Set Pou interface
   846         # Set Pou interface
   930         pou.setvars(self.ExtractVarLists(vars))
   847         pou.setvars(self.ExtractVarLists(vars))
   931         self.RefreshPouUsingTree()
   848         self.Project.RefreshElementUsingTree()
   932         self.RefreshBlockTypes()
   849         self.Project.RefreshCustomBlockTypes()
   933     
   850     
   934     # Replace the return type of the pou given by its name (only for functions)
   851     # Replace the return type of the pou given by its name (only for functions)
   935     def SetPouInterfaceReturnType(self, name, type):
   852     def SetPouInterfaceReturnType(self, name, type):
   936         pou = self.Project.getpou(name)
   853         pou = self.Project.getpou(name)
   937         if not pou.interface:
   854         if not pou.interface:
   951                 return_type.setcontent({"name" : type, "value" : None})
   868                 return_type.setcontent({"name" : type, "value" : None})
   952         else:
   869         else:
   953             derived_type = plcopen.derivedTypes_derived()
   870             derived_type = plcopen.derivedTypes_derived()
   954             derived_type.setname(type)
   871             derived_type.setname(type)
   955             return_type.setcontent({"name" : "derived", "value" : derived_type})
   872             return_type.setcontent({"name" : "derived", "value" : derived_type})
   956         self.RefreshBlockTypes()
   873         self.Project.RefreshElementUsingTree()
       
   874         self.Project.RefreshCustomBlockTypes()
   957     
   875     
   958     def UpdateProjectUsedPous(self, old_name, new_name):
   876     def UpdateProjectUsedPous(self, old_name, new_name):
   959         if self.Project:
   877         if self.Project:
   960             self.Project.updateElementName(old_name, new_name)
   878             self.Project.updateElementName(old_name, new_name)
   961     
   879     
   982                 elif returntype_content["name"] in ["string", "wstring"]:
   900                 elif returntype_content["name"] in ["string", "wstring"]:
   983                     return returntype_content["name"].upper()
   901                     return returntype_content["name"].upper()
   984                 else:
   902                 else:
   985                     return returntype_content["name"]
   903                     return returntype_content["name"]
   986         return None
   904         return None
   987     
   905 
   988     # Update data types with user-defined data types added
   906     # Function that add a new plugin to the plugin list
   989     def RefreshDataTypes(self):
   907     def AddPluginBlockList(self, blocklist):
   990         ResetTypeHierarchy()
   908         self.PluginTypes.extend(blocklist)
   991         ResetEnumeratedDataValues()
   909         
       
   910     # Function that clear the plugin list
       
   911     def ClearPluginTypes(self):
       
   912         for i in xrange(len(self.PluginTypes)):
       
   913             self.PluginTypes.pop(0)
       
   914 
       
   915     # Function that returns the block definition associated to the block type given
       
   916     def GetBlockType(self, type, inputs = None):
       
   917         for category in BlockTypes + self.PluginTypes:
       
   918             for blocktype in category["list"]:
       
   919                 if inputs:
       
   920                     block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
       
   921                     same_inputs = inputs == block_inputs
       
   922                 else:
       
   923                     same_inputs = True
       
   924                 if blocktype["name"] == type and same_inputs:
       
   925                     return blocktype
   992         if self.Project:
   926         if self.Project:
   993             for datatype in self.Project.getdataTypes():
   927             return self.Project.GetCustomBlockType(type, inputs)
   994                 name = datatype.getname()
   928         return None
   995                 basetype_content = datatype.getbaseType().getcontent()
   929 
   996                 if basetype_content["value"] is None:
       
   997                     AddDataTypeHierarchy(name, basetype_content["name"])
       
   998                 elif basetype_content["name"] in ["string", "wstring"]:
       
   999                     AddDataTypeHierarchy(name, basetype_content["name"].upper())
       
  1000                 elif basetype_content["name"] == "derived":
       
  1001                     AddDataTypeHierarchy(name, basetype_content["value"].getname())
       
  1002                 elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]:
       
  1003                     base_type = basetype_content["value"].baseType.getcontent()
       
  1004                     if base_type["value"] is None:
       
  1005                         AddDataTypeHierarchy(name, base_type["name"])
       
  1006                     else:
       
  1007                         AddDataTypeHierarchy(name, base_type["value"].getname())
       
  1008                 else:
       
  1009                     if basetype_content["name"] == "enum":
       
  1010                         values = []
       
  1011                         for value in basetype_content["value"].values.getvalue():
       
  1012                             values.append(value.getname())
       
  1013                         AddEnumeratedDataValues(values)
       
  1014                     AddDataTypeHierarchy(name, "ANY_DERIVED")
       
  1015     
       
  1016     # Update Block types with user-defined pou added
       
  1017     def RefreshBlockTypes(self):
       
  1018         if BlockTypes[-1]["name"] == "User-defined POUs":
       
  1019             BlockTypes[-1]["list"] = []
       
  1020         else:
       
  1021             BlockTypes.append({"name" : "User-defined POUs", "list": []})
       
  1022         if self.Project:
       
  1023             for pou in self.Project.getpous():
       
  1024                 pou_name = pou.getname()
       
  1025                 pou_type = pou.getpouType()
       
  1026                 if pou_type != "program":
       
  1027                     block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
       
  1028                                    "inputs" : [], "outputs" : [], "comment" : "",
       
  1029                                    "generate" : generate_block, "initialise" : initialise_block }
       
  1030                     if pou.getinterface():
       
  1031                         for type, varlist in pou.getvars():
       
  1032                             if type == "InOut":
       
  1033                                 for var in varlist.getvariable():
       
  1034                                     var_type = var.type.getcontent()
       
  1035                                     if var_type["name"] == "derived":
       
  1036                                         block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
       
  1037                                         block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none"))
       
  1038                                     elif var_type["name"] in ["string", "wstring"]:
       
  1039                                         block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none"))
       
  1040                                         block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none"))
       
  1041                                     else:
       
  1042                                         block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
       
  1043                                         block_infos["outputs"].append((var.getname(), var_type["name"], "none"))
       
  1044                             elif type == "Input":
       
  1045                                 for var in varlist.getvariable():
       
  1046                                     var_type = var.type.getcontent()
       
  1047                                     if var_type["name"] == "derived":
       
  1048                                         block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none"))
       
  1049                                     elif var_type["name"] in ["string", "wstring"]:
       
  1050                                         block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none"))
       
  1051                                     else:
       
  1052                                         block_infos["inputs"].append((var.getname(), var_type["name"], "none"))
       
  1053                             elif type == "Output":
       
  1054                                 for var in varlist.getvariable():
       
  1055                                     var_type = var.type.getcontent()
       
  1056                                     if var_type["name"] == "derived":
       
  1057                                         block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none"))
       
  1058                                     elif var_type["name"] in ["string", "wstring"]:
       
  1059                                         block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none"))
       
  1060                                     else:
       
  1061                                         block_infos["outputs"].append((var.getname(), var_type["name"], "none"))    
       
  1062                         return_type = pou.interface.getreturnType()
       
  1063                         if return_type:
       
  1064                             var_type = return_type.getcontent()
       
  1065                             if var_type["name"] == "derived":
       
  1066                                 block_infos["outputs"].append(("", var_type["value"].getname(), "none"))
       
  1067                             elif var_type["name"] in ["string", "wstring"]:
       
  1068                                 block_infos["outputs"].append(("", var_type["name"].upper(), "none"))
       
  1069                             else:
       
  1070                                 block_infos["outputs"].append(("", var_type["name"], "none"))
       
  1071                     if pou.getbodyType() in ["FBD","LD","SFC"]:
       
  1072                         for instance in pou.getinstances():
       
  1073                             if isinstance(instance, plcopen.commonObjects_comment):
       
  1074                                 block_infos["comment"] = instance.getcontentText()
       
  1075                     BlockTypes[-1]["list"].append(block_infos)
       
  1076     
       
  1077     # Return Block types checking for recursion
   930     # Return Block types checking for recursion
  1078     def GetBlockTypes(self, tagname = ""):
   931     def GetBlockTypes(self, tagname = ""):
  1079         name = ""
       
  1080         type = None
   932         type = None
  1081         if self.Project:
   933         if self.Project:
       
   934             name = ""
  1082             words = tagname.split("::")
   935             words = tagname.split("::")
  1083             if words[0] in ["P","T","A"]:
   936             if words[0] in ["P","T","A"]:
  1084                 name = words[1]
   937                 name = words[1]
  1085                 type = self.GetPouType(name)
   938                 type = self.GetPouType(name)
  1086         if type == "function":
   939         if type == "function":
  1087             blocktypes = []
   940             blocktypes = []
  1088             for category in BlockTypes[:-1] + PluginTypes:
   941             for category in BlockTypes + self.PluginTypes:
  1089                 cat = {"name" : category["name"], "list" : []}
   942                 cat = {"name" : category["name"], "list" : []}
  1090                 for block in category["list"]:
   943                 for block in category["list"]:
  1091                     if block["type"] == "function":
   944                     if block["type"] == "function":
  1092                         cat["list"].append(block)
   945                         cat["list"].append(block)
  1093                 if len(cat["list"]) > 0:
   946                 if len(cat["list"]) > 0:
  1094                     blocktypes.append(cat)
   947                     blocktypes.append(cat)
  1095         else:
   948         else:
  1096             blocktypes = [category for category in BlockTypes[:-1] + PluginTypes]
   949             blocktypes = [category for category in BlockTypes + self.PluginTypes]
  1097         if self.Project:
   950         if self.Project:
  1098             blocktypes.append({"name" : "User-defined POUs", "list": []})
   951             blocktypes.append({"name" : "User-defined POUs", "list": self.Project.GetCustomBlockTypes(name)})
  1099             for blocktype in BlockTypes[-1]["list"]:
       
  1100                 if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
       
  1101                     blocktypes[-1]["list"].append(blocktype)
       
  1102         return blocktypes
   952         return blocktypes
  1103 
   953 
  1104     # Return Function Block types checking for recursion
   954     # Return Function Block types checking for recursion
  1105     def GetFunctionBlockTypes(self, tagname = ""):
   955     def GetFunctionBlockTypes(self, tagname = ""):
  1106         name = ""
       
  1107         type = None
       
  1108         if self.Project:
       
  1109             words = tagname.split("::")
       
  1110             if words[0] in ["P","T","A"]:
       
  1111                 name = words[1]
       
  1112                 type = self.GetPouType(name)
       
  1113         blocktypes = []
   956         blocktypes = []
  1114         for category in BlockTypes[:-1]:
   957         for category in BlockTypes + self.PluginTypes:
  1115             for block in category["list"]:
   958             for block in category["list"]:
  1116                 if block["type"] != "function":
   959                 if block["type"] != "function":
  1117                     blocktypes.append(block["name"])
   960                     blocktypes.append(block["name"])
  1118         if self.Project:
   961         if self.Project:
  1119             for blocktype in BlockTypes[-1]["list"]:
   962             name = ""
  1120                 if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
   963             words = tagname.split("::")
  1121                     blocktypes.append(blocktype["name"])
   964             if words[0] in ["P","T","A"]:
       
   965                 name = words[1]
       
   966             blocktypes.extend(self.Project.GetCustomFunctionBlockTypes(name))
  1122         return blocktypes
   967         return blocktypes
  1123 
   968 
  1124     # Return Block types checking for recursion
   969     # Return Block types checking for recursion
  1125     def GetBlockResource(self):
   970     def GetBlockResource(self):
  1126         blocktypes = []
   971         blocktypes = []
  1127         for category in BlockTypes[:-1]:
   972         for category in BlockTypes[:-1]:
  1128             for blocktype in category["list"]:
   973             for blocktype in category["list"]:
  1129                 if blocktype["type"] == "program":
   974                 if blocktype["type"] == "program":
  1130                     blocktypes.append(blocktype["name"])
   975                     blocktypes.append(blocktype["name"])
  1131         if self.Project:
   976         if self.Project:
  1132             for pou in self.Project.getpous():
   977             blocktypes.extend(self.Project.GetCustomBlockResource())
  1133                 if pou.getpouType() == "program":
       
  1134                     blocktypes.append(pou.getname())
       
  1135         return blocktypes
   978         return blocktypes
  1136 
   979 
  1137     # Return Data Types checking for recursion
   980     # Return Data Types checking for recursion
  1138     def GetDataTypes(self, tagname = "", basetypes = True):
   981     def GetDataTypes(self, tagname = "", basetypes = True):
  1139         if basetypes:
   982         if basetypes:
  1140             datatypes = self.GetBaseTypes()
   983             datatypes = self.GetBaseTypes()
  1141         else:
   984         else:
  1142             datatypes = []
   985             datatypes = []
  1143         if self.Project:
   986         if self.Project:
       
   987             name = ""
  1144             words = tagname.split("::")
   988             words = tagname.split("::")
  1145             if words[0] in ["D"]:
   989             if words[0] in ["D"]:
  1146                 name = words[1]
   990                 name = words[1]
  1147             else:
   991             datatypes.extend(self.Project.GetCustomDataTypes(name))
  1148                 name = ""
       
  1149             for datatype in self.Project.getdataTypes():
       
  1150                 datatype_name = datatype.getname()
       
  1151                 if datatype_name != name and not self.DataTypeIsUsedBy(name, datatype_name):
       
  1152                     datatypes.append(datatype_name)
       
  1153         return datatypes
   992         return datatypes
  1154 
   993 
  1155     # Return Base Type of given possible derived type
   994     # Return Base Type of given possible derived type
  1156     def GetBaseType(self, type):
   995     def GetBaseType(self, type):
  1157         return GetBaseType(type)
   996         if self.Project:
       
   997             return self.Project.GetBaseType(type)
       
   998         return None
  1158 
   999 
  1159     # Return Base Types
  1000     # Return Base Types
  1160     def GetBaseTypes(self):
  1001     def GetBaseTypes(self):
  1161         return [value for value, parent in TypeHierarchy_list if not value.startswith("ANY")]
  1002         return [value for value in TypeHierarchy.keys() if not value.startswith("ANY")]
  1162 
  1003 
       
  1004     def IsOfType(self, type, reference):
       
  1005         if self.Project:
       
  1006             return self.Project.IsOfType(type, reference)
       
  1007         elif reference is None:
       
  1008             return True
       
  1009         elif type == reference:
       
  1010             return True
       
  1011         else:
       
  1012             if type in TypeHierarchy:
       
  1013                 return self.IsOfType(TypeHierarchy[type], reference)
       
  1014         return None
       
  1015     
       
  1016     def IsEndType(self, type):
       
  1017         if type is not None:
       
  1018             return not type.startswith("ANY")
       
  1019         return True
       
  1020 
       
  1021     def GetDataTypeRange(self, type):
       
  1022         if self.Project:
       
  1023             return self.Project.GetDataTypeRange(type)
       
  1024         elif type in DataTypeRange:
       
  1025             return DataTypeRange[type]
       
  1026         return None
       
  1027     
  1163     # Return Subrange types
  1028     # Return Subrange types
  1164     def GetSubrangeTypes(self):
  1029     def GetSubrangeBaseTypes(self, exclude):
  1165         return [value for value, range in DataTypeRange_list]
  1030         if self.Project:
  1166 
  1031             return self.Project.GetSubrangeBaseTypes(exclude)
       
  1032         return []
       
  1033     
  1167     # Return Enumerated Values
  1034     # Return Enumerated Values
  1168     def GetEnumeratedDataValues(self):
  1035     def GetEnumeratedDataValues(self):
  1169         return EnumeratedDataValues
  1036         if self.Project:
       
  1037             return self.Project.GetEnumeratedDataTypeValues()
       
  1038         return []
  1170 
  1039 
  1171 #-------------------------------------------------------------------------------
  1040 #-------------------------------------------------------------------------------
  1172 #                   Project Element tag name computation functions
  1041 #                   Project Element tag name computation functions
  1173 #-------------------------------------------------------------------------------
  1042 #-------------------------------------------------------------------------------
  1174     
  1043     
  1193         return "C::%s" % config
  1062         return "C::%s" % config
  1194 
  1063 
  1195     # Compute a pou  name
  1064     # Compute a pou  name
  1196     def ComputeConfigurationResourceName(self, config, resource):
  1065     def ComputeConfigurationResourceName(self, config, resource):
  1197         return "R::%s::%s" % (config, resource)
  1066         return "R::%s::%s" % (config, resource)
       
  1067 
       
  1068     def GetElementType(self, tagname):
       
  1069         words = tagname.split("::")
       
  1070         return {"D" : ITEM_DATATYPE, "P" : ITEM_POU, 
       
  1071                 "T" : ITEM_TRANSITION, "A" : ITEM_ACTION,
       
  1072                 "C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]]
  1198 
  1073 
  1199 #-------------------------------------------------------------------------------
  1074 #-------------------------------------------------------------------------------
  1200 #                    Project opened Data types management functions
  1075 #                    Project opened Data types management functions
  1201 #-------------------------------------------------------------------------------
  1076 #-------------------------------------------------------------------------------
  1202 
  1077 
  1312                 if datatype.initialValue is None:
  1187                 if datatype.initialValue is None:
  1313                     datatype.initialValue = plcopen.value()
  1188                     datatype.initialValue = plcopen.value()
  1314                 datatype.initialValue.setvalue(infos["initial"])
  1189                 datatype.initialValue.setvalue(infos["initial"])
  1315             else:
  1190             else:
  1316                 datatype.initialValue = None
  1191                 datatype.initialValue = None
  1317             self.RefreshDataTypeUsingTree()
  1192             self.Project.RefreshDataTypeHierarchy()
  1318             self.RefreshDataTypes()
       
  1319             self.BufferProject()
  1193             self.BufferProject()
  1320     
  1194     
  1321 #-------------------------------------------------------------------------------
  1195 #-------------------------------------------------------------------------------
  1322 #                       Project opened Pous management functions
  1196 #                       Project opened Pous management functions
  1323 #-------------------------------------------------------------------------------
  1197 #-------------------------------------------------------------------------------
  1324 
  1198 
  1325     # Return edited element
  1199     # Return edited element
  1326     def GetEditedElement(self, tagname):
  1200     def GetEditedElement(self, tagname):
  1327         words = tagname.split("::")
  1201         words = tagname.split("::")
  1328         if words[0] == "P":
  1202         if words[0] == "D":
       
  1203             return self.Project.getdataType(words[1])
       
  1204         elif words[0] == "P":
  1329             return self.Project.getpou(words[1])
  1205             return self.Project.getpou(words[1])
  1330         if words[0] in ['T', 'A']:
  1206         elif words[0] in ['T', 'A']:
  1331             pou = self.Project.getpou(words[1])
  1207             pou = self.Project.getpou(words[1])
  1332             if words[0] == 'T':
  1208             if words[0] == 'T':
  1333                 return pou.gettransition(words[2])
  1209                 return pou.gettransition(words[2])
  1334             elif words[0] == 'A':
  1210             elif words[0] == 'A':
  1335                 return pou.getaction(words[2])
  1211                 return pou.getaction(words[2])
  1340         return None
  1216         return None
  1341     
  1217     
  1342     # Return edited element name
  1218     # Return edited element name
  1343     def GetEditedElementName(self, tagname):
  1219     def GetEditedElementName(self, tagname):
  1344         words = tagname.split("::")
  1220         words = tagname.split("::")
  1345         if words[0] in ["P","C"]:
  1221         if words[0] in ["P","C","D"]:
  1346             return words[1]
  1222             return words[1]
  1347         else:
  1223         else:
  1348             return words[2]
  1224             return words[2]
  1349         return None
  1225         return None
  1350     
  1226     
  1788         element = self.GetEditedElement(tagname)
  1664         element = self.GetEditedElement(tagname)
  1789         if element is not None:
  1665         if element is not None:
  1790             block = plcopen.fbdObjects_block()
  1666             block = plcopen.fbdObjects_block()
  1791             block.setlocalId(id)
  1667             block.setlocalId(id)
  1792             block.settypeName(blocktype)
  1668             block.settypeName(blocktype)
  1793             blocktype_infos = GetBlockType(blocktype)
  1669             blocktype_infos = self.GetBlockType(blocktype)
  1794             if blocktype_infos["type"] != "function" and blockname is not None:
  1670             if blocktype_infos["type"] != "function" and blockname is not None:
  1795                 block.setinstanceName(blockname)
  1671                 block.setinstanceName(blockname)
  1796                 self.AddEditedElementPouVar(tagname, blocktype, blockname)
  1672                 self.AddEditedElementPouVar(tagname, blocktype, blockname)
  1797             element.addinstance("block", block)
  1673             element.addinstance("block", block)
  1798             self.RefreshPouUsingTree()
  1674             self.RefreshPouUsingTree()
  1805                 return 
  1681                 return 
  1806             old_name = block.getinstanceName()
  1682             old_name = block.getinstanceName()
  1807             old_type = block.gettypeName()
  1683             old_type = block.gettypeName()
  1808             new_name = infos.get("name", old_name)
  1684             new_name = infos.get("name", old_name)
  1809             new_type = infos.get("type", old_type)
  1685             new_type = infos.get("type", old_type)
  1810             old_typeinfos = GetBlockType(old_type)
  1686             old_typeinfos = self.GetBlockType(old_type)
  1811             new_typeinfos = GetBlockType(new_type)
  1687             new_typeinfos = self.GetBlockType(new_type)
  1812             if new_typeinfos["type"] != old_typeinfos["type"]:
  1688             if new_typeinfos["type"] != old_typeinfos["type"]:
  1813                 if new_typeinfos["type"] == "function":
  1689                 if new_typeinfos["type"] == "function":
  1814                     self.RemoveEditedElementPouVar(tagname, old_type, old_name)
  1690                     self.RemoveEditedElementPouVar(tagname, old_type, old_name)
  1815                 else:
  1691                 else:
  1816                     self.AddEditedElementPouVar(tagname, new_type, new_name)
  1692                     self.AddEditedElementPouVar(tagname, new_type, new_name)
  2461         self.Project = plcopen.project()
  2337         self.Project = plcopen.project()
  2462         for child in tree.childNodes:
  2338         for child in tree.childNodes:
  2463             if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project":
  2339             if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project":
  2464                 self.Project.loadXMLTree(child, ["xmlns", "xmlns:xhtml", "xmlns:xsi", "xsi:schemaLocation"])
  2340                 self.Project.loadXMLTree(child, ["xmlns", "xmlns:xhtml", "xmlns:xsi", "xsi:schemaLocation"])
  2465                 self.SetFilePath(filepath)
  2341                 self.SetFilePath(filepath)
       
  2342                 self.Project.RefreshElementUsingTree()
       
  2343                 self.Project.RefreshDataTypeHierarchy()
       
  2344                 self.Project.RefreshCustomBlockTypes()
  2466                 self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), True)
  2345                 self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), True)
  2467                 self.Buffering = False
  2346                 self.Buffering = False
  2468                 self.ElementsOpened = []
  2347                 self.ElementsOpened = []
  2469                 self.CurrentElementEditing = None
  2348                 self.CurrentElementEditing = None
  2470                 self.RefreshDataTypeUsingTree()
       
  2471                 self.RefreshDataTypes()
       
  2472                 self.RefreshPouUsingTree()
       
  2473                 self.RefreshBlockTypes()
       
  2474                 return None
  2349                 return None
  2475         return "No PLC project found"
  2350         return "No PLC project found"
  2476 
  2351 
  2477     def SaveXMLFile(self, filepath = None):
  2352     def SaveXMLFile(self, filepath = None):
  2478         if not filepath and self.FilePath == "":
  2353         if not filepath and self.FilePath == "":