diff -r 1460273f40ed -r 5743cbdff669 PLCControler.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PLCControler.py Fri Sep 07 16:45:55 2012 +0200 @@ -0,0 +1,3043 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from xml.dom import minidom +from types import StringType, UnicodeType, TupleType +import cPickle +import os,sys,re +import datetime +from time import localtime + +from plcopen import plcopen +from plcopen.structures import * +from graphics.GraphicCommons import * +from PLCGenerator import * + +duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?") + +ITEMS_EDITABLE = [ITEM_PROJECT, + ITEM_POU, + ITEM_VARIABLE, + ITEM_TRANSITION, + ITEM_ACTION, + ITEM_CONFIGURATION, + ITEM_RESOURCE, + ITEM_DATATYPE + ] = range(8) + +ITEMS_UNEDITABLE = [ITEM_DATATYPES, + ITEM_FUNCTION, + ITEM_FUNCTIONBLOCK, + ITEM_PROGRAM, + ITEM_TRANSITIONS, + ITEM_ACTIONS, + ITEM_CONFIGURATIONS, + ITEM_RESOURCES, + ITEM_PROPERTIES + ] = range(8, 17) + +ITEMS_VARIABLE = [ITEM_VAR_LOCAL, + ITEM_VAR_GLOBAL, + ITEM_VAR_EXTERNAL, + ITEM_VAR_TEMP, + ITEM_VAR_INPUT, + ITEM_VAR_OUTPUT, + ITEM_VAR_INOUT + ] = range(17, 24) + +VAR_CLASS_INFOS = {"Local" : (plcopen.interface_localVars, ITEM_VAR_LOCAL), + "Global" : (plcopen.interface_globalVars, ITEM_VAR_GLOBAL), + "External" : (plcopen.interface_externalVars, ITEM_VAR_EXTERNAL), + "Temp" : (plcopen.interface_tempVars, ITEM_VAR_TEMP), + "Input" : (plcopen.interface_inputVars, ITEM_VAR_INPUT), + "Output" : (plcopen.interface_outputVars, ITEM_VAR_OUTPUT), + "InOut" : (plcopen.interface_inOutVars, ITEM_VAR_INOUT) + } + +POU_TYPES = {"program": ITEM_PROGRAM, + "functionBlock": ITEM_FUNCTIONBLOCK, + "function": ITEM_FUNCTION, + } + +LOCATIONS_ITEMS = [LOCATION_CONFNODE, + LOCATION_MODULE, + LOCATION_GROUP, + LOCATION_VAR_INPUT, + LOCATION_VAR_OUTPUT, + LOCATION_VAR_MEMORY] = range(6) + +ScriptDirectory = os.path.split(os.path.realpath(__file__))[0] + +def GetUneditableNames(): + _ = lambda x:x + return [_("User-defined POUs"), _("Functions"), _("Function Blocks"), + _("Programs"), _("Data Types"), _("Transitions"), _("Actions"), + _("Configurations"), _("Resources"), _("Properties")] +UNEDITABLE_NAMES = GetUneditableNames() +[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS, + DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS, + RESOURCES, PROPERTIES] = UNEDITABLE_NAMES + +#------------------------------------------------------------------------------- +# Undo Buffer for PLCOpenEditor +#------------------------------------------------------------------------------- + +# Length of the buffer +UNDO_BUFFER_LENGTH = 20 + +""" +Class implementing a buffer of changes made on the current editing model +""" +class UndoBuffer: + + # Constructor initialising buffer + def __init__(self, currentstate, issaved = False): + self.Buffer = [] + self.CurrentIndex = -1 + self.MinIndex = -1 + self.MaxIndex = -1 + # if current state is defined + if currentstate: + self.CurrentIndex = 0 + self.MinIndex = 0 + self.MaxIndex = 0 + # Initialising buffer with currentstate at the first place + for i in xrange(UNDO_BUFFER_LENGTH): + if i == 0: + self.Buffer.append(currentstate) + else: + self.Buffer.append(None) + # Initialising index of state saved + if issaved: + self.LastSave = 0 + else: + self.LastSave = -1 + + # Add a new state in buffer + def Buffering(self, currentstate): + self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH + self.Buffer[self.CurrentIndex] = currentstate + # Actualising buffer limits + self.MaxIndex = self.CurrentIndex + if self.MinIndex == self.CurrentIndex: + # If the removed state was the state saved, there is no state saved in the buffer + if self.LastSave == self.MinIndex: + self.LastSave = -1 + self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH + self.MinIndex = max(self.MinIndex, 0) + + # Return current state of buffer + def Current(self): + return self.Buffer[self.CurrentIndex] + + # Change current state to previous in buffer and return new current state + def Previous(self): + if self.CurrentIndex != self.MinIndex: + self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH + return self.Buffer[self.CurrentIndex] + return None + + # Change current state to next in buffer and return new current state + def Next(self): + if self.CurrentIndex != self.MaxIndex: + self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH + return self.Buffer[self.CurrentIndex] + return None + + # Return True if current state is the first in buffer + def IsFirst(self): + return self.CurrentIndex == self.MinIndex + + # Return True if current state is the last in buffer + def IsLast(self): + return self.CurrentIndex == self.MaxIndex + + # Note that current state is saved + def CurrentSaved(self): + self.LastSave = self.CurrentIndex + + # Return True if current state is saved + def IsCurrentSaved(self): + return self.LastSave == self.CurrentIndex + + +#------------------------------------------------------------------------------- +# Controler for PLCOpenEditor +#------------------------------------------------------------------------------- + +""" +Class which controls the operations made on the plcopen model and answers to view requests +""" +class PLCControler: + + # Create a new PLCControler + def __init__(self): + self.LastNewIndex = 0 + self.Reset() + + # Reset PLCControler internal variables + def Reset(self): + self.Project = None + self.ProjectBufferEnabled = True + self.ProjectBuffer = None + self.ProjectSaved = True + self.Buffering = False + self.FilePath = "" + self.FileName = "" + self.ProgramChunks = [] + self.ProgramOffset = 0 + self.NextCompiledProject = None + self.CurrentCompiledProject = None + self.ConfNodeTypes = [] + self.ProgramFilePath = "" + + def GetQualifierTypes(self): + return plcopen.QualifierList + + def GetProject(self, debug = False): + if debug and self.CurrentCompiledProject is not None: + return self.CurrentCompiledProject + else: + return self.Project + +#------------------------------------------------------------------------------- +# Project management functions +#------------------------------------------------------------------------------- + + # Return if a project is opened + def HasOpenedProject(self): + return self.Project is not None + + # Create a new project by replacing the current one + def CreateNewProject(self, properties): + # Create the project + self.Project = plcopen.project() + properties["creationDateTime"] = datetime.datetime(*localtime()[:6]) + self.Project.setfileHeader(properties) + self.Project.setcontentHeader(properties) + self.SetFilePath("") + # Initialize the project buffer + self.CreateProjectBuffer(False) + self.ProgramChunks = [] + self.ProgramOffset = 0 + self.NextCompiledProject = self.Copy(self.Project) + self.CurrentCompiledProject = None + self.Buffering = False + + # Return project data type names + def GetProjectDataTypeNames(self, debug = False): + project = self.GetProject(debug) + if project is not None: + return [datatype.getname() for datatype in project.getdataTypes()] + return [] + + # Return project pou names + def GetProjectPouNames(self, debug = False): + project = self.GetProject(debug) + if project is not None: + return [pou.getname() for pou in project.getpous()] + return [] + + # Return project pou names + def GetProjectConfigNames(self, debug = False): + project = self.GetProject(debug) + if project is not None: + return [config.getname() for config in project.getconfigurations()] + return [] + + # Return project pou variables + def GetProjectPouVariables(self, pou_name = None, debug = False): + variables = [] + project = self.GetProject(debug) + if project is not None: + for pou in project.getpous(): + if pou_name is None or pou_name == pou.getname(): + variables.extend([var["Name"] for var in self.GetPouInterfaceVars(pou, debug)]) + for transition in pou.gettransitionList(): + variables.append(transition.getname()) + for action in pou.getactionList(): + variables.append(action.getname()) + return variables + + # Return file path if project is an open file + def GetFilePath(self): + return self.FilePath + + # Return file path if project is an open file + def GetProgramFilePath(self): + return self.ProgramFilePath + + # Return file name and point out if file is up to date + def GetFilename(self): + if self.Project is not None: + if self.ProjectIsSaved(): + return self.FileName + else: + return "~%s~"%self.FileName + return "" + + # Change file path and save file name or create a default one if file path not defined + def SetFilePath(self, filepath): + self.FilePath = filepath + if filepath == "": + self.LastNewIndex += 1 + self.FileName = _("Unnamed%d")%self.LastNewIndex + else: + self.FileName = os.path.splitext(os.path.basename(filepath))[0] + + # Change project properties + def SetProjectProperties(self, name = None, properties = None, buffer = True): + if self.Project is not None: + if name is not None: + self.Project.setname(name) + if properties is not None: + self.Project.setfileHeader(properties) + self.Project.setcontentHeader(properties) + if buffer and (name is not None or properties is not None): + self.BufferProject() + + # Return project name + def GetProjectName(self, debug=False): + project = self.GetProject(debug) + if project is not None: + return project.getname() + return None + + # Return project properties + def GetProjectProperties(self, debug = False): + project = self.GetProject(debug) + if project is not None: + properties = project.getfileHeader() + properties.update(project.getcontentHeader()) + return properties + return None + + # Return project informations + def GetProjectInfos(self, debug = False): + project = self.GetProject(debug) + if project is not None: + infos = {"name": project.getname(), "type": ITEM_PROJECT} + datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]} + for datatype in project.getdataTypes(): + datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE, + "tagname": self.ComputeDataTypeName(datatype.getname()), "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":[]}} + for pou in project.getpous(): + pou_type = pou.getpouType() + 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, + "tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()), + "values": []}) + pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions}) + actions = [] + for action in pou.getactionList(): + actions.append({"name": action.getname(), "type": ITEM_ACTION, + "tagname": self.ComputePouActionName(pou.getname(), action.getname()), + "values": []}) + pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "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": []} + for config in project.getconfigurations(): + config_name = config.getname() + config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, + "tagname": self.ComputeConfigurationName(config.getname()), + "values": []} + resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []} + for resource in config.getresource(): + resource_name = resource.getname() + 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"] = [datatypes, pou_types["function"], pou_types["functionBlock"], + pou_types["program"], configurations] + return infos + return None + + def GetPouVariableInfos(self, project, variable, var_class, debug=False): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + var_type = vartype_content["value"].getname() + pou_type = None + pou = project.getpou(var_type) + if pou is not None: + pou_type = pou.getpouType() + edit = debug = pou_type is not None + if pou_type is None: + block_infos = self.GetBlockType(var_type, debug = debug) + if block_infos is not None: + pou_type = block_infos["type"] + if pou_type is not None: + var_class = None + if pou_type == "program": + var_class = ITEM_PROGRAM + elif pou_type != "function": + var_class = ITEM_FUNCTIONBLOCK + if var_class is not None: + return {"name": variable.getname(), + "type": var_type, + "class": var_class, + "edit": edit, + "debug": debug} + elif var_type in self.GetDataTypes(debug = debug): + return {"name": variable.getname(), + "type": var_type, + "class": var_class, + "edit": False, + "debug": False} + elif vartype_content["name"] in ["string", "wstring"]: + return {"name": variable.getname(), + "type": vartype_content["name"].upper(), + "class": var_class, + "edit": False, + "debug": True} + else: + return {"name": variable.getname(), + "type": vartype_content["name"], + "class": var_class, + "edit": False, + "debug": True} + return None + + def GetPouVariables(self, tagname, debug = False): + vars = [] + pou_type = None + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "P": + pou = project.getpou(words[1]) + if pou is not None: + pou_type = pou.getpouType() + if (pou_type in ["program", "functionBlock"] and + pou.interface is not None): + # Extract variables from every varLists + for varlist_type, varlist in pou.getvars(): + var_infos = VAR_CLASS_INFOS.get(varlist_type, None) + if var_infos is not None: + var_class = var_infos[1] + else: + var_class = ITEM_VAR_LOCAL + for variable in varlist.getvariable(): + var_infos = self.GetPouVariableInfos(project, variable, var_class, debug) + if var_infos is not None: + vars.append(var_infos) + return {"class": POU_TYPES[pou_type], + "type": words[1], + "variables": vars, + "edit": True, + "debug": True} + else: + block_infos = self.GetBlockType(words[1], debug = debug) + if (block_infos is not None and + block_infos["type"] in ["program", "functionBlock"]): + for varname, vartype, varmodifier in block_infos["inputs"]: + vars.append({"name" : varname, + "type" : vartype, + "class" : ITEM_VAR_INPUT, + "edit": False, + "debug": True}) + for varname, vartype, varmodifier in block_infos["outputs"]: + vars.append({"name" : varname, + "type" : vartype, + "class" : ITEM_VAR_OUTPUT, + "edit": False, + "debug": True}) + return {"class": POU_TYPES[block_infos["type"]], + "type": None, + "variables": vars, + "edit": False, + "debug": False} + elif words[0] in ['C', 'R']: + if words[0] == 'C': + element_type = ITEM_CONFIGURATION + element = project.getconfiguration(words[1]) + if element is not None: + for resource in element.getresource(): + vars.append({"name": resource.getname(), + "type": None, + "class": ITEM_RESOURCE, + "edit": True, + "debug": False}) + elif words[0] == 'R': + element_type = ITEM_RESOURCE + element = project.getconfigurationResource(words[1], words[2]) + if element is not None: + for task in element.gettask(): + for pou in task.getpouInstance(): + vars.append({"name": pou.getname(), + "type": pou.gettypeName(), + "class": ITEM_PROGRAM, + "edit": True, + "debug": True}) + for pou in element.getpouInstance(): + vars.append({"name": pou.getname(), + "type": pou.gettypeName(), + "class": ITEM_PROGRAM, + "edit": True, + "debug": True}) + if element is not None: + for varlist in element.getglobalVars(): + for variable in varlist.getvariable(): + var_infos = self.GetPouVariableInfos(project, variable, ITEM_VAR_GLOBAL, debug) + if var_infos is not None: + vars.append(var_infos) + return {"class": element_type, + "type": None, + "variables": vars, + "edit": True, + "debug": False} + return None + + def RecursiveSearchPouInstances(self, project, pou_type, parent_path, varlists, debug = False): + instances = [] + for varlist in varlists: + for variable in varlist.getvariable(): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + var_path = "%s.%s" % (parent_path, variable.getname()) + var_type = vartype_content["value"].getname() + if var_type == pou_type: + instances.append(var_path) + else: + pou = project.getpou(var_type) + if pou is not None: + instances.extend( + self.RecursiveSearchPouInstances( + project, pou_type, var_path, + [varlist for type, varlist in pou.getvars()], + debug)) + return instances + + def SearchPouInstances(self, tagname, debug = False): + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "P": + instances = [] + for config in project.getconfigurations(): + config_name = config.getname() + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], config_name, + config.getglobalVars(), debug)) + for resource in config.getresource(): + res_path = "%s.%s" % (config_name, resource.getname()) + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], res_path, + resource.getglobalVars(), debug)) + pou_instances = resource.getpouInstance()[:] + for task in resource.gettask(): + pou_instances.extend(task.getpouInstance()) + for pou_instance in pou_instances: + pou_path = "%s.%s" % (res_path, pou_instance.getname()) + pou_type = pou_instance.gettypeName() + if pou_type == words[1]: + instances.append(pou_path) + pou = project.getpou(pou_type) + if pou is not None: + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], pou_path, + [varlist for type, varlist in pou.getvars()], + debug)) + return instances + elif words[0] == 'C': + return [words[1]] + elif words[0] == 'R': + return ["%s.%s" % (words[1], words[2])] + return [] + + def RecursiveGetPouInstanceTagName(self, project, pou_type, parts): + pou = project.getpou(pou_type) + if pou is not None: + if len(parts) == 0: + return self.ComputePouName(pou_type) + + for varlist_type, varlist in pou.getvars(): + for variable in varlist.getvariable(): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + return self.RecursiveGetPouInstanceTagName( + project, + vartype_content["value"].getname(), + parts[1:]) + return None + + def GetPouInstanceTagName(self, instance_path, debug = False): + parts = instance_path.split(".") + if len(parts) == 1: + return self.ComputeConfigurationName(parts[0]) + elif len(parts) == 2: + return self.ComputeConfigurationResourceName(parts[0], parts[1]) + else: + project = self.GetProject(debug) + for config in project.getconfigurations(): + if config.getname() == parts[0]: + for resource in config.getresource(): + if resource.getname() == parts[1]: + pou_instances = resource.getpouInstance()[:] + for task in resource.gettask(): + pou_instances.extend(task.getpouInstance()) + for pou_instance in pou_instances: + if pou_instance.getname() == parts[2]: + if len(parts) == 3: + return self.ComputePouName( + pou_instance.gettypeName()) + else: + return self.RecursiveGetPouInstanceTagName( + project, + pou_instance.gettypeName(), + parts[3:]) + return None + + def GetInstanceInfos(self, instance_path, debug = False): + tagname = self.GetPouInstanceTagName(instance_path) + if tagname is not None: + return self.GetPouVariables(tagname, debug) + else: + pou_path, var_name = instance_path.rsplit(".", 1) + tagname = self.GetPouInstanceTagName(pou_path) + if tagname is not None: + pou_infos = self.GetPouVariables(tagname, debug) + for var_infos in pou_infos["variables"]: + if var_infos["name"] == var_name: + return var_infos + return None + + # Return if data type given by name is used by another data type or pou + def DataTypeIsUsed(self, name, debug = False): + project = self.GetProject(debug) + if project is not None: + return project.ElementIsUsed(name) or project.DataTypeIsDerived(name) + return False + + # Return if pou given by name is used by another pou + def PouIsUsed(self, name, debug = False): + project = self.GetProject(debug) + if project is not None: + return project.ElementIsUsed(name) + return False + + # Return if pou given by name is directly or undirectly used by the reference pou + def PouIsUsedBy(self, name, reference, debug = False): + project = self.GetProject(debug) + if project is not None: + return project.ElementIsUsedBy(name, reference) + return False + + def GenerateProgram(self, filepath=None): + errors = [] + warnings = [] + if self.Project is not None: + try: + self.ProgramChunks = GenerateCurrentProgram(self, self.Project, errors, warnings) + self.NextCompiledProject = self.Copy(self.Project) + program_text = "".join([item[0].decode("utf-8") for item in self.ProgramChunks]) + if filepath is not None: + programfile = open(filepath, "w") + programfile.write(program_text.encode("utf-8")) + programfile.close() + self.ProgramFilePath = filepath + return program_text, errors, warnings + except PLCGenException, e: + errors.append(e.message) + else: + errors.append("No project opened") + return "", errors, warnings + + def DebugAvailable(self): + return self.CurrentCompiledProject is not None + + def ProgramTransferred(self): + if self.NextCompiledProject is None: + self.CurrentCompiledProject = self.NextCompiledProject + else: + self.CurrentCompiledProject = self.Copy(self.Project) + + def GetChunkInfos(self, from_location, to_location): + row = self.ProgramOffset + 1 + 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_row = row + next_col = col + len(chunk) + if (next_row > from_location[0] or 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 +#------------------------------------------------------------------------------- + + # Add a Data Type to Project + def ProjectAddDataType(self, datatype_name=None): + if self.Project is not None: + if datatype_name is None: + datatype_name = self.GenerateNewName(None, None, "datatype%d") + # Add the datatype to project + self.Project.appenddataType(datatype_name) + self.BufferProject() + return self.ComputeDataTypeName(datatype_name) + return None + + # Remove a Data Type from project + def ProjectRemoveDataType(self, datatype_name): + if self.Project is not None: + self.Project.removedataType(datatype_name) + self.BufferProject() + + # Add a Pou to Project + def ProjectAddPou(self, pou_name, pou_type, body_type): + if self.Project is not None: + # Add the pou to project + self.Project.appendpou(pou_name, pou_type, body_type) + if pou_type == "function": + self.SetPouInterfaceReturnType(pou_name, "BOOL") + self.BufferProject() + return self.ComputePouName(pou_name) + return None + + def ProjectChangePouType(self, name, pou_type): + if self.Project is not None: + pou = self.Project.getpou(name) + if pou is not None: + pou.setpouType(pou_type) + self.Project.RefreshCustomBlockTypes() + self.BufferProject() + + def GetPouXml(self, pou_name): + if self.Project is not None: + pou = self.Project.getpou(pou_name) + if pou is not None: + return pou.generateXMLText('pou', 0) + return None + + def PastePou(self, pou_type, pou_xml): + ''' + Adds the POU defined by 'pou_xml' to the current project with type 'pou_type' + ''' + try: + tree = minidom.parseString(pou_xml.encode("utf-8")) + root = tree.childNodes[0] + except: + return _("Couldn't paste non-POU object.") + + if root.nodeName == "pou": + new_pou = plcopen.pous_pou() + new_pou.loadXMLTree(root) + + name = new_pou.getname() + + idx = 0 + new_name = name + while self.Project.getpou(new_name): + # a POU with that name already exists. + # make a new name and test if a POU with that name exists. + # append an incrementing numeric suffix to the POU name. + idx += 1 + new_name = "%s%d" % (name, idx) + + # we've found a name that does not already exist, use it + new_pou.setname(new_name) + + if pou_type is not None: + orig_type = new_pou.getpouType() + + # prevent violations of POU content restrictions: + # function blocks cannot be pasted as functions, + # programs cannot be pasted as functions or function blocks + if orig_type == 'functionBlock' and pou_type == 'function' or \ + orig_type == 'program' and pou_type in ['function', 'functionBlock']: + return _('''%s "%s" can't be pasted as a %s.''') % (orig_type, name, pou_type) + + new_pou.setpouType(pou_type) + + self.Project.insertpou(-1, new_pou) + self.BufferProject() + + return self.ComputePouName(new_name), + else: + return _("Couldn't paste non-POU object.") + + # Remove a Pou from project + def ProjectRemovePou(self, pou_name): + if self.Project is not None: + self.Project.removepou(pou_name) + self.BufferProject() + + # Return the name of the configuration if only one exist + def GetProjectMainConfigurationName(self): + if self.Project is not None: + # Found the configuration corresponding to old name and change its name to new name + configurations = self.Project.getconfigurations() + if len(configurations) == 1: + return configurations[0].getname() + return None + + # Add a configuration to Project + def ProjectAddConfiguration(self, config_name=None): + if self.Project is not None: + if config_name is None: + config_name = self.GenerateNewName(None, None, "configuration%d") + self.Project.addconfiguration(config_name) + self.BufferProject() + return self.ComputeConfigurationName(config_name) + return None + + # Remove a configuration from project + def ProjectRemoveConfiguration(self, config_name): + if self.Project is not None: + self.Project.removeconfiguration(config_name) + self.BufferProject() + + # Add a resource to a configuration of the Project + def ProjectAddConfigurationResource(self, config_name, resource_name=None): + if self.Project is not None: + if resource_name is None: + resource_name = self.GenerateNewName(None, None, "resource%d") + self.Project.addconfigurationResource(config_name, resource_name) + self.BufferProject() + return self.ComputeConfigurationResourceName(config_name, resource_name) + return None + + # Remove a resource from a configuration of the project + def ProjectRemoveConfigurationResource(self, config_name, resource_name): + if self.Project is not None: + self.Project.removeconfigurationResource(config_name, resource_name) + self.BufferProject() + + # Add a Transition to a Project Pou + def ProjectAddPouTransition(self, pou_name, transition_name, transition_type): + if self.Project is not None: + pou = self.Project.getpou(pou_name) + if pou is not None: + pou.addtransition(transition_name, transition_type) + self.BufferProject() + return self.ComputePouTransitionName(pou_name, transition_name) + return None + + # Remove a Transition from a Project Pou + def ProjectRemovePouTransition(self, pou_name, transition_name): + # Search if the pou removed is currently opened + if self.Project is not None: + pou = self.Project.getpou(pou_name) + if pou is not None: + pou.removetransition(transition_name) + self.BufferProject() + + # Add an Action to a Project Pou + def ProjectAddPouAction(self, pou_name, action_name, action_type): + if self.Project is not None: + pou = self.Project.getpou(pou_name) + if pou is not None: + pou.addaction(action_name, action_type) + self.BufferProject() + return self.ComputePouActionName(pou_name, action_name) + return None + + # Remove an Action from a Project Pou + def ProjectRemovePouAction(self, pou_name, action_name): + # Search if the pou removed is currently opened + if self.Project is not None: + pou = self.Project.getpou(pou_name) + if pou is not None: + pou.removeaction(action_name) + self.BufferProject() + + # Change the name of a pou + def ChangeDataTypeName(self, old_name, new_name): + if self.Project is not None: + # Found the pou corresponding to old name and change its name to new name + datatype = self.Project.getdataType(old_name) + if datatype is not None: + datatype.setname(new_name) + self.Project.updateElementName(old_name, new_name) + self.Project.RefreshElementUsingTree() + self.Project.RefreshDataTypeHierarchy() + self.BufferProject() + + # Change the name of a pou + def ChangePouName(self, old_name, new_name): + if self.Project is not None: + # Found the pou corresponding to old name and change its name to new name + pou = self.Project.getpou(old_name) + if pou is not None: + pou.setname(new_name) + self.Project.updateElementName(old_name, new_name) + self.Project.RefreshElementUsingTree() + self.Project.RefreshCustomBlockTypes() + self.BufferProject() + + # Change the name of a pou transition + def ChangePouTransitionName(self, pou_name, old_name, new_name): + if self.Project is not None: + # Found the pou transition corresponding to old name and change its name to new name + pou = self.Project.getpou(pou_name) + if pou is not None: + transition = pou.gettransition(old_name) + if transition is not None: + transition.setname(new_name) + pou.updateElementName(old_name, new_name) + self.BufferProject() + + # Change the name of a pou action + def ChangePouActionName(self, pou_name, old_name, new_name): + if self.Project is not None: + # Found the pou action corresponding to old name and change its name to new name + pou = self.Project.getpou(pou_name) + if pou is not None: + action = pou.getaction(old_name) + if action is not None: + action.setname(new_name) + pou.updateElementName(old_name, new_name) + self.BufferProject() + + # Change the name of a pou variable + def ChangePouVariableName(self, pou_name, old_name, new_name): + if self.Project is not None: + # Found the pou action corresponding to old name and change its name to new name + pou = self.Project.getpou(pou_name) + if pou is not None: + for type, varlist in pou.getvars(): + for var in varlist.getvariable(): + if var.getname() == old_name: + var.setname(new_name) + self.Project.RefreshCustomBlockTypes() + self.BufferProject() + + # Change the name of a configuration + def ChangeConfigurationName(self, old_name, new_name): + if self.Project is not None: + # Found the configuration corresponding to old name and change its name to new name + configuration = self.Project.getconfiguration(old_name) + if configuration is not None: + configuration.setname(new_name) + self.BufferProject() + + # Change the name of a configuration resource + def ChangeConfigurationResourceName(self, config_name, old_name, new_name): + if self.Project is not None: + # Found the resource corresponding to old name and change its name to new name + resource = self.Project.getconfigurationResource(config_name, old_name) + if resource is not None: + resource.setname(new_name) + self.BufferProject() + + # Return the description of the pou given by its name + def GetPouDescription(self, name, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its type + pou = project.getpou(name) + if pou is not None: + return pou.getdescription() + return "" + + # Return the description of the pou given by its name + def SetPouDescription(self, name, description, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its type + pou = project.getpou(name) + if pou is not None: + pou.setdescription(description) + project.RefreshCustomBlockTypes() + self.BufferProject() + + # Return the type of the pou given by its name + def GetPouType(self, name, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its type + pou = project.getpou(name) + if pou is not None: + return pou.getpouType() + return None + + # Return pous with SFC language + def GetSFCPous(self, debug = False): + list = [] + project = self.GetProject(debug) + if project is not None: + for pou in project.getpous(): + if pou.getBodyType() == "SFC": + list.append(pou.getname()) + return list + + # Return the body language of the pou given by its name + def GetPouBodyType(self, name, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its body language + pou = project.getpou(name) + if pou is not None: + return pou.getbodyType() + return None + + # Return the actions of a pou + def GetPouTransitions(self, pou_name, debug = False): + transitions = [] + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its transitions if SFC + pou = project.getpou(pou_name) + if pou is not None and pou.getbodyType() == "SFC": + for transition in pou.gettransitionList(): + transitions.append(transition.getname()) + return transitions + + # Return the body language of the transition given by its name + def GetTransitionBodyType(self, pou_name, pou_transition, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name + pou = project.getpou(pou_name) + if pou is not None: + # Found the pou transition correponding to name and return its body language + transition = pou.gettransition(pou_transition) + if transition is not None: + return transition.getbodyType() + return None + + # Return the actions of a pou + def GetPouActions(self, pou_name, debug = False): + actions = [] + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its actions if SFC + pou = project.getpou(pou_name) + if pou.getbodyType() == "SFC": + for action in pou.getactionList(): + actions.append(action.getname()) + return actions + + # Return the body language of the pou given by its name + def GetActionBodyType(self, pou_name, pou_action, debug = False): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return its body language + pou = project.getpou(pou_name) + if pou is not None: + action = pou.getaction(pou_action) + if action is not None: + return action.getbodyType() + return None + + # Extract varlists from a list of vars + def ExtractVarLists(self, vars): + varlist_list = [] + current_varlist = None + current_type = None + for var in vars: + next_type = (var["Class"], + var["Option"], + var["Location"] in ["", None] or + # When declaring globals, located + # and not located variables are + # in the same declaration block + var["Class"] == "Global") + if current_type != next_type: + current_type = next_type + infos = VAR_CLASS_INFOS.get(var["Class"], None) + if infos is not None: + current_varlist = infos[0]() + else: + current_varlist = plcopen.varList() + varlist_list.append((var["Class"], current_varlist)) + if var["Option"] == "Constant": + current_varlist.setconstant(True) + elif var["Option"] == "Retain": + current_varlist.setretain(True) + elif var["Option"] == "Non-Retain": + current_varlist.setnonretain(True) + # Create variable and change its properties + tempvar = plcopen.varListPlain_variable() + tempvar.setname(var["Name"]) + + var_type = plcopen.dataType() + if isinstance(var["Type"], TupleType): + if var["Type"][0] == "array": + array_type, base_type_name, dimensions = var["Type"] + array = plcopen.derivedTypes_array() + for i, dimension in enumerate(dimensions): + dimension_range = plcopen.rangeSigned() + dimension_range.setlower(dimension[0]) + dimension_range.setupper(dimension[1]) + if i == 0: + array.setdimension([dimension_range]) + else: + array.appenddimension(dimension_range) + if base_type_name in self.GetBaseTypes(): + if base_type_name == "STRING": + array.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif base_type_name == "WSTRING": + array.baseType.setcontent({"name" : "wstring", "value" : plcopen.wstring()}) + else: + array.baseType.setcontent({"name" : base_type_name, "value" : None}) + else: + derived_datatype = plcopen.derivedTypes_derived() + derived_datatype.setname(base_type_name) + array.baseType.setcontent({"name" : "derived", "value" : derived_datatype}) + var_type.setcontent({"name" : "array", "value" : array}) + elif var["Type"] in self.GetBaseTypes(): + if var["Type"] == "STRING": + var_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif var["Type"] == "WSTRING": + var_type.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()}) + else: + var_type.setcontent({"name" : var["Type"], "value" : None}) + else: + derived_type = plcopen.derivedTypes_derived() + derived_type.setname(var["Type"]) + var_type.setcontent({"name" : "derived", "value" : derived_type}) + tempvar.settype(var_type) + + if var["Initial Value"] != "": + value = plcopen.value() + value.setvalue(var["Initial Value"]) + tempvar.setinitialValue(value) + if var["Location"] != "": + tempvar.setaddress(var["Location"]) + else: + tempvar.setaddress(None) + if var['Documentation'] != "": + ft = plcopen.formattedText() + ft.settext(var['Documentation']) + tempvar.setdocumentation(ft) + + # Add variable to varList + current_varlist.appendvariable(tempvar) + return varlist_list + + def GetVariableDictionary(self, varlist, var): + ''' + convert a PLC variable to the dictionary representation + returned by Get*Vars) + ''' + + tempvar = {"Name": var.getname()} + + vartype_content = var.gettype().getcontent() + if vartype_content["name"] == "derived": + tempvar["Type"] = vartype_content["value"].getname() + elif vartype_content["name"] == "array": + dimensions = [] + for dimension in vartype_content["value"].getdimension(): + dimensions.append((dimension.getlower(), dimension.getupper())) + base_type = vartype_content["value"].baseType.getcontent() + if base_type["value"] is None: + base_type_name = base_type["name"] + else: + base_type_name = base_type["value"].getname() + tempvar["Type"] = ("array", base_type_name, dimensions) + elif vartype_content["name"] in ["string", "wstring"]: + tempvar["Type"] = vartype_content["name"].upper() + else: + tempvar["Type"] = vartype_content["name"] + + tempvar["Edit"] = True + + initial = var.getinitialValue() + if initial: + tempvar["Initial Value"] = initial.getvalue() + else: + tempvar["Initial Value"] = "" + + address = var.getaddress() + if address: + tempvar["Location"] = address + else: + tempvar["Location"] = "" + + if varlist.getconstant(): + tempvar["Option"] = "Constant" + elif varlist.getretain(): + tempvar["Option"] = "Retain" + elif varlist.getnonretain(): + tempvar["Option"] = "Non-Retain" + else: + tempvar["Option"] = "" + + doc = var.getdocumentation() + if doc: + tempvar["Documentation"] = doc.gettext() + else: + tempvar["Documentation"] = "" + + return tempvar + + # Replace the configuration globalvars by those given + def SetConfigurationGlobalVars(self, name, vars): + if self.Project is not None: + # Found the configuration corresponding to name + configuration = self.Project.getconfiguration(name) + if configuration is not None: + # Set configuration global vars + configuration.setglobalVars([]) + for vartype, varlist in self.ExtractVarLists(vars): + configuration.globalVars.append(varlist) + + # Return the configuration globalvars + def GetConfigurationGlobalVars(self, name, debug = False): + vars = [] + project = self.GetProject(debug) + if project is not None: + # Found the configuration corresponding to name + configuration = project.getconfiguration(name) + if configuration is not None: + # Extract variables from every varLists + for varlist in configuration.getglobalVars(): + for var in varlist.getvariable(): + tempvar = self.GetVariableDictionary(varlist, var) + tempvar["Class"] = "Global" + vars.append(tempvar) + return vars + + # Replace the resource globalvars by those given + def SetConfigurationResourceGlobalVars(self, config_name, name, vars): + if self.Project is not None: + # Found the resource corresponding to name + resource = self.Project.getconfigurationResource(config_name, name) + # Set resource global vars + if resource is not None: + resource.setglobalVars([]) + for vartype, varlist in self.ExtractVarLists(vars): + resource.globalVars.append(varlist) + + # Return the resource globalvars + def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False): + vars = [] + project = self.GetProject(debug) + if project is not None: + # Found the resource corresponding to name + resource = project.getconfigurationResource(config_name, name) + if resource: + # Extract variables from every varLists + for varlist in resource.getglobalVars(): + for var in varlist.getvariable(): + tempvar = self.GetVariableDictionary(varlist, var) + tempvar["Class"] = "Global" + vars.append(tempvar) + return vars + + # Recursively generate element name tree for a structured variable + def GenerateVarTree(self, typename, debug = False): + project = self.GetProject(debug) + if project is not None: + blocktype = self.GetBlockType(typename, debug = debug) + if blocktype is not None: + tree = [] + en = False + eno = False + for var_name, var_type, var_modifier in blocktype["inputs"] + blocktype["outputs"]: + en |= var_name.upper() == "EN" + eno |= var_name.upper() == "ENO" + tree.append((var_name, var_type, self.GenerateVarTree(var_type, debug))) + if not eno: + tree.insert(0, ("ENO", "BOOL", ([], []))) + if not en: + tree.insert(0, ("EN", "BOOL", ([], []))) + return tree, [] + datatype = project.getdataType(typename) + if datatype is None: + datatype = self.GetConfNodeDataType(typename) + if datatype is not None: + tree = [] + basetype_content = datatype.baseType.getcontent() + if basetype_content["name"] == "derived": + return self.GenerateVarTree(basetype_content["value"].getname()) + elif basetype_content["name"] == "array": + dimensions = [] + base_type = basetype_content["value"].baseType.getcontent() + if base_type["name"] == "derived": + tree = self.GenerateVarTree(base_type["value"].getname()) + if len(tree[1]) == 0: + tree = tree[0] + for dimension in basetype_content["value"].getdimension(): + dimensions.append((dimension.getlower(), dimension.getupper())) + return tree, dimensions + elif basetype_content["name"] == "struct": + for element in basetype_content["value"].getvariable(): + element_type = element.type.getcontent() + if element_type["name"] == "derived": + tree.append((element.getname(), element_type["value"].getname(), self.GenerateVarTree(element_type["value"].getname()))) + else: + tree.append((element.getname(), element_type["name"], ([], []))) + return tree, [] + return [], [] + + # Return the interface for the given pou + def GetPouInterfaceVars(self, pou, debug = False): + vars = [] + # Verify that the pou has an interface + if pou.interface is not None: + # Extract variables from every varLists + for type, varlist in pou.getvars(): + for var in varlist.getvariable(): + tempvar = self.GetVariableDictionary(varlist, var) + + tempvar["Class"] = type + tempvar["Tree"] = ([], []) + + vartype_content = var.gettype().getcontent() + if vartype_content["name"] == "derived": + tempvar["Edit"] = not pou.hasblock(tempvar["Name"]) + tempvar["Tree"] = self.GenerateVarTree(tempvar["Type"], debug) + + vars.append(tempvar) + return vars + + # Replace the Pou interface by the one given + def SetPouInterfaceVars(self, name, vars): + if self.Project is not None: + # Found the pou corresponding to name and add interface if there isn't one yet + pou = self.Project.getpou(name) + if pou is not None: + if pou.interface is None: + pou.interface = plcopen.pou_interface() + # Set Pou interface + pou.setvars(self.ExtractVarLists(vars)) + 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): + if self.Project is not None: + pou = self.Project.getpou(name) + if pou is not None: + if pou.interface is None: + pou.interface = plcopen.pou_interface() + # If there isn't any return type yet, add it + return_type = pou.interface.getreturnType() + if not return_type: + return_type = plcopen.dataType() + pou.interface.setreturnType(return_type) + # Change return type + if type in self.GetBaseTypes(): + if type == "STRING": + return_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif type == "WSTRING": + return_type.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()}) + else: + return_type.setcontent({"name" : type, "value" : None}) + else: + derived_type = plcopen.derivedTypes_derived() + derived_type.setname(type) + return_type.setcontent({"name" : "derived", "value" : derived_type}) + self.Project.RefreshElementUsingTree() + self.Project.RefreshCustomBlockTypes() + + def UpdateProjectUsedPous(self, old_name, new_name): + if self.Project: + self.Project.updateElementName(old_name, new_name) + + def UpdateEditedElementUsedVariable(self, tagname, old_name, new_name): + pou = self.GetEditedElement(tagname) + if pou: + pou.updateElementName(old_name, new_name) + + # Return the return type of the pou given by its name + def GetPouInterfaceReturnTypeByName(self, name): + project = self.GetProject(debug) + if project is not None: + # Found the pou correponding to name and return the return type + pou = project.getpou(name) + if pou is not None: + return self.GetPouInterfaceReturnType(pou) + return False + + # Return the return type of the given pou + def GetPouInterfaceReturnType(self, pou): + # Verify that the pou has an interface + if pou.interface is not None: + # Return the return type if there is one + return_type = pou.interface.getreturnType() + if return_type: + returntype_content = return_type.getcontent() + if returntype_content["name"] == "derived": + return returntype_content["value"].getname() + elif returntype_content["name"] in ["string", "wstring"]: + return returntype_content["name"].upper() + else: + return returntype_content["name"] + return None + + # Function that add a new confnode to the confnode list + def AddConfNodeTypesList(self, typeslist): + self.ConfNodeTypes.extend(typeslist) + + # Function that clear the confnode list + def ClearConfNodeTypes(self): + for i in xrange(len(self.ConfNodeTypes)): + self.ConfNodeTypes.pop(0) + + def GetConfNodeBlockTypes(self): + return [{"name": _("%s POUs") % confnodetypes["name"], + "list": confnodetypes["types"].GetCustomBlockTypes()} + for confnodetypes in self.ConfNodeTypes] + + def GetConfNodeDataTypes(self, exclude = ""): + return [{"name": _("%s Data Types") % confnodetypes["name"], + "list": [datatype["name"] for datatype in confnodetypes["types"].GetCustomDataTypes(exclude)]} + for confnodetypes in self.ConfNodeTypes] + + def GetConfNodeDataType(self, type): + for confnodetype in self.ConfNodeTypes: + datatype = confnodetype["types"].getdataType(type) + if datatype is not None: + return datatype + return None + + def GetVariableLocationTree(self): + return [] + + # Function that returns the block definition associated to the block type given + def GetBlockType(self, type, inputs = None, debug = False): + result_blocktype = None + for category in BlockTypes + self.GetConfNodeBlockTypes(): + for blocktype in category["list"]: + if blocktype["name"] == type: + if inputs is not None and inputs != "undefined": + block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]]) + if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True): + return blocktype + else: + if result_blocktype is not None: + if inputs == "undefined": + return None + else: + result_blocktype["inputs"] = [(i[0], "ANY", i[2]) for i in result_blocktype["inputs"]] + result_blocktype["outputs"] = [(o[0], "ANY", o[2]) for o in result_blocktype["outputs"]] + return result_blocktype + result_blocktype = blocktype + if result_blocktype is not None: + return result_blocktype + project = self.GetProject(debug) + if project is not None: + return project.GetCustomBlockType(type, inputs) + return None + + # Return Block types checking for recursion + def GetBlockTypes(self, tagname = "", debug = False): + type = None + words = tagname.split("::") + if self.Project: + name = "" + if words[0] in ["P","T","A"]: + name = words[1] + type = self.GetPouType(name, debug) + if type == "function" or words[0] == "T": + blocktypes = [] + for category in BlockTypes + self.GetConfNodeBlockTypes(): + cat = {"name" : category["name"], "list" : []} + for block in category["list"]: + if block["type"] == "function": + cat["list"].append(block) + if len(cat["list"]) > 0: + blocktypes.append(cat) + else: + blocktypes = [category for category in BlockTypes + self.GetConfNodeBlockTypes()] + project = self.GetProject(debug) + if project is not None: + blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")}) + return blocktypes + + # Return Function Block types checking for recursion + def GetFunctionBlockTypes(self, tagname = "", debug = False): + blocktypes = [] + for category in BlockTypes + self.GetConfNodeBlockTypes(): + for block in category["list"]: + if block["type"] == "functionBlock": + blocktypes.append(block["name"]) + project = self.GetProject(debug) + if project is not None: + name = "" + words = tagname.split("::") + if words[0] in ["P","T","A"]: + name = words[1] + blocktypes.extend(project.GetCustomFunctionBlockTypes(name)) + return blocktypes + + # Return Block types checking for recursion + def GetBlockResource(self, debug = False): + blocktypes = [] + for category in BlockTypes[:-1]: + for blocktype in category["list"]: + if blocktype["type"] == "program": + blocktypes.append(blocktype["name"]) + project = self.GetProject(debug) + if project is not None: + blocktypes.extend(project.GetCustomBlockResource()) + return blocktypes + + # Return Data Types checking for recursion + def GetDataTypes(self, tagname = "", basetypes = True, only_locatables = False, debug = False): + if basetypes: + datatypes = self.GetBaseTypes() + else: + datatypes = [] + project = self.GetProject(debug) + if project is not None: + name = "" + words = tagname.split("::") + if words[0] in ["D"]: + name = words[1] + datatypes.extend([datatype["name"] for datatype in project.GetCustomDataTypes(name, only_locatables)]) + return datatypes + + # Return Base Type of given possible derived type + def GetBaseType(self, type, debug = False): + project = self.GetProject(debug) + if project is not None: + result = project.GetBaseType(type) + if result is not None: + return result + for confnodetype in self.ConfNodeTypes: + result = confnodetype["types"].GetBaseType(type) + if result is not None: + return result + return None + + def GetBaseTypes(self): + ''' + return the list of datatypes defined in IEC 61131-3. + TypeHierarchy_list has a rough order to it (e.g. SINT, INT, DINT, ...), + which makes it easy for a user to find a type in a menu. + ''' + return [x for x,y in TypeHierarchy_list if not x.startswith("ANY")] + + def IsOfType(self, type, reference, debug = False): + if reference is None: + return True + elif type == reference: + return True + elif type in TypeHierarchy: + return self.IsOfType(TypeHierarchy[type], reference) + else: + project = self.GetProject(debug) + if project is not None and project.IsOfType(type, reference): + return True + for confnodetype in self.ConfNodeTypes: + if confnodetype["types"].IsOfType(type, reference): + return True + return False + + def IsEndType(self, type): + if type is not None: + return not type.startswith("ANY") + return True + + def IsLocatableType(self, type, debug = False): + if isinstance(type, TupleType): + return False + project = self.GetProject(debug) + if project is not None: + datatype = project.getdataType(type) + if datatype is None: + datatype = self.GetConfNodeDataType(type) + if datatype is not None: + return project.IsLocatableType(datatype) + return True + + def IsEnumeratedType(self, type, debug = False): + project = self.GetProject(debug) + if project is not None: + datatype = project.getdataType(type) + if datatype is None: + datatype = self.GetConfNodeDataType(type) + if datatype is not None: + basetype_content = datatype.baseType.getcontent() + return basetype_content["name"] == "enum" + return False + + def GetDataTypeRange(self, type, debug = False): + if type in DataTypeRange: + return DataTypeRange[type] + else: + project = self.GetProject(debug) + if project is not None: + result = project.GetDataTypeRange(type) + if result is not None: + return result + for confnodetype in self.ConfNodeTypes: + result = confnodetype["types"].GetDataTypeRange(type) + if result is not None: + return result + return None + + # Return Subrange types + def GetSubrangeBaseTypes(self, exclude, debug = False): + subrange_basetypes = [] + project = self.GetProject(debug) + if project is not None: + subrange_basetypes.extend(project.GetSubrangeBaseTypes(exclude)) + for confnodetype in self.ConfNodeTypes: + subrange_basetypes.extend(confnodetype["types"].GetSubrangeBaseTypes(exclude)) + return DataTypeRange.keys() + subrange_basetypes + + # Return Enumerated Values + def GetEnumeratedDataValues(self, type = None, debug = False): + values = [] + project = self.GetProject(debug) + if project is not None: + values.extend(project.GetEnumeratedDataTypeValues(type)) + if type is None and len(values) > 0: + return values + for confnodetype in self.ConfNodeTypes: + values.extend(confnodetype["types"].GetEnumeratedDataTypeValues(type)) + if type is None and len(values) > 0: + return values + return values + +#------------------------------------------------------------------------------- +# Project Element tag name computation functions +#------------------------------------------------------------------------------- + + # Compute a data type name + def ComputeDataTypeName(self, datatype): + return "D::%s" % datatype + + # Compute a pou name + def ComputePouName(self, pou): + return "P::%s" % pou + + # Compute a pou transition name + def ComputePouTransitionName(self, pou, transition): + return "T::%s::%s" % (pou, transition) + + # Compute a pou action name + def ComputePouActionName(self, pou, action): + return "A::%s::%s" % (pou, action) + + # Compute a pou name + def ComputeConfigurationName(self, config): + return "C::%s" % config + + # Compute a pou name + 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 +#------------------------------------------------------------------------------- + + # Return the data type informations + def GetDataTypeInfos(self, tagname, debug = False): + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "D": + infos = {} + datatype = project.getdataType(words[1]) + basetype_content = datatype.baseType.getcontent() + if basetype_content["value"] is None or basetype_content["name"] in ["string", "wstring"]: + infos["type"] = "Directly" + infos["base_type"] = basetype_content["name"].upper() + elif basetype_content["name"] == "derived": + infos["type"] = "Directly" + infos["base_type"] = basetype_content["value"].getname() + elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]: + infos["type"] = "Subrange" + infos["min"] = basetype_content["value"].range.getlower() + infos["max"] = basetype_content["value"].range.getupper() + base_type = basetype_content["value"].baseType.getcontent() + if base_type["value"] is None: + infos["base_type"] = base_type["name"] + else: + infos["base_type"] = base_type["value"].getname() + elif basetype_content["name"] == "enum": + infos["type"] = "Enumerated" + infos["values"] = [] + for value in basetype_content["value"].values.getvalue(): + infos["values"].append(value.getname()) + elif basetype_content["name"] == "array": + infos["type"] = "Array" + infos["dimensions"] = [] + for dimension in basetype_content["value"].getdimension(): + infos["dimensions"].append((dimension.getlower(), dimension.getupper())) + base_type = basetype_content["value"].baseType.getcontent() + if base_type["value"] is None or base_type["name"] in ["string", "wstring"]: + infos["base_type"] = base_type["name"].upper() + else: + infos["base_type"] = base_type["value"].getname() + elif basetype_content["name"] == "struct": + infos["type"] = "Structure" + infos["elements"] = [] + for element in basetype_content["value"].getvariable(): + element_infos = {} + element_infos["Name"] = element.getname() + element_type = element.type.getcontent() + if element_type["value"] is None or element_type["name"] in ["string", "wstring"]: + element_infos["Type"] = element_type["name"].upper() + else: + element_infos["Type"] = element_type["value"].getname() + if element.initialValue is not None: + element_infos["Initial Value"] = str(element.initialValue.getvalue()) + else: + element_infos["Initial Value"] = "" + infos["elements"].append(element_infos) + if datatype.initialValue is not None: + infos["initial"] = str(datatype.initialValue.getvalue()) + else: + infos["initial"] = "" + return infos + return None + + # Change the data type informations + def SetDataTypeInfos(self, tagname, infos): + words = tagname.split("::") + if self.Project is not None and words[0] == "D": + datatype = self.Project.getdataType(words[1]) + if infos["type"] == "Directly": + if infos["base_type"] in self.GetBaseTypes(): + if infos["base_type"] == "STRING": + datatype.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif infos["base_type"] == "WSTRING": + datatype.baseType.setcontent({"name" : "wstring", "value" : plcopen.elementaryTypes_wstring()}) + else: + datatype.baseType.setcontent({"name" : infos["base_type"], "value" : None}) + else: + derived_datatype = plcopen.derivedTypes_derived() + derived_datatype.setname(infos["base_type"]) + datatype.baseType.setcontent({"name" : "derived", "value" : derived_datatype}) + elif infos["type"] == "Subrange": + if infos["base_type"] in GetSubTypes("ANY_UINT"): + subrange = plcopen.derivedTypes_subrangeUnsigned() + datatype.baseType.setcontent({"name" : "subrangeUnsigned", "value" : subrange}) + else: + subrange = plcopen.derivedTypes_subrangeSigned() + datatype.baseType.setcontent({"name" : "subrangeSigned", "value" : subrange}) + subrange.range.setlower(infos["min"]) + subrange.range.setupper(infos["max"]) + if infos["base_type"] in self.GetBaseTypes(): + subrange.baseType.setcontent({"name" : infos["base_type"], "value" : None}) + else: + derived_datatype = plcopen.derivedTypes_derived() + derived_datatype.setname(infos["base_type"]) + subrange.baseType.setcontent({"name" : "derived", "value" : derived_datatype}) + elif infos["type"] == "Enumerated": + enumerated = plcopen.derivedTypes_enum() + for i, enum_value in enumerate(infos["values"]): + value = plcopen.values_value() + value.setname(enum_value) + if i == 0: + enumerated.values.setvalue([value]) + else: + enumerated.values.appendvalue(value) + datatype.baseType.setcontent({"name" : "enum", "value" : enumerated}) + elif infos["type"] == "Array": + array = plcopen.derivedTypes_array() + for i, dimension in enumerate(infos["dimensions"]): + dimension_range = plcopen.rangeSigned() + dimension_range.setlower(dimension[0]) + dimension_range.setupper(dimension[1]) + if i == 0: + array.setdimension([dimension_range]) + else: + array.appenddimension(dimension_range) + if infos["base_type"] in self.GetBaseTypes(): + if infos["base_type"] == "STRING": + array.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif infos["base_type"] == "WSTRING": + array.baseType.setcontent({"name" : "wstring", "value" : plcopen.wstring()}) + else: + array.baseType.setcontent({"name" : infos["base_type"], "value" : None}) + else: + derived_datatype = plcopen.derivedTypes_derived() + derived_datatype.setname(infos["base_type"]) + array.baseType.setcontent({"name" : "derived", "value" : derived_datatype}) + datatype.baseType.setcontent({"name" : "array", "value" : array}) + elif infos["type"] == "Structure": + struct = plcopen.varListPlain() + for i, element_infos in enumerate(infos["elements"]): + element = plcopen.varListPlain_variable() + element.setname(element_infos["Name"]) + if element_infos["Type"] in self.GetBaseTypes(): + if element_infos["Type"] == "STRING": + element.type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()}) + elif element_infos["Type"] == "WSTRING": + element.type.setcontent({"name" : "wstring", "value" : plcopen.wstring()}) + else: + element.type.setcontent({"name" : element_infos["Type"], "value" : None}) + else: + derived_datatype = plcopen.derivedTypes_derived() + derived_datatype.setname(element_infos["Type"]) + element.type.setcontent({"name" : "derived", "value" : derived_datatype}) + if element_infos["Initial Value"] != "": + value = plcopen.value() + value.setvalue(element_infos["Initial Value"]) + element.setinitialValue(value) + if i == 0: + struct.setvariable([element]) + else: + struct.appendvariable(element) + datatype.baseType.setcontent({"name" : "struct", "value" : struct}) + if infos["initial"] != "": + if datatype.initialValue is None: + datatype.initialValue = plcopen.value() + datatype.initialValue.setvalue(infos["initial"]) + else: + datatype.initialValue = None + self.Project.RefreshDataTypeHierarchy() + self.Project.RefreshElementUsingTree() + self.BufferProject() + +#------------------------------------------------------------------------------- +# Project opened Pous management functions +#------------------------------------------------------------------------------- + + # Return edited element + def GetEditedElement(self, tagname, debug = False): + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "D": + return project.getdataType(words[1]) + elif words[0] == "P": + return project.getpou(words[1]) + elif words[0] in ['T', 'A']: + pou = project.getpou(words[1]) + if pou is not None: + if words[0] == 'T': + return pou.gettransition(words[2]) + elif words[0] == 'A': + return pou.getaction(words[2]) + elif words[0] == 'C': + return project.getconfiguration(words[1]) + elif words[0] == 'R': + return project.getconfigurationResource(words[1], words[2]) + return None + + # Return edited element name + def GetEditedElementName(self, tagname): + words = tagname.split("::") + if words[0] in ["P","C","D"]: + return words[1] + else: + return words[2] + return None + + # Return edited element name and type + def GetEditedElementType(self, tagname, debug = False): + words = tagname.split("::") + if words[0] in ["P","T","A"]: + return words[1], self.GetPouType(words[1], debug) + return None, None + + # Return language in which edited element is written + def GetEditedElementBodyType(self, tagname, debug = False): + words = tagname.split("::") + if words[0] == "P": + return self.GetPouBodyType(words[1], debug) + elif words[0] == 'T': + return self.GetTransitionBodyType(words[1], words[2], debug) + elif words[0] == 'A': + return self.GetActionBodyType(words[1], words[2], debug) + return None + + # Return the edited element variables + def GetEditedElementInterfaceVars(self, tagname, debug = False): + words = tagname.split("::") + if words[0] in ["P","T","A"]: + project = self.GetProject(debug) + if project is not None: + pou = project.getpou(words[1]) + if pou is not None: + return self.GetPouInterfaceVars(pou, debug) + return [] + + # Return the edited element return type + def GetEditedElementInterfaceReturnType(self, tagname, debug = False): + words = tagname.split("::") + if words[0] == "P": + project = self.GetProject(debug) + if project is not None: + pou = self.Project.getpou(words[1]) + if pou is not None: + return self.GetPouInterfaceReturnType(pou) + elif words[0] == 'T': + return "BOOL" + return None + + # Change the edited element text + def SetEditedElementText(self, tagname, text): + if self.Project is not None: + element = self.GetEditedElement(tagname) + if element is not None: + element.settext(text) + self.Project.RefreshElementUsingTree() + + # Return the edited element text + def GetEditedElementText(self, tagname, debug = False): + element = self.GetEditedElement(tagname, debug) + if element is not None: + return element.gettext() + return "" + + # Return the edited element transitions + def GetEditedElementTransitions(self, tagname, debug = False): + pou = self.GetEditedElement(tagname, debug) + if pou is not None and pou.getbodyType() == "SFC": + transitions = [] + for transition in pou.gettransitionList(): + transitions.append(transition.getname()) + return transitions + return [] + + # Return edited element transitions + def GetEditedElementActions(self, tagname, debug = False): + pou = self.GetEditedElement(tagname, debug) + if pou is not None and pou.getbodyType() == "SFC": + actions = [] + for action in pou.getactionList(): + actions.append(action.getname()) + return actions + return [] + + # Return the names of the pou elements + def GetEditedElementVariables(self, tagname, debug = False): + words = tagname.split("::") + if words[0] in ["P","T","A"]: + return self.GetProjectPouVariables(words[1], debug) + return [] + + def GetEditedElementCopy(self, tagname, debug = False): + element = self.GetEditedElement(tagname, debug) + if element is not None: + name = element.__class__.__name__ + return element.generateXMLText(name.split("_")[-1], 0) + return "" + + def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False): + element = self.GetEditedElement(tagname, debug) + text = "" + if element is not None: + wires = dict([(wire, True) for wire in wires if wire[0] in blocks_id and wire[1] in blocks_id]) + for id in blocks_id: + instance = element.getinstance(id) + if instance is not None: + instance_copy = self.Copy(instance) + instance_copy.filterConnections(wires) + name = instance_copy.__class__.__name__ + text += instance_copy.generateXMLText(name.split("_")[-1], 0) + return text + + def GenerateNewName(self, tagname, name, format, exclude={}, debug=False): + names = exclude.copy() + if tagname is not None: + names.update(dict([(varname.upper(), True) for varname in self.GetEditedElementVariables(tagname, debug)])) + element = self.GetEditedElement(tagname, debug) + if element is not None: + for instance in element.getinstances(): + if isinstance(instance, (plcopen.sfcObjects_step, plcopen.commonObjects_connector, plcopen.commonObjects_continuation)): + names[instance.getname().upper()] = True + else: + project = self.GetProject(debug) + if project is not None: + for datatype in project.getdataTypes(): + names[datatype.getname().upper()] = True + for pou in project.getpous(): + names[pou.getname().upper()] = True + for var in self.GetPouInterfaceVars(pou, debug): + names[var["Name"].upper()] = True + for transition in pou.gettransitionList(): + names[transition.getname().upper()] = True + for action in pou.getactionList(): + names[action.getname().upper()] = True + for config in project.getconfigurations(): + names[config.getname().upper()] = True + for resource in config.getresource(): + names[resource.getname().upper()] = True + + i = 0 + while name is None or names.get(name.upper(), False): + name = (format%i) + i += 1 + return name + + CheckPasteCompatibility = {"SFC": lambda name: True, + "LD": lambda name: not name.startswith("sfcObjects"), + "FBD": lambda name: name.startswith("fbdObjects") or name.startswith("commonObjects")} + + def PasteEditedElementInstances(self, tagname, text, new_pos, middle=False, debug=False): + element = self.GetEditedElement(tagname, debug) + element_name, element_type = self.GetEditedElementType(tagname, debug) + if element is not None: + bodytype = element.getbodyType() + + # Get edited element type scaling + scaling = None + project = self.GetProject(debug) + if project is not None: + properties = project.getcontentHeader() + scaling = properties["scaling"][bodytype] + + # Get ids already by all the instances in edited element + used_id = dict([(instance.getlocalId(), True) for instance in element.getinstances()]) + new_id = {} + + text = "%s"%text + + try: + tree = minidom.parseString(text) + except: + return _("Invalid plcopen element(s)!!!") + instances = [] + exclude = {} + for root in tree.childNodes: + if root.nodeType == tree.ELEMENT_NODE and root.nodeName == "paste": + for child in root.childNodes: + if child.nodeType == tree.ELEMENT_NODE: + if not child.nodeName in plcopen.ElementNameToClass: + return _("\"%s\" element can't be pasted here!!!")%child.nodeName + + classname = plcopen.ElementNameToClass[child.nodeName] + if not self.CheckPasteCompatibility[bodytype](classname): + return _("\"%s\" element can't be pasted here!!!")%child.nodeName + + classobj = getattr(plcopen, classname, None) + if classobj is not None: + instance = classobj() + instance.loadXMLTree(child) + if child.nodeName == "block": + blockname = instance.getinstanceName() + if blockname is not None: + blocktype = instance.gettypeName() + if element_type == "function": + return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype + blockname = self.GenerateNewName(tagname, blockname, "%s%%d"%blocktype, debug=debug) + exclude[blockname] = True + instance.setinstanceName(blockname) + self.AddEditedElementPouVar(tagname, blocktype, blockname) + elif child.nodeName == "step": + stepname = self.GenerateNewName(tagname, instance.getname(), "Step%d", exclude, debug) + exclude[stepname] = True + instance.setname(stepname) + localid = instance.getlocalId() + if not used_id.has_key(localid): + new_id[localid] = True + instances.append((child.nodeName, instance)) + + if len(instances) == 0: + return _("Invalid plcopen element(s)!!!") + + idx = 1 + translate_id = {} + bbox = plcopen.rect() + for name, instance in instances: + localId = instance.getlocalId() + bbox.union(instance.getBoundingBox()) + if used_id.has_key(localId): + while used_id.has_key(idx) or new_id.has_key(idx): + idx += 1 + new_id[idx] = True + instance.setlocalId(idx) + translate_id[localId] = idx + + x, y, width, height = bbox.bounding_box() + if middle: + new_pos[0] -= width / 2 + new_pos[1] -= height / 2 + else: + new_pos = map(lambda x: x + 30, new_pos) + if scaling[0] != 0 and scaling[1] != 0: + min_pos = map(lambda x: 30 / x, scaling) + minx = round(min_pos[0]) + if int(min_pos[0]) == round(min_pos[0]): + minx += 1 + miny = round(min_pos[1]) + if int(min_pos[1]) == round(min_pos[1]): + miny += 1 + minx *= scaling[0] + miny *= scaling[1] + new_pos = (max(minx, round(new_pos[0] / scaling[0]) * scaling[0]), + max(miny, round(new_pos[1] / scaling[1]) * scaling[1])) + else: + new_pos = (max(30, new_pos[0]), max(30, new_pos[1])) + diff = (new_pos[0] - x, new_pos[1] - y) + + connections = {} + for name, instance in instances: + connections.update(instance.updateConnectionsId(translate_id)) + if getattr(instance, "setexecutionOrderId", None) is not None: + instance.setexecutionOrderId(0) + instance.translate(*diff) + element.addinstance(name, instance) + + return new_id, connections + + # Return the current pou editing informations + def GetEditedElementInstanceInfos(self, tagname, id = None, exclude = [], debug = False): + infos = {} + instance = None + element = self.GetEditedElement(tagname, debug) + if element is not None: + # if id is defined + if id is not None: + instance = element.getinstance(id) + else: + instance = element.getrandomInstance(exclude) + if instance is not None: + infos = instance.getinfos() + if infos["type"] in ["input", "output", "inout"]: + var_type = self.GetEditedElementVarValueType(tagname, infos["specific_values"]["name"], debug) + infos["specific_values"]["value_type"] = var_type + return infos + return None + + def ClearEditedElementExecutionOrder(self, tagname): + element = self.GetEditedElement(tagname) + if element is not None: + element.resetexecutionOrder() + + def ResetEditedElementExecutionOrder(self, tagname): + element = self.GetEditedElement(tagname) + if element is not None: + element.compileexecutionOrder() + + # Return the variable type of the given pou + def GetEditedElementVarValueType(self, tagname, varname, debug = False): + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] in ["P","T","A"]: + pou = self.Project.getpou(words[1]) + if pou is not None: + if words[0] == "T" and varname == words[2]: + return "BOOL" + if words[1] == varname: + return self.GetPouInterfaceReturnType(pou) + for type, varlist in pou.getvars(): + for var in varlist.getvariable(): + if var.getname() == varname: + vartype_content = var.gettype().getcontent() + if vartype_content["name"] == "derived": + return vartype_content["value"].getname() + elif vartype_content["name"] in ["string", "wstring"]: + return vartype_content["name"].upper() + else: + return vartype_content["name"] + return None + + def SetConnectionWires(self, connection, connector): + wires = connector.GetWires() + idx = 0 + for wire, handle in wires: + points = wire.GetPoints(handle != 0) + if handle == 0: + result = wire.GetConnectedInfos(-1) + else: + result = wire.GetConnectedInfos(0) + if result != None: + refLocalId, formalParameter = result + connections = connection.getconnections() + if connections is None or len(connection.getconnections()) <= idx: + connection.addconnection() + connection.setconnectionId(idx, refLocalId) + connection.setconnectionPoints(idx, points) + if formalParameter != "": + connection.setconnectionParameter(idx, formalParameter) + else: + connection.setconnectionParameter(idx, None) + idx += 1 + + def AddEditedElementPouVar(self, tagname, type, name, location="", description=""): + if self.Project is not None: + words = tagname.split("::") + if words[0] in ['P', 'T', 'A']: + pou = self.Project.getpou(words[1]) + if pou is not None: + pou.addpouLocalVar(type, name, location, description) + + def AddEditedElementPouExternalVar(self, tagname, type, name): + if self.Project is not None: + words = tagname.split("::") + if words[0] in ['P', 'T', 'A']: + pou = self.Project.getpou(words[1]) + if pou is not None: + pou.addpouExternalVar(type, name) + + def ChangeEditedElementPouVar(self, tagname, old_type, old_name, new_type, new_name): + if self.Project is not None: + words = tagname.split("::") + if words[0] in ['P', 'T', 'A']: + pou = self.Project.getpou(words[1]) + if pou is not None: + pou.changepouVar(old_type, old_name, new_type, new_name) + + def RemoveEditedElementPouVar(self, tagname, type, name): + if self.Project is not None: + words = tagname.split("::") + if words[0] in ['P', 'T', 'A']: + pou = self.Project.getpou(words[1]) + if pou is not None: + pou.removepouVar(type, name) + + def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None): + element = self.GetEditedElement(tagname) + if element is not None: + block = plcopen.fbdObjects_block() + block.setlocalId(id) + block.settypeName(blocktype) + blocktype_infos = self.GetBlockType(blocktype) + if blocktype_infos["type"] != "function" and blockname is not None: + block.setinstanceName(blockname) + self.AddEditedElementPouVar(tagname, blocktype, blockname) + element.addinstance("block", block) + self.Project.RefreshElementUsingTree() + + def SetEditedElementBlockInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + block = element.getinstance(id) + if block is None: + return + old_name = block.getinstanceName() + old_type = block.gettypeName() + new_name = infos.get("name", old_name) + new_type = infos.get("type", old_type) + if new_type != old_type: + old_typeinfos = self.GetBlockType(old_type) + new_typeinfos = self.GetBlockType(new_type) + if old_typeinfos is None or new_typeinfos is None: + self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name) + elif new_typeinfos["type"] != old_typeinfos["type"]: + if new_typeinfos["type"] == "function": + self.RemoveEditedElementPouVar(tagname, old_type, old_name) + else: + self.AddEditedElementPouVar(tagname, new_type, new_name) + elif new_typeinfos["type"] != "function": + self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name) + elif new_name != old_name: + self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name) + for param, value in infos.items(): + if param == "name": + block.setinstanceName(value) + elif param == "type": + block.settypeName(value) + elif param == "executionOrder" and block.getexecutionOrderId() != value: + element.setelementExecutionOrder(block, value) + elif param == "height": + block.setheight(value) + elif param == "width": + block.setwidth(value) + elif param == "x": + block.setx(value) + elif param == "y": + block.sety(value) + elif param == "connectors": + block.inputVariables.setvariable([]) + block.outputVariables.setvariable([]) + for connector in value["inputs"]: + variable = plcopen.inputVariables_variable() + variable.setformalParameter(connector.GetName()) + if connector.IsNegated(): + variable.setnegated(True) + if connector.GetEdge() != "none": + variable.setedge(connector.GetEdge()) + position = connector.GetRelPosition() + variable.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(variable.connectionPointIn, connector) + block.inputVariables.appendvariable(variable) + for connector in value["outputs"]: + variable = plcopen.outputVariables_variable() + variable.setformalParameter(connector.GetName()) + if connector.IsNegated(): + variable.setnegated(True) + if connector.GetEdge() != "none": + variable.setedge(connector.GetEdge()) + position = connector.GetRelPosition() + variable.addconnectionPointOut() + variable.connectionPointOut.setrelPositionXY(position.x, position.y) + block.outputVariables.appendvariable(variable) + self.Project.RefreshElementUsingTree() + + def AddEditedElementVariable(self, tagname, id, type): + element = self.GetEditedElement(tagname) + if element is not None: + if type == INPUT: + name = "inVariable" + variable = plcopen.fbdObjects_inVariable() + elif type == OUTPUT: + name = "outVariable" + variable = plcopen.fbdObjects_outVariable() + elif type == INOUT: + name = "inOutVariable" + variable = plcopen.fbdObjects_inOutVariable() + variable.setlocalId(id) + element.addinstance(name, variable) + + def SetEditedElementVariableInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + variable = element.getinstance(id) + if variable is None: + return + for param, value in infos.items(): + if param == "name": + variable.setexpression(value) + elif param == "executionOrder" and variable.getexecutionOrderId() != value: + element.setelementExecutionOrder(variable, value) + elif param == "height": + variable.setheight(value) + elif param == "width": + variable.setwidth(value) + elif param == "x": + variable.setx(value) + elif param == "y": + variable.sety(value) + elif param == "connectors": + if len(value["outputs"]) > 0: + output = value["outputs"][0] + if len(value["inputs"]) > 0: + variable.setnegatedOut(output.IsNegated()) + variable.setedgeOut(output.GetEdge()) + else: + variable.setnegated(output.IsNegated()) + variable.setedge(output.GetEdge()) + position = output.GetRelPosition() + variable.addconnectionPointOut() + variable.connectionPointOut.setrelPositionXY(position.x, position.y) + if len(value["inputs"]) > 0: + input = value["inputs"][0] + if len(value["outputs"]) > 0: + variable.setnegatedIn(input.IsNegated()) + variable.setedgeIn(input.GetEdge()) + else: + variable.setnegated(input.IsNegated()) + variable.setedge(input.GetEdge()) + position = input.GetRelPosition() + variable.addconnectionPointIn() + variable.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(variable.connectionPointIn, input) + + def AddEditedElementConnection(self, tagname, id, type): + element = self.GetEditedElement(tagname) + if element is not None: + if type == CONNECTOR: + name = "connector" + connection = plcopen.commonObjects_connector() + elif type == CONTINUATION: + name = "continuation" + connection = plcopen.commonObjects_continuation() + connection.setlocalId(id) + element.addinstance(name, connection) + + def SetEditedElementConnectionInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + connection = element.getinstance(id) + if connection is None: + return + for param, value in infos.items(): + if param == "name": + connection.setname(value) + elif param == "height": + connection.setheight(value) + elif param == "width": + connection.setwidth(value) + elif param == "x": + connection.setx(value) + elif param == "y": + connection.sety(value) + elif param == "connector": + position = value.GetRelPosition() + if isinstance(connection, plcopen.commonObjects_continuation): + connection.addconnectionPointOut() + connection.connectionPointOut.setrelPositionXY(position.x, position.y) + elif isinstance(connection, plcopen.commonObjects_connector): + connection.addconnectionPointIn() + connection.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(connection.connectionPointIn, value) + + def AddEditedElementComment(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + comment = plcopen.commonObjects_comment() + comment.setlocalId(id) + element.addinstance("comment", comment) + + def SetEditedElementCommentInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + comment = element.getinstance(id) + for param, value in infos.items(): + if param == "content": + comment.setcontentText(value) + elif param == "height": + comment.setheight(value) + elif param == "width": + comment.setwidth(value) + elif param == "x": + comment.setx(value) + elif param == "y": + comment.sety(value) + + def AddEditedElementPowerRail(self, tagname, id, type): + element = self.GetEditedElement(tagname) + if element is not None: + if type == LEFTRAIL: + name = "leftPowerRail" + powerrail = plcopen.ldObjects_leftPowerRail() + elif type == RIGHTRAIL: + name = "rightPowerRail" + powerrail = plcopen.ldObjects_rightPowerRail() + powerrail.setlocalId(id) + element.addinstance(name, powerrail) + + def SetEditedElementPowerRailInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + powerrail = element.getinstance(id) + if powerrail is None: + return + for param, value in infos.items(): + if param == "height": + powerrail.setheight(value) + elif param == "width": + powerrail.setwidth(value) + elif param == "x": + powerrail.setx(value) + elif param == "y": + powerrail.sety(value) + elif param == "connectors": + if isinstance(powerrail, plcopen.ldObjects_leftPowerRail): + powerrail.setconnectionPointOut([]) + for connector in value["outputs"]: + position = connector.GetRelPosition() + connection = plcopen.leftPowerRail_connectionPointOut() + connection.setrelPositionXY(position.x, position.y) + powerrail.connectionPointOut.append(connection) + elif isinstance(powerrail, plcopen.ldObjects_rightPowerRail): + powerrail.setconnectionPointIn([]) + for connector in value["inputs"]: + position = connector.GetRelPosition() + connection = plcopen.connectionPointIn() + connection.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(connection, connector) + powerrail.connectionPointIn.append(connection) + + def AddEditedElementContact(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + contact = plcopen.ldObjects_contact() + contact.setlocalId(id) + element.addinstance("contact", contact) + + def SetEditedElementContactInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + contact = element.getinstance(id) + if contact is None: + return + for param, value in infos.items(): + if param == "name": + contact.setvariable(value) + elif param == "type": + if value == CONTACT_NORMAL: + contact.setnegated(False) + contact.setedge("none") + elif value == CONTACT_REVERSE: + contact.setnegated(True) + contact.setedge("none") + elif value == CONTACT_RISING: + contact.setnegated(False) + contact.setedge("rising") + elif value == CONTACT_FALLING: + contact.setnegated(False) + contact.setedge("falling") + elif param == "height": + contact.setheight(value) + elif param == "width": + contact.setwidth(value) + elif param == "x": + contact.setx(value) + elif param == "y": + contact.sety(value) + elif param == "connectors": + input_connector = value["inputs"][0] + position = input_connector.GetRelPosition() + contact.addconnectionPointIn() + contact.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(contact.connectionPointIn, input_connector) + output_connector = value["outputs"][0] + position = output_connector.GetRelPosition() + contact.addconnectionPointOut() + contact.connectionPointOut.setrelPositionXY(position.x, position.y) + + def AddEditedElementCoil(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + coil = plcopen.ldObjects_coil() + coil.setlocalId(id) + element.addinstance("coil", coil) + + def SetEditedElementCoilInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + coil = element.getinstance(id) + if coil is None: + return + for param, value in infos.items(): + if param == "name": + coil.setvariable(value) + elif param == "type": + if value == COIL_NORMAL: + coil.setnegated(False) + coil.setstorage("none") + coil.setedge("none") + elif value == COIL_REVERSE: + coil.setnegated(True) + coil.setstorage("none") + coil.setedge("none") + elif value == COIL_SET: + coil.setnegated(False) + coil.setstorage("set") + coil.setedge("none") + elif value == COIL_RESET: + coil.setnegated(False) + coil.setstorage("reset") + coil.setedge("none") + elif value == COIL_RISING: + coil.setnegated(False) + coil.setstorage("none") + coil.setedge("rising") + elif value == COIL_FALLING: + coil.setnegated(False) + coil.setstorage("none") + coil.setedge("falling") + elif param == "height": + coil.setheight(value) + elif param == "width": + coil.setwidth(value) + elif param == "x": + coil.setx(value) + elif param == "y": + coil.sety(value) + elif param == "connectors": + input_connector = value["inputs"][0] + position = input_connector.GetRelPosition() + coil.addconnectionPointIn() + coil.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(coil.connectionPointIn, input_connector) + output_connector = value["outputs"][0] + position = output_connector.GetRelPosition() + coil.addconnectionPointOut() + coil.connectionPointOut.setrelPositionXY(position.x, position.y) + + def AddEditedElementStep(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + step = plcopen.sfcObjects_step() + step.setlocalId(id) + element.addinstance("step", step) + + def SetEditedElementStepInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + step = element.getinstance(id) + if step is None: + return + for param, value in infos.items(): + if param == "name": + step.setname(value) + elif param == "initial": + step.setinitialStep(value) + elif param == "height": + step.setheight(value) + elif param == "width": + step.setwidth(value) + elif param == "x": + step.setx(value) + elif param == "y": + step.sety(value) + elif param == "connectors": + if len(value["inputs"]) > 0: + input_connector = value["inputs"][0] + position = input_connector.GetRelPosition() + step.addconnectionPointIn() + step.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(step.connectionPointIn, input_connector) + else: + step.deleteconnectionPointIn() + if len(value["outputs"]) > 0: + output_connector = value["outputs"][0] + position = output_connector.GetRelPosition() + step.addconnectionPointOut() + step.connectionPointOut.setrelPositionXY(position.x, position.y) + else: + step.deleteconnectionPointOut() + elif param == "action": + if value: + position = value.GetRelPosition() + step.addconnectionPointOutAction() + step.connectionPointOutAction.setrelPositionXY(position.x, position.y) + else: + step.deleteconnectionPointOutAction() + + def AddEditedElementTransition(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + transition = plcopen.sfcObjects_transition() + transition.setlocalId(id) + element.addinstance("transition", transition) + + def SetEditedElementTransitionInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + transition = element.getinstance(id) + if transition is None: + return + for param, value in infos.items(): + if param == "type" and value != "connection": + transition.setconditionContent(value, infos["condition"]) + elif param == "height": + transition.setheight(value) + elif param == "width": + transition.setwidth(value) + elif param == "x": + transition.setx(value) + elif param == "y": + transition.sety(value) + elif param == "priority": + if value != 0: + transition.setpriority(value) + else: + transition.setpriority(None) + elif param == "connectors": + input_connector = value["inputs"][0] + position = input_connector.GetRelPosition() + transition.addconnectionPointIn() + transition.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(transition.connectionPointIn, input_connector) + output_connector = value["outputs"][0] + position = output_connector.GetRelPosition() + transition.addconnectionPointOut() + transition.connectionPointOut.setrelPositionXY(position.x, position.y) + elif infos.get("type", None) == "connection" and param == "connection" and value: + transition.setconditionContent("connection", None) + self.SetConnectionWires(transition.condition.content["value"], value) + + def AddEditedElementDivergence(self, tagname, id, type): + element = self.GetEditedElement(tagname) + if element is not None: + if type == SELECTION_DIVERGENCE: + name = "selectionDivergence" + divergence = plcopen.sfcObjects_selectionDivergence() + elif type == SELECTION_CONVERGENCE: + name = "selectionConvergence" + divergence = plcopen.sfcObjects_selectionConvergence() + elif type == SIMULTANEOUS_DIVERGENCE: + name = "simultaneousDivergence" + divergence = plcopen.sfcObjects_simultaneousDivergence() + elif type == SIMULTANEOUS_CONVERGENCE: + name = "simultaneousConvergence" + divergence = plcopen.sfcObjects_simultaneousConvergence() + divergence.setlocalId(id) + element.addinstance(name, divergence) + + def SetEditedElementDivergenceInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + divergence = element.getinstance(id) + if divergence is None: + return + for param, value in infos.items(): + if param == "height": + divergence.setheight(value) + elif param == "width": + divergence.setwidth(value) + elif param == "x": + divergence.setx(value) + elif param == "y": + divergence.sety(value) + elif param == "connectors": + input_connectors = value["inputs"] + if isinstance(divergence, (plcopen.sfcObjects_selectionDivergence, plcopen.sfcObjects_simultaneousDivergence)): + position = input_connectors[0].GetRelPosition() + divergence.addconnectionPointIn() + divergence.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(divergence.connectionPointIn, input_connectors[0]) + else: + divergence.setconnectionPointIn([]) + for input_connector in input_connectors: + position = input_connector.GetRelPosition() + if isinstance(divergence, plcopen.sfcObjects_selectionConvergence): + connection = plcopen.selectionConvergence_connectionPointIn() + else: + connection = plcopen.connectionPointIn() + connection.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(connection, input_connector) + divergence.appendconnectionPointIn(connection) + output_connectors = value["outputs"] + if isinstance(divergence, (plcopen.sfcObjects_selectionConvergence, plcopen.sfcObjects_simultaneousConvergence)): + position = output_connectors[0].GetRelPosition() + divergence.addconnectionPointOut() + divergence.connectionPointOut.setrelPositionXY(position.x, position.y) + else: + divergence.setconnectionPointOut([]) + for output_connector in output_connectors: + position = output_connector.GetRelPosition() + if isinstance(divergence, plcopen.sfcObjects_selectionDivergence): + connection = plcopen.selectionDivergence_connectionPointOut() + else: + connection = plcopen.simultaneousDivergence_connectionPointOut() + connection.setrelPositionXY(position.x, position.y) + divergence.appendconnectionPointOut(connection) + + def AddEditedElementJump(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + jump = plcopen.sfcObjects_jumpStep() + jump.setlocalId(id) + element.addinstance("jumpStep", jump) + + def SetEditedElementJumpInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + jump = element.getinstance(id) + if jump is None: + return + for param, value in infos.items(): + if param == "target": + jump.settargetName(value) + elif param == "height": + jump.setheight(value) + elif param == "width": + jump.setwidth(value) + elif param == "x": + jump.setx(value) + elif param == "y": + jump.sety(value) + elif param == "connector": + position = value.GetRelPosition() + jump.addconnectionPointIn() + jump.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(jump.connectionPointIn, value) + + def AddEditedElementActionBlock(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + actionBlock = plcopen.commonObjects_actionBlock() + actionBlock.setlocalId(id) + element.addinstance("actionBlock", actionBlock) + + def SetEditedElementActionBlockInfos(self, tagname, id, infos): + element = self.GetEditedElement(tagname) + if element is not None: + actionBlock = element.getinstance(id) + if actionBlock is None: + return + for param, value in infos.items(): + if param == "actions": + actionBlock.setactions(value) + elif param == "height": + actionBlock.setheight(value) + elif param == "width": + actionBlock.setwidth(value) + elif param == "x": + actionBlock.setx(value) + elif param == "y": + actionBlock.sety(value) + elif param == "connector": + position = value.GetRelPosition() + actionBlock.addconnectionPointIn() + actionBlock.connectionPointIn.setrelPositionXY(position.x, position.y) + self.SetConnectionWires(actionBlock.connectionPointIn, value) + + def RemoveEditedElementInstance(self, tagname, id): + element = self.GetEditedElement(tagname) + if element is not None: + instance = element.getinstance(id) + if isinstance(instance, plcopen.fbdObjects_block): + self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName()) + element.removeinstance(id) + self.Project.RefreshElementUsingTree() + + def GetEditedResourceVariables(self, tagname, debug = False): + varlist = [] + words = tagname.split("::") + for var in self.GetConfigurationGlobalVars(words[1], debug): + if var["Type"] == "BOOL": + varlist.append(var["Name"]) + for var in self.GetConfigurationResourceGlobalVars(words[1], words[2], debug): + if var["Type"] == "BOOL": + varlist.append(var["Name"]) + return varlist + + def SetEditedResourceInfos(self, tagname, tasks, instances): + resource = self.GetEditedElement(tagname) + if resource is not None: + resource.settask([]) + resource.setpouInstance([]) + task_list = {} + for task in tasks: + new_task = plcopen.resource_task() + new_task.setname(task["Name"]) + if task["Triggering"] == "Interrupt": + new_task.setsingle(task["Single"]) +## result = duration_model.match(task["Interval"]).groups() +## if reduce(lambda x, y: x or y != None, result): +## values = [] +## for value in result[:-1]: +## if value != None: +## values.append(int(value)) +## else: +## values.append(0) +## if result[-1] is not None: +## values.append(int(float(result[-1]) * 1000)) +## new_task.setinterval(datetime.time(*values)) + if task["Triggering"] == "Cyclic": + new_task.setinterval(task["Interval"]) + new_task.setpriority(int(task["Priority"])) + if task["Name"] != "": + task_list[task["Name"]] = new_task + resource.appendtask(new_task) + for instance in instances: + new_instance = plcopen.pouInstance() + new_instance.setname(instance["Name"]) + new_instance.settypeName(instance["Type"]) + task_list.get(instance["Task"], resource).appendpouInstance(new_instance) + + def GetEditedResourceInfos(self, tagname, debug = False): + resource = self.GetEditedElement(tagname, debug) + if resource is not None: + tasks = resource.gettask() + instances = resource.getpouInstance() + tasks_data = [] + instances_data = [] + for task in tasks: + new_task = {} + new_task["Name"] = task.getname() + single = task.getsingle() + if single is not None: + new_task["Single"] = single + else: + new_task["Single"] = "" + interval = task.getinterval() + if interval is not None: +## text = "" +## if interval.hour != 0: +## text += "%dh"%interval.hour +## if interval.minute != 0: +## text += "%dm"%interval.minute +## if interval.second != 0: +## text += "%ds"%interval.second +## if interval.microsecond != 0: +## if interval.microsecond % 1000 != 0: +## text += "%.3fms"%(float(interval.microsecond) / 1000) +## else: +## text += "%dms"%(interval.microsecond / 1000) +## new_task["Interval"] = text + new_task["Interval"] = interval + else: + new_task["Interval"] = "" + if single is not None and interval is None: + new_task["Triggering"] = "Interrupt" + elif interval is not None and single is None: + new_task["Triggering"] = "Cyclic" + else: + new_task["Triggering"] = "" + new_task["Priority"] = str(task.getpriority()) + tasks_data.append(new_task) + for instance in task.getpouInstance(): + new_instance = {} + new_instance["Name"] = instance.getname() + new_instance["Type"] = instance.gettypeName() + new_instance["Task"] = task.getname() + instances_data.append(new_instance) + for instance in instances: + new_instance = {} + new_instance["Name"] = instance.getname() + new_instance["Type"] = instance.gettypeName() + new_instance["Task"] = "" + instances_data.append(new_instance) + return tasks_data, instances_data + + def OpenXMLFile(self, filepath): + xmlfile = open(filepath, 'r') + tree = minidom.parse(xmlfile) + xmlfile.close() + + self.Project = plcopen.project() + for child in tree.childNodes: + if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project": + try: + result = self.Project.loadXMLTree(child) + except ValueError, e: + return _("Project file syntax error:\n\n") + str(e) + self.SetFilePath(filepath) + self.Project.RefreshElementUsingTree() + self.Project.RefreshDataTypeHierarchy() + self.Project.RefreshCustomBlockTypes() + self.CreateProjectBuffer(True) + self.ProgramChunks = [] + self.ProgramOffset = 0 + self.NextCompiledProject = self.Copy(self.Project) + self.CurrentCompiledProject = None + self.Buffering = False + self.CurrentElementEditing = None + return None + return _("No PLC project found") + + def SaveXMLFile(self, filepath = None): + if not filepath and self.FilePath == "": + return False + else: + contentheader = {"modificationDateTime": datetime.datetime(*localtime()[:6])} + self.Project.setcontentHeader(contentheader) + + text = "\n" + extras = {"xmlns" : "http://www.plcopen.org/xml/tc6.xsd", + "xmlns:xhtml" : "http://www.w3.org/1999/xhtml", + "xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation" : "http://www.plcopen.org/xml/tc6.xsd"} + text += self.Project.generateXMLText("project", 0, extras) + + if filepath: + xmlfile = open(filepath,"w") + else: + xmlfile = open(self.FilePath,"w") + xmlfile.write(text.encode("utf-8")) + xmlfile.close() + self.MarkProjectAsSaved() + if filepath: + self.SetFilePath(filepath) + return True + +#------------------------------------------------------------------------------- +# Search in Current Project Functions +#------------------------------------------------------------------------------- + + def SearchInProject(self, criteria): + return self.Project.Search(criteria) + + def SearchInPou(self, tagname, criteria, debug=False): + pou = self.GetEditedElement(tagname, debug) + if pou is not None: + return pou.Search(criteria) + return [] + +#------------------------------------------------------------------------------- +# Current Buffering Management Functions +#------------------------------------------------------------------------------- + + """ + Return a copy of the project + """ + def Copy(self, model): + return cPickle.loads(cPickle.dumps(model)) + + def CreateProjectBuffer(self, saved): + if self.ProjectBufferEnabled: + self.ProjectBuffer = UndoBuffer(cPickle.dumps(self.Project), saved) + else: + self.ProjectBuffer = None + self.ProjectSaved = saved + + def IsProjectBufferEnabled(self): + return self.ProjectBufferEnabled + + def EnableProjectBuffer(self, enable): + self.ProjectBufferEnabled = enable + if self.Project is not None: + if enable: + current_saved = self.ProjectSaved + else: + current_saved = self.ProjectBuffer.IsCurrentSaved() + self.CreateProjectBuffer(current_saved) + + def BufferProject(self): + if self.ProjectBuffer is not None: + self.ProjectBuffer.Buffering(cPickle.dumps(self.Project)) + else: + self.ProjectSaved = False + + def StartBuffering(self): + if self.ProjectBuffer is not None: + self.Buffering = True + else: + self.ProjectSaved = False + + def EndBuffering(self): + if self.ProjectBuffer is not None and self.Buffering: + self.ProjectBuffer.Buffering(cPickle.dumps(self.Project)) + self.Buffering = False + + def MarkProjectAsSaved(self): + self.EndBuffering() + if self.ProjectBuffer is not None: + self.ProjectBuffer.CurrentSaved() + else: + self.ProjectSaved = True + + # Return if project is saved + def ProjectIsSaved(self): + if self.ProjectBuffer is not None: + return self.ProjectBuffer.IsCurrentSaved() and not self.Buffering + else: + return self.ProjectSaved + + def LoadPrevious(self): + self.EndBuffering() + if self.ProjectBuffer is not None: + self.Project = cPickle.loads(self.ProjectBuffer.Previous()) + + def LoadNext(self): + if self.ProjectBuffer is not None: + self.Project = cPickle.loads(self.ProjectBuffer.Next()) + + def GetBufferState(self): + if self.ProjectBuffer is not None: + first = self.ProjectBuffer.IsFirst() and not self.Buffering + last = self.ProjectBuffer.IsLast() + return not first, not last + return False, False