PLCControler.py
author lbessard
Fri, 16 Nov 2007 17:43:32 +0100
changeset 121 40b91ba978db
parent 118 0c53d6a36013
child 125 394d9f168258
permissions -rw-r--r--
Improving PLCOpenEditor for using wx2.8 AUI
#!/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 minixsv import pyxsval
from xml.dom import minidom
from types import StringType, UnicodeType
import cPickle
import os,sys,re
from datetime import *

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)?")

[ITEM_UNEDITABLE, ITEM_PROJECT, ITEM_POU, ITEM_CLASS, ITEM_VARIABLE,
 ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE] = range(9)

"""
pyxsval is not complete and the parts that are not supported print some error
reports. This class is used for not displaying them
"""
class HolePseudoFile:
    """ Base class for file like objects to facilitate StdOut for the Shell."""
    def __init__(self, output = None):
        if output is None: output = []
        self.output = output

    def writelines(self, l):
        map(self.write, l)

    def write(self, s):
        pass

    def flush(self):
        pass
    
    def isatty(self):
        return false

#-------------------------------------------------------------------------------
#                         Undo Buffer for PLCOpenEditor
#-------------------------------------------------------------------------------

# Length of the buffer
UNDO_BUFFER_LENGTH = 20

"""
Class implementing a buffer of changes made on the current editing Object Dictionary
"""
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.VerifyXML = False
        self.Project = None
        self.ProjectBuffer = None
        self.Buffering = False
        self.FilePath = ""
        self.FileName = ""
        self.ProgramFilePath = ""
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()

    def GetQualifierTypes(self):
        return plcopen.QualifierList


#-------------------------------------------------------------------------------
#                         Project management functions
#-------------------------------------------------------------------------------

    # Return if a project is opened
    def HasOpenedProject(self):
        return self.Project != None

    # Create a new project by replacing the current one
    def CreateNewProject(self, name):
        # Create the project
        self.Project = plcopen.project()
        self.Project.setName(name)
        self.SetFilePath("")
        # Initialize the project buffer
        self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), False)
        self.Buffering = False
    
    # Return project pou names
    def GetProjectPouNames(self):
        if self.Project:
            return [pou.getName() for pou in self.Project.getPous()]
        return []
    
    # Return project pou names
    def GetProjectConfigNames(self):
        if self.Project:
            return [config.getName() for config in self.Project.getConfigurations()]
        return []
    
    # Return project pou variables
    def GetProjectPouVariables(self, pou_name=None):
        variables = []
        for pou in self.Project.getPous():
            if not pou_name or pou_name == pou.getName():
                variables.extend([var["Name"] for var in self.GetPouInterfaceVars(pou)])
                for transition in pou.getTransitionList():
                    variables.append(transition.getName())
                for action in pou.getActionList():
                    variables.append(action.getName())
        return variables
    
    # Return if project is saved
    def ProjectIsSaved(self):
        return self.ProjectBuffer.IsCurrentSaved()
    
    # 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.ProjectBuffer.IsCurrentSaved():
            return self.FileName
        else:
            return "~%s~"%self.FileName
    
    # 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):
        if name != None:
            self.Project.setName(name)
        if properties != None:
            self.Project.setFileHeader(properties)
        if name != None or properties != None:
            self.BufferProject()
            
    # Return project properties
    def GetProjectProperties(self):
        properties = self.Project.getFileHeader()
        properties["projectName"] = self.Project.getName()
        return properties
    
    # Return project informations
    def GetProjectInfos(self):
        if self.Project:
            infos = {"name": self.Project.getName(), "type": ITEM_PROJECT}
            pou_types = {"function": {"name": "Functions", "type": ITEM_UNEDITABLE, "values":[]},
                         "functionBlock": {"name": "Function Blocks", "type": ITEM_UNEDITABLE, "values":[]},
                         "program": {"name": "Programs", "type": ITEM_UNEDITABLE, "values":[]}}
            for pou in self.Project.getPous():
                pou_type = pou.getPouType().getValue()
                pou_infos = {"name": pou.getName(), "type": ITEM_POU}
                pou_values = []
                if pou.getBodyType() == "SFC":
                    transitions = []
                    for transition in pou.getTransitionList():
                        transitions.append({"name": transition.getName(), "type": ITEM_TRANSITION, "values": []})
                    pou_values.append({"name": "Transitions", "type": ITEM_UNEDITABLE, "values": transitions})
                    actions = []
                    for action in pou.getActionList():
                        actions.append({"name": action.getName(), "type": ITEM_ACTION, "values": []})
                    pou_values.append({"name": "Actions", "type": ITEM_UNEDITABLE, "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_UNEDITABLE, "values": []}
            for config in self.Project.getConfigurations():
                config_name = config.getName()
                config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []}
                resources = {"name": "Resources", "type": ITEM_UNEDITABLE, "values": []}
                for resource in config.getResource():
                    resource_name = resource.getName()
                    resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []}
                    resources["values"].append(resource_infos)
                config_infos["values"] = [resources]
                configurations["values"].append(config_infos)
            infos["values"] = [{"name": "Properties", "type": ITEM_UNEDITABLE, "values": []},
                               pou_types["function"], pou_types["functionBlock"], 
                               pou_types["program"], configurations]
            return infos
        return None

    # Refresh the tree of user-defined pou cross-use
    def RefreshPouUsingTree(self):
        # Reset the tree of user-defined pou cross-use
        self.PouUsingTree = {}
        if self.Project:
            pous = self.Project.getPous()
            # Reference all the user-defined pou names and initialize the tree of 
            # user-defined pou cross-use
            pounames = [pou.getName() for pou in pous]
            for name in pounames:
                self.PouUsingTree[name] = []
            # Analyze each pou 
            for pou in pous:
                name = pou.getName()
                if pou.interface:
                    # Extract variables from every varLists
                    for type, varlist in pou.getVars():
                        for var in varlist.getVariable():
                            var_type = var.getType().getValue()
                            if not isinstance(var_type, (StringType, UnicodeType)):
                                typename = var_type.getName()
                                if typename in pounames and name not in self.PouUsingTree[typename]:
                                    self.PouUsingTree[typename].append(name)
                bodytype = pou.getBodyType()
                # If pou is written in a graphical language
                if bodytype in ["FBD","LD","SFC"]:
                    # Analyze each instance of the pou
                    for instance in pou.getInstances():
                        if isinstance(instance, plcopen.block):
                            typename = instance.getTypeName()
                            # Update tree if there is a cross-use
                            if typename in pounames and name not in self.PouUsingTree[typename]:
                                 self.PouUsingTree[typename].append(name)
                # If pou is written in a textual language
                elif bodytype in ["IL", "ST"]:
                    text = pou.getText()
                    # Search if each pou is mentioned in the pou text
                    for typename in pounames:
                        typename_model = re.compile("[ \t\n]%s[ \t\n]"%typename)
                        # Update tree if there is a cross-use
                        if typename != name and typename_model.search(text):
                            self.PouUsingTree[typename].append(name)

    # Return if pou given by name is used by another pou
    def PouIsUsed(self, name):
        if name in self.PouUsingTree:
            return len(self.PouUsingTree[name]) > 0
        return False

    # Return if pou given by name is directly or undirectly used by the reference pou
    def PouIsUsedBy(self, name, reference):
        if name in self.PouUsingTree:
            list = self.PouUsingTree[name]
            # Test if pou is directly used by reference
            if reference in list:
                return True
            else:
                # Test if pou is undirectly used by reference, by testing if pous 
                # that directly use pou is directly or undirectly used by reference
                used = False
                for element in list:
                    used |= self.PouIsUsedBy(element, reference)
                return used
        return False

    def GenerateProgram(self, filepath):
        if self.Project:
            try:
                program = GenerateCurrentProgram(self.Project)
                programfile = open(filepath, "w")
                programfile.write(program)
                programfile.close()
                self.ProgramFilePath = filepath
                return True
            except:
                pass
        return False

#-------------------------------------------------------------------------------
#                        Project Pous management functions
#-------------------------------------------------------------------------------
        
    # Add a Pou to Project
    def ProjectAddPou(self, pou_name, pou_type, body_type):
        # Add the pou to project
        self.Project.appendPou(pou_name, pou_type, body_type)
        if pou_type == "function":
            self.SetPouInterfaceReturnType(pou_name, "BOOL")
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
        self.BufferProject()
    
    # Remove a pou from project
    def ProjectRemovePou(self, pou_name):
        self.Project.removePou(pou_name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
        self.BufferProject()
    
    # Add a configuration to Project
    def ProjectAddConfiguration(self, config_name):
        self.Project.addConfiguration(config_name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
        self.BufferProject()
    
    # Remove a configuration from project
    def ProjectRemoveConfiguration(self, config_name):
        self.Project.removeConfiguration(config_name)
        self.BufferProject()
    
    # Add a resource to a configuration of the Project
    def ProjectAddConfigurationResource(self, config_name, resource_name):
        self.Project.addConfigurationResource(config_name, resource_name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
        self.BufferProject()
    
    # Remove a resource from a configuration of the project
    def ProjectRemoveConfigurationResource(self, config_name, resource_name):
        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):
        pou = self.Project.getPou(pou_name)
        pou.addTransition(transition_name, transition_type)
        self.BufferProject()
    
    # Remove a Transition from a Project Pou
    def ProjectRemovePouTransition(self, pou_name, transition_name):
        pou = self.Project.getPou(pou_name)
        pou.removeTransition(transition_name)
        self.BufferProject()
    
    # Add an Action to a Project Pou
    def ProjectAddPouAction(self, pou_name, action_name, action_type):
        pou = self.Project.getPou(pou_name)
        pou.addAction(action_name, action_type)
        self.BufferProject()
    
    # Remove an Action from a Project Pou
    def ProjectRemovePouAction(self, pou_name, action_name):
        # Search if the pou removed is currently opened
        for i, element in enumerate(self.ElementsOpened):
            words = element.split("::")
            if words[0] == "A" and words[1] == pou_name and words[2] == action_name:
                self.RemoveElementEditing(i)
        pou = self.Project.getPou(pou_name)
        pou.removeAction(action_name)
        self.BufferProject()
        
    # Change the name of a pou
    def ChangePouName(self, old_name, new_name):
        # Found the pou corresponding to old name and change its name to new name
        pou = self.Project.getPou(old_name)
        pou.setName(new_name)
        self.Project.updateElementName(old_name, new_name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
        self.BufferProject()
    
    # Change the name of a pou transition
    def ChangePouTransitionName(self, pou_name, old_name, new_name):
        # Found the pou transition corresponding to old name and change its name to new name
        pou = self.Project.getPou(pou_name)
        transition = pou.getTransition(old_name)
        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):
        # Found the pou action corresponding to old name and change its name to new name
        pou = self.Project.getPou(pou_name)
        action = pou.getAction(old_name)
        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):
        # Found the pou action corresponding to old name and change its name to new name
        pou = self.Project.getPou(pou_name)
        for type, varlist in pou.getVars():
            for var in varlist.getVariable():
                if var.getName() == old_name:
                    var.setName(new_name)
        self.RefreshBlockTypes()
        self.BufferProject()
        
    # Change the name of a configuration
    def ChangeConfigurationName(self, old_name, new_name):
        # Found the configuration corresponding to old name and change its name to new name
        configuration = self.Project.getConfiguration(old_name)
        configuration.setName(new_name)
        self.BufferProject()
    
    # Change the name of a configuration resource
    def ChangeConfigurationResourceName(self, config_name, old_name, new_name):
        # Found the resource corresponding to old name and change its name to new name
        resource = self.Project.getConfigurationResource(config_name)
        resource.setName(new_name)
        self.BufferProject()
    
    # Return the type of the pou given by its name
    def GetPouType(self, name):
        # Found the pou correponding to name and return its type
        pou = self.Project.getPou(name)
        return pou.pouType.getValue()
    
    # Return pous with SFC language
    def GetSFCPous(self):
        list = []
        if self.Project:
            for pou in self.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):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(name)
        return pou.getBodyType()
    
    # Return the actions of a pou
    def GetPouTransitions(self, pou_name):
        transitions = []
        pou = self.Project.getPou(pou_name)
        if 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):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(pou_name)
        transition = pou.getTransition(pou_transition)
        return transition.getBodyType()
    
    # Return the actions of a pou
    def GetPouActions(self, pou_name):
        actions = []
        pou = self.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):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(pou_name)
        action = pou.getAction(pou_action)
        return action.getBodyType()
    
    # Extract varlists from a list of vars
    def ExtractVarLists(self, vars):
        varlist_list = []
        current_varlist = None
        current_type = None
        for var in vars:
            if current_type != (var["Class"], var["Retain"], var["Constant"], var["Location"] in ["", None]):
                current_type = (var["Class"], var["Retain"], var["Constant"], var["Location"] in ["", None])
                current_varlist = plcopen.varList()
                varlist_list.append((var["Class"], current_varlist))
                if var["Retain"] == "Yes":
                    varlist.setRetain(True)
                if var["Constant"] == "Yes":
                    varlist.setConstant(True)
            # Create variable and change its properties
            tempvar = plcopen.varListPlain_variable()
            tempvar.setName(var["Name"])
            var_type = plcopen.dataType()
            if GetBlockType(var["Type"]) != None:
                derived_type = plcopen.derived()
                derived_type.setName(var["Type"])
                var_type.setValue(derived_type)
            else:
                var_type.setValue(var["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)
            # Add variable to varList
            current_varlist.appendVariable(tempvar)
        return varlist_list

    # Replace the configuration globalvars by those given
    def SetConfigurationGlobalVars(self, name, vars):
        # Found the configuration corresponding to name
        configuration = self.Project.getConfiguration(name)
        if configuration:
            # Set configuration global vars
            configuration.setGlobalVars([])
            for vartype, varlist in self.ExtractVarLists(vars):
                configuration.globalVars.append(varlist)
        self.RefreshBlockTypes()
    
    # Return the configuration globalvars
    def GetConfigurationGlobalVars(self, name):
        vars = []
        # Found the configuration corresponding to name
        configuration = self.Project.getConfiguration(name)
        if configuration:
            # Extract variables from every varLists
            for varlist in configuration.getGlobalVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":"Global"}
                    var_type = var.getType().getValue()
                    if isinstance(var_type, (StringType, UnicodeType)):
                        tempvar["Type"] = var_type
                    else:
                        tempvar["Type"] = var_type.getName()
                    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.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars

    # Replace the resource globalvars by those given
    def SetConfigurationResourceGlobalVars(self, config_name, name, vars):
        # Found the resource corresponding to name
        resource = self.Project.getConfigurationResource(config_name, name)
        # Set resource global vars
        if resource:
            resource.setGlobalVars([])
            for vartype, varlist in self.ExtractVarLists(vars):
                resource.globalVars.append(varlist)
        self.RefreshBlockTypes()
    
    # Return the resource globalvars
    def GetConfigurationResourceGlobalVars(self, config_name, name):
        vars = []
        # Found the resource corresponding to name
        resource = self.Project.getConfigurationResource(config_name, name)
        if resource:
            # Extract variables from every varLists
            for varlist in resource.getGlobalVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":"Global"}
                    var_type = var.getType().getValue()
                    if isinstance(var_type, (StringType, UnicodeType)):
                        tempvar["Type"] = var_type
                    else:
                        tempvar["Type"] = var_type.getName()
                    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.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars
    
    # Return the interface of the pou given by its name
    def GetPouInterfaceVarsByName(self, name):
        # Found the pou correponding to name and return the interface
        return self.GetPouInterfaceVars(self.Project.getPou(name))
    
    # Return the interface for the given pou
    def GetPouInterfaceVars(self, pou):
        vars = []
        # Verify that the pou has an interface
        if pou.interface:
            # Extract variables from every varLists
            for type, varlist in pou.getVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":type}
                    var_type = var.getType().getValue()
                    if isinstance(var_type, (StringType, UnicodeType)):
                        tempvar["Type"] = var_type
                        tempvar["Edit"] = True
                    else:
                        tempvar["Type"] = var_type.getName()
                        tempvar["Edit"] = not pou.hasBlock(tempvar["Name"])
                    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.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars

    # Replace the Pou interface by the one given
    def SetPouInterfaceVars(self, name, vars):
        # Found the pou corresponding to name and add interface if there isn't one yet
        pou = self.Project.getPou(name)
        if not pou.interface:
            pou.interface = plcopen.pou_interface()
        # Set Pou interface
        pou.setVars(self.ExtractVarLists(vars))
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Replace the return type of the pou given by its name (only for functions)
    def SetPouInterfaceReturnType(self, name, type):
        pou = self.Project.getPou(name)
        if not pou.interface:
            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
        return_type.setValue(type)
        self.RefreshBlockTypes()
    
    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):
        # Found the pou correponding to name and return the return type
        return self.GetPouInterfaceReturnType(self.Project.getPou(name))
    
    # Return the return type of the given pou
    def GetPouInterfaceReturnType(self, pou):
        # Verify that the pou has an interface
        if pou.interface:
            # Return the return type if there is one
            return_type = pou.interface.getReturnType()
            if return_type:
                return return_type.getValue()
        return None

    # Update Block types with user-defined pou added
    def RefreshBlockTypes(self):
        if BlockTypes[-1]["name"] == "User-defined POUs":
            BlockTypes[-1]["list"] = []
        else:
            BlockTypes.append({"name" : "User-defined POUs", "list": []})
        if self.Project:
            for pou in self.Project.getPous():
                pou_name = pou.getName()
                pou_type = pou.pouType.getValue()
                if pou_type != "program":
                    block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
                                   "inputs" : [], "outputs" : [], "comment" : "",
                                   "generate" : generate_block, "initialise" : initialise_block }
                    if pou.getInterface():
                        for type, varlist in pou.getVars():
                            if type == "InOut":
                                for var in varlist.getVariable():
                                    block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
                                    block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
                            elif type == "Input":
                                for var in varlist.getVariable():
                                    block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
                            elif type == "Output":
                                for var in varlist.getVariable():
                                    block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
                        return_type = pou.interface.getReturnType()
                        if return_type:
                            block_infos["outputs"].append(("",return_type.getValue(),"none"))
                    if pou.getBodyType() in ["FBD","LD","SFC"]:
                        for instance in pou.getInstances():
                            if isinstance(instance, plcopen.comment):
                                block_infos["comment"] = instance.getContentText()
                    BlockTypes[-1]["list"].append(block_infos)
    
    # Return Block types checking for recursion
    def GetBlockTypes(self, tagname = ""):
        if self.Project:
            words = tagname.split("::")
            if len(words) == 1:
                name = current_name
            else:
                name = words[1]
            type = self.GetPouType(name)
        else:
            name = ""
            type = None
        if type == "function":
            blocktypes = []
            for category in BlockTypes[:-1] + PluginTypes:
                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[:-1] + PluginTypes]
        if self.Project:
            blocktypes.append({"name" : "User-defined POUs", "list": []})
            for blocktype in BlockTypes[-1]["list"]:
                if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
                    blocktypes[-1]["list"].append(blocktype)
        return blocktypes

    # Return Function Block types checking for recursion
    def GetFunctionBlockTypes(self, tagname = ""):
        name = ""
        type = None
        if self.Project:
            words = tagname.split("::")
            if words[0] in ["P","T","A"]:
                if len(words) == 1:
                    name = current_name
                else:
                    name = words[1]
                type = self.GetPouType(name)
        blocktypes = []
        for category in BlockTypes[:-1]:
            for block in category["list"]:
                if block["type"] != "function":
                    blocktypes.append(block["name"])
        if self.Project:
            for blocktype in BlockTypes[-1]["list"]:
                if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
                    blocktypes.append(blocktype["name"])
        return blocktypes

    # Return Block types checking for recursion
    def GetBlockResource(self):
        blocktypes = []
        for category in BlockTypes[:-1]:
            for blocktype in category["list"]:
                if blocktype["type"] == "program":
                    blocktypes.append(blocktype["name"])
        if self.Project:
            for pou in self.Project.getPous():
                if pou.pouType.getValue() == "program":
                    blocktypes.append(pou.getName())
        return blocktypes

#-------------------------------------------------------------------------------
#                   Project Element tag name computation functions
#-------------------------------------------------------------------------------
    
    # Compute a pou transition 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)
    
#-------------------------------------------------------------------------------
#                       Project opened Pous management functions
#-------------------------------------------------------------------------------

    # Return edited element
    def GetEditedElement(self, tagname):
        words = tagname.split("::")
        if words[0] == "P":
            return self.Project.getPou(words[1])
        if words[0] in ['T', 'A']:
            pou = self.Project.getPou(words[1])
            if words[0] == 'T':
                return pou.getTransition(words[2])
            elif words[0] == 'A':
                return pou.getAction(words[2])
        elif words[0] == 'C':
            return self.Project.getConfiguration(words[1])
        elif words[0] == 'R':
            return self.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"]:
            return words[1]
        else:
            return words[2]
        return None
    
    # Return edited element name and type
    def GetEditedElementType(self, tagname):
        words = tagname.split("::")
        if words[0] in ["P","T","A"]:
            return words[1], self.GetPouType(words[1])
        return None, None

    # Return language in which edited element is written
    def GetEditedElementBodyType(self, tagname):
        words = tagname.split("::")
        if words[0] == "P":
            return self.GetPouBodyType(words[1])
        elif words[0] == 'T':
            return self.GetTransitionBodyType(words[1], words[2])
        elif words[0] == 'A':
            return self.GetActionBodyType(words[1], words[2])
        return None

    # Return the edited element variables
    def GetEditedElementInterfaceVars(self, tagname):
        words = tagname.split("::")
        if words[0] in ["P","T","A"]:
            pou = self.Project.getPou(words[1])
            return self.GetPouInterfaceVars(pou)
        return []

    # Return the edited element return type
    def GetEditedElementInterfaceReturnType(self, tagname):
        words = tagname.split("::")
        if words[0] == "P":
            pou = self.Project.getPou(words[1])
            return self.GetPouInterfaceReturnType(pou)
        elif words[0] == 'T':
            return "BOOL"
        return None
    
    # Change the edited element taxt
    def SetEditedElementText(self, tagname, text):
        element = self.GetEditedElement(tagname)
        if element != None:
            element.setText(text)
            self.RefreshPouUsingTree()
    
    # Return the edited element text
    def GetEditedElementText(self, tagname):
        element = self.GetEditedElement(tagname)
        if element != None:
            return element.getText()
        return ""

    # Return the edited element transitions
    def GetEditedElementTransitions(self, tagname):
        pou = self.GetEditedElement(tagname)
        if pou != 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):
        pou = self.GetEditedElement(tagname)
        if pou != 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):
        words = tagname.split("::")
        if words[0] in ["P","T","A"]:
            return self.GetProjectPouVariables(words[1])
        return []

    # Return the current pou editing informations
    def GetEditedElementInstanceInfos(self, tagname, id = None, exclude = []):
        infos = {}
        instance = None
        element = self.GetEditedElement(tagname)
        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:
            if id is not None:
                infos["id"] = id
            else:
                infos["id"] = instance.getLocalId() 
            infos["x"] = instance.getX()
            infos["y"] = instance.getY()
            infos["height"] = instance.getHeight()
            infos["width"] = instance.getWidth()
            if isinstance(instance, plcopen.block):
                infos["name"] = instance.getInstanceName()
                infos["type"] = instance.getTypeName()
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connectors"] = {"inputs":[],"outputs":[]}
                for variable in instance.inputVariables.getVariable():
                    connector = {}
                    connector["name"] = variable.getFormalParameter()
                    connector["position"] = variable.connectionPointIn.getRelPosition()
                    connector["negated"] = variable.getNegated()
                    connector["edge"] = variable.getConnectorEdge()
                    connector["links"] = []
                    connections = variable.connectionPointIn.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                            connector["links"].append(dic)
                    infos["connectors"]["inputs"].append(connector)
                for variable in instance.outputVariables.getVariable():
                    connector = {}
                    connector["name"] = variable.getFormalParameter()
                    connector["position"] = variable.connectionPointOut.getRelPosition()
                    connector["negated"] = variable.getNegated()
                    connector["edge"] = variable.getConnectorEdge()
                    infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, plcopen.inVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"])
                infos["type"] = "input"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
                infos["connector"]["negated"] = instance.getNegated()
                infos["connector"]["edge"] = instance.getConnectorEdge()
            elif isinstance(instance, plcopen.outVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"])
                infos["type"] = "output"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["negated"] = instance.getNegated()
                infos["connector"]["edge"] = instance.getConnectorEdge()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.inOutVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetEditedElementVarValueType(tagname, infos["name"])
                infos["type"] = "inout"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
                infos["connectors"]["output"]["negated"] = instance.getNegatedOut()
                infos["connectors"]["output"]["edge"] = instance.getOutputEdge()
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["negated"] = instance.getNegatedIn()
                infos["connectors"]["input"]["edge"] = instance.getInputEdge()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connectors"]["input"]["links"].append(dic)
            elif isinstance(instance, plcopen.continuation):
                infos["name"] = instance.getName()
                infos["value_type"] = self.GetCurrentPouVarValueType(infos["name"])
                infos["type"] = "continuation"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.connector):
                infos["name"] = instance.getName()
                infos["value_type"] = self.GetCurrentPouVarValueType(infos["name"])
                infos["type"] = "connection"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.comment):
                infos["type"] = "comment"
                infos["content"] = instance.getContentText()
            elif isinstance(instance, plcopen.leftPowerRail):
                infos["type"] = "leftPowerRail"
                infos["connectors"] = []
                for connection in instance.getConnectionPointOut():
                    connector = {}
                    connector["position"] = connection.getRelPosition()
                    infos["connectors"].append(connector)
            elif isinstance(instance, plcopen.rightPowerRail):
                infos["type"] = "rightPowerRail"
                infos["connectors"] = []
                for connection in instance.getConnectionPointIn():
                    connector = {}
                    connector["position"] = connection.getRelPosition()
                    connector["links"] = []
                    for link in connection.getConnections():
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        connector["links"].append(dic)
                    infos["connectors"].append(connector)
            elif isinstance(instance, plcopen.contact):
                infos["name"] = instance.getVariable()
                infos["type"] = "contact"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["negated"] = instance.getNegated()
                infos["edge"] = instance.getContactEdge()
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.coil):
                infos["name"] = instance.getVariable()
                infos["type"] = "coil"
                executionOrder = instance.getExecutionOrderId()
                if executionOrder is not None:
                    infos["executionOrder"] = executionOrder
                else:
                    infos["executionOrder"] = 0
                infos["negated"] = instance.getNegated()
                infos["storage"] = instance.getCoilStorage()
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.step):
                infos["name"] = instance.getName()
                infos["type"] = "step"
                infos["initial"] = instance.getInitialStep()
                infos["connectors"] = {}
                if instance.connectionPointIn:
                    infos["connectors"]["input"] = {}
                    infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                    infos["connectors"]["input"]["links"] = []
                    connections = instance.connectionPointIn.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                            infos["connectors"]["input"]["links"].append(dic)
                if instance.connectionPointOut:
                    infos["connectors"]["output"] = {"position" : instance.connectionPointOut.getRelPosition()}
                if instance.connectionPointOutAction:
                    infos["connectors"]["action"] = {"position" : instance.connectionPointOutAction.getRelPosition()}
            elif isinstance(instance, plcopen.transition):
                infos["type"] = "transition"
                condition = instance.getConditionContent()
                priority = instance.getPriority()
                if priority == None:
                    infos["priority"] = 0
                else:
                    infos["priority"] = priority
                infos["condition_type"] = condition["type"]
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
                if infos["condition_type"] == "connection":
                    infos["connectors"]["connection"] = {}
                    infos["connectors"]["connection"]["links"] = []
                    connections = instance.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                            infos["connectors"]["connection"]["links"].append(dic)
                    infos["condition"] = None
                else:
                    infos["condition"] = condition["value"]
            elif isinstance(instance, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)):
                if isinstance(instance, plcopen.selectionDivergence):
                    infos["type"] = "selectionDivergence"
                else:
                    infos["type"] = "simultaneousDivergence"
                infos["connectors"] = {"inputs":[],"outputs":[]}
                connector = {}
                connector["position"] = instance.connectionPointIn.getRelPosition()
                connector["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        connector["links"].append(dic)
                infos["connectors"]["inputs"].append(connector)
                for sequence in instance.getConnectionPointOut():
                    connector = {}
                    connector["position"] = sequence.getRelPosition()
                    infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)):
                if isinstance(instance, plcopen.selectionConvergence):
                    infos["type"] = "selectionConvergence"
                else:
                    infos["type"] = "simultaneousConvergence"
                infos["connectors"] = {"inputs":[],"outputs":[]}
                for sequence in instance.getConnectionPointIn():
                    connector = {}
                    connector["position"] = sequence.getRelPosition()
                    connector["links"] = []
                    connections = sequence.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                            connector["links"].append(dic)
                    infos["connectors"]["inputs"].append(connector)
                connector = {}
                connector["position"] = instance.connectionPointOut.getRelPosition()
                infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, plcopen.jumpStep):
                infos["type"] = "jump"
                infos["target"] = instance.getTargetName()
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.actionBlock):
                infos["type"] = "actionBlock"
                infos["actions"] = instance.getActions()
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                        infos["connector"]["links"].append(dic)
            return infos
        return False
    
    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):
        words = tagname.split("::")
        if words[0] in ["P","T","A"]:
            pou = self.Project.getPou(words[1])
            for type, varlist in pou.getVars():
                for var in varlist.getVariable():
                    if var.getName() == varname:
                        return var.getType().getValue()
        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
                connection.addConnection()
                connection.setConnectionId(idx, refLocalId)
                connection.setConnectionPoints(idx, points)
                if formalParameter != "":
                    connection.setConnectionParameter(idx, formalParameter)
                else:
                    connection.setConnectionParameter(idx, None)
                idx += 1
    
    def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None):
        element = self.GetEditedElement(tagname)
        if element is not None:
            block = plcopen.block()
            block.setLocalId(id)
            block.setTypeName(blocktype)
            blocktype_infos = GetBlockType(blocktype)
            if blocktype_infos["type"] != "function" and blockname is not None:
                block.setInstanceName(blockname)
                element.addPouVar(blocktype, blockname)    
            element.addInstance("block", block)
            self.RefreshPouUsingTree()
    
    def SetEditedElementBlockInfos(self, tagname, id, infos):
        element = self.GetEditedElement(tagname)
        if element is not None:
            block = element.getInstance(id)
            if "name" in infos or "type" in infos:
                old_name = block.getInstanceName()
                old_type = block.getTypeName()
                new_name = infos.get("name", old_name)
                new_type = infos.get("type", old_type)
                self.GetEditedElement(tagname).changePouVar(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:
                    self.GetEditedElement(tagname).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.setConnectorEdge(connector.GetEdge())
                        position = connector.GetRelPosition()
                        variable.connectionPointIn.setRelPosition(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.setConnectorEdge(connector.GetEdge())
                        position = connector.GetRelPosition()
                        variable.addConnectionPointOut()
                        variable.connectionPointOut.setRelPosition(position.x, position.y)
                        block.outputVariables.appendVariable(variable)
            self.RefreshPouUsingTree()
        
    def AddEditedElementVariable(self, tagname, id, type):
        element = self.GetEditedElement(tagname)
        if element is not None:            
            if type == INPUT:
                name = "inVariable"
                variable = plcopen.inVariable()
            elif type == OUTPUT:
                name = "outVariable"
                variable = plcopen.outVariable()
            elif type == INOUT:
                name = "inOutVariable"
                variable = plcopen.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)
            for param, value in infos.items():
                if param == "name":
                    variable.setExpression(value)    
                elif param == "executionOrder" and variable.getExecutionOrderId() != value:
                    self.GetEditedElement(tagname).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 isinstance(variable, plcopen.inVariable):
                        if value["output"].IsNegated():
                            variable.setNegated(True)
                        if value["output"].GetEdge() != "none":
                            variable.setConnectorEdge(value["output"].GetEdge())
                        position = value["output"].GetRelPosition()
                        variable.addConnectionPointOut()
                        variable.connectionPointOut.setRelPosition(position.x, position.y)
                    elif isinstance(variable, plcopen.outVariable):
                        if value["input"].IsNegated():
                            variable.setNegated(True)
                        if value["input"].GetEdge() != "none":
                            variable.setConnectorEdge(value["input"].GetEdge())
                        position = value["input"].GetRelPosition()
                        variable.addConnectionPointIn()
                        variable.connectionPointIn.setRelPosition(position.x, position.y)
                        self.SetConnectionWires(variable.connectionPointIn, value["input"])
                    elif isinstance(variable, plcopen.inOutVariable):
                        if value["input"].IsNegated():
                            variable.setNegatedIn(True)
                        if value["input"].GetEdge() != "none":
                            variable.setInputEdge(value["input"].GetEdge())
                        if value["output"].IsNegated():
                            variable.setNegatedOut(True)
                        if value["output"].GetEdge() != "none":
                            variable.setOutputEdge(value["output"].GetEdge())
                        position = value["output"].GetRelPosition()
                        variable.addConnectionPointOut()
                        variable.connectionPointOut.setRelPosition(position.x, position.y)
                        position = value["input"].GetRelPosition()
                        variable.addConnectionPointIn()
                        variable.connectionPointIn.setRelPosition(position.x, position.y)
                        self.SetConnectionWires(variable.connectionPointIn, value["input"])

    def AddEditedElementConnection(self, tagname, id, type):
        element = self.GetEditedElement(tagname)
        if element is not None:
            if type == CONNECTOR:
                name = "connector"
                connection = plcopen.connector()
            elif type == CONTINUATION:
                name = "continuation"
                connection = plcopen.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)
            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.continuation):
                        connection.addConnectionPointOut()
                        connection.connectionPointOut.setRelPosition(position.x, position.y)
                    elif isinstance(connection, plcopen.connector):
                        connection.addConnectionPointIn()
                        connection.connectionPointIn.setRelPosition(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.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.leftPowerRail()
            elif type == RIGHTRAIL:
                name = "rightPowerRail"
                powerrail = plcopen.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)
            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.leftPowerRail):
                        powerrail.setConnectionPointOut([])
                        for connector in value:
                            position = connector.GetRelPosition()
                            connection = plcopen.leftPowerRail_connectionPointOut()
                            connection.setRelPosition(position.x, position.y)
                            powerrail.connectionPointOut.append(connection)
                    elif isinstance(powerrail, plcopen.rightPowerRail):
                        powerrail.setConnectionPointIn([])
                        for connector in value:
                            position = connector.GetRelPosition()
                            connection = plcopen.connectionPointIn()
                            connection.setRelPosition(position.x, position.y)
                            self.SetConnectionWires(connection, connector)
                            powerrail.connectionPointIn.append(connection)

    def AddEditedElementEditingContact(self, tagname, id):
        element = self.GetEditedElement(tagname)
        if element is not None:
            contact = plcopen.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)
            for param, value in infos.items():
                if param == "name":
                    contact.setVariable(value)
                elif param == "type":
                    if value == CONTACT_NORMAL:
                        contact.setNegated(False)
                        contact.setContactEdge("none")
                    elif value == CONTACT_REVERSE:
                        contact.setNegated(True)
                        contact.setContactEdge("none")
                    elif value == CONTACT_RISING:
                        contact.setNegated(False)
                        contact.setContactEdge("rising")
                    elif value == CONTACT_FALLING:
                        contact.setNegated(False)
                        contact.setContactEdge("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["input"]
                    position = input_connector.GetRelPosition()
                    contact.addConnectionPointIn()
                    contact.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(contact.connectionPointIn, input_connector)
                    output_connector = value["output"]
                    position = output_connector.GetRelPosition()
                    contact.addConnectionPointOut()
                    contact.connectionPointOut.setRelPosition(position.x, position.y)

    def AddEditedElementCoil(self, tagname, id):
        element = self.GetEditedElement(tagname)
        if element is not None:
            coil = plcopen.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)
            for param, value in infos.items():
                if param == "name":
                    coil.setVariable(value)
                elif param == "type":
                    if value == COIL_NORMAL:
                        coil.setNegated(False)
                        coil.setCoilStorage("none")
                    elif value == COIL_REVERSE:
                        coil.setNegated(True)
                        coil.setCoilStorage("none")
                    elif value == COIL_SET:
                        coil.setNegated(False)
                        coil.setCoilStorage("set")
                    elif value == COIL_RESET:
                        coil.setNegated(False)
                        coil.setCoilStorage("reset")
                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["input"]
                    position = input_connector.GetRelPosition()
                    coil.addConnectionPointIn()
                    coil.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(coil.connectionPointIn, input_connector)
                    output_connector = value["output"]
                    position = output_connector.GetRelPosition()
                    coil.addConnectionPointOut()
                    coil.connectionPointOut.setRelPosition(position.x, position.y)

    def AddEditedElementStep(self, tagname, id):
        element = self.GetEditedElement(tagname)
        if element is not None:
            step = plcopen.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)
            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":
                    input_connector = value["input"]
                    if input_connector:
                        position = input_connector.GetRelPosition()
                        step.addConnectionPointIn()
                        step.connectionPointIn.setRelPosition(position.x, position.y)
                        self.SetConnectionWires(step.connectionPointIn, input_connector)
                    else:
                        step.deleteConnectionPointIn()
                    output_connector = value["output"]
                    if output_connector:
                        position = output_connector.GetRelPosition()
                        step.addConnectionPointOut()
                        step.connectionPointOut.setRelPosition(position.x, position.y)
                    else:
                        step.deleteConnectionPointOut()
                    action_connector = value["action"]
                    if action_connector:
                        position = action_connector.GetRelPosition()
                        step.addConnectionPointOutAction()
                        step.connectionPointOutAction.setRelPosition(position.x, position.y)
                    else:
                        step.deleteConnectionPointOutAction()
    
    def AddEditedElementTransition(self, tagname, id):
        element = self.GetEditedElement(tagname)
        if element is not None:
            transition = plcopen.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)
            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["input"]
                    position = input_connector.GetRelPosition()
                    transition.addConnectionPointIn()
                    transition.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(transition.connectionPointIn, input_connector)
                    output_connector = value["output"]
                    position = output_connector.GetRelPosition()
                    transition.addConnectionPointOut()
                    transition.connectionPointOut.setRelPosition(position.x, position.y)
                    if infos.get("type", None) == "connection":
                        transition.setConditionContent("connection", None)
                        connection_connector = value["connection"]
                        self.SetConnectionWires(transition, connection_connector)
    
    def AddEditedElementDivergence(self, tagname, id, type):
        element = self.GetEditedElement(tagname)
        if element is not None:
            if type == SELECTION_DIVERGENCE:
                name = "selectionDivergence"
                divergence = plcopen.selectionDivergence()
            elif type == SELECTION_CONVERGENCE:
                name = "selectionConvergence"
                divergence = plcopen.selectionConvergence()
            elif type == SIMULTANEOUS_DIVERGENCE:
                name = "simultaneousDivergence"
                divergence = plcopen.simultaneousDivergence()
            elif type == SIMULTANEOUS_CONVERGENCE:
                name = "simultaneousConvergence"
                divergence = plcopen.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)
            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.selectionDivergence, plcopen.simultaneousDivergence)):
                        position = input_connectors[0].GetRelPosition()
                        divergence.addConnectionPointIn()
                        divergence.connectionPointIn.setRelPosition(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.selectionConvergence):
                                connection = plcopen.selectionConvergence_connectionPointIn()
                            else:
                                connection = plcopen.connectionPointIn()
                            connection.setRelPosition(position.x, position.y)
                            self.SetConnectionWires(connection, input_connector)
                            divergence.appendConnectionPointIn(connection)
                    output_connectors = value["outputs"]
                    if isinstance(divergence, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)):
                        position = output_connectors[0].GetRelPosition()
                        divergence.addConnectionPointOut()
                        divergence.connectionPointOut.setRelPosition(position.x, position.y)
                    else:
                        divergence.setConnectionPointOut([])
                        for output_connector in output_connectors:
                            position = output_connector.GetRelPosition()
                            if isinstance(divergence, plcopen.selectionDivergence):
                                connection = plcopen.selectionDivergence_connectionPointOut()
                            else:
                                connection = plcopen.simultaneousDivergence_connectionPointOut()
                            connection.setRelPosition(position.x, position.y)
                            divergence.appendConnectionPointOut(connection)
    
    def AddEditedElementJump(self, tagname, id):
        element = self.GetEditedElement(tagname)
        if element is not None:
            jump = plcopen.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)
            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.setRelPosition(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.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)
            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.setRelPosition(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.block):
                blocktype = instance.getTypeName()
                element.removePouVar(blocktype, instance.getInstanceName())    
            element.removeInstance(id)
            self.RefreshPouUsingTree()

    def GetEditedResourceVariables(self, tagname):
        varlist = []
        words = tagname.split("::")
        for var in self.GetConfigurationGlobalVars(words[1]):
            if var["Type"] == "BOOL":
                varlist.append(var["Name"])
        for var in self.GetConfigurationResourceGlobalVars(words[1], words[2]):
            if var["Type"] == "BOOL":
                varlist.append(var["Name"])
        return varlist

    def SetEditedResourceInfos(self, 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["Single"] != "":
                    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)
                    values.append(int(float(result[-1]) * 1000))
                    new_task.setInterval(time(*values))
                new_task.priority.setValue(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.setType(instance["Type"])
                if instance["Task"] != "":
                    task_list[instance["Task"]].appendPouInstance(new_instance)
                else:
                    resource.appendPouInstance(new_instance)

    def GetEditedResourceInfos(self, tagname):
        resource = self.GetEditedElement(tagname)
        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:
                    new_task["Single"] = single
                else:
                    new_task["Single"] = ""
                interval = task.getInterval()
                if interval:
                    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
                else:
                    new_task["Interval"] = ""
                new_task["Priority"] = str(task.priority.getValue())
                tasks_data.append(new_task)
                for instance in task.getPouInstance():
                    new_instance = {}
                    new_instance["Name"] = instance.getName()
                    new_instance["Type"] = instance.getType()
                    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.getType()
                new_instance["Task"] = ""
                instances_data.append(new_instance)
            return tasks_data, instances_data

    def OpenXMLFile(self, filepath):
        if self.VerifyXML:
            if sys:
                sys.stdout = HolePseudoFile()
            result = pyxsval.parseAndValidate(filepath, os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"))
            if sys:
                sys.stdout = sys.__stdout__
            tree = result.getTree()
        else:
            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":
                self.Project.loadXMLTree(child)
                self.SetFilePath(filepath)
                self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), True)
                self.Buffering = False
                self.ElementsOpened = []
                self.CurrentElementEditing = None
                self.RefreshPouUsingTree()
                self.RefreshBlockTypes()
                return None
        return "No PLC project found"

    def SaveXMLFile(self, filepath = None):
        if not filepath and self.FilePath == "":
            return False
        else:
            text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 http://www.plcopen.org/xml/tc6.xsd"}
            text += self.Project.generateXMLText("project", 0, extras)

            if self.VerifyXML:
                if sys:
                    sys.stdout = HolePseudoFile()
                pyxsval.parseAndValidateString(text, open(os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"),"r").read())
                if sys:
                    sys.stdout = sys.__stdout__
            
            if filepath:
                xmlfile = open(filepath,"w")
            else:
                xmlfile = open(self.FilePath,"w")
            xmlfile.write(text)
            xmlfile.close()
            self.ProjectBuffer.CurrentSaved()
            if filepath:
                self.SetFilePath(filepath)
            return True

#-------------------------------------------------------------------------------
#                      Current Buffering Management Functions
#-------------------------------------------------------------------------------

    """
    Return a copy of the project
    """
    def Copy(self, model):
        return cPickle.loads(cPickle.dumps(model))

    def BufferProject(self):
        self.ProjectBuffer.Buffering(self.Copy(self.Project))

    def StartBuffering(self):
        self.ProjectBuffer.Buffering(self.Project)
        self.Buffering = True
        
    def EndBuffering(self):
        if self.Buffering:
            self.Project = self.Copy(self.Project)
            self.Buffering = False

    def ProjectIsSaved(self):
        if self.ProjectBuffer:
            return self.ProjectBuffer.IsCurrentSaved()
        else:
            return True

    def LoadPrevious(self):
        self.Project = self.Copy(self.ProjectBuffer.Previous())
    
    def LoadNext(self):
        self.Project = self.Copy(self.ProjectBuffer.Next())
    
    def GetBufferState(self):
        first = self.ProjectBuffer.IsFirst()
        last = self.ProjectBuffer.IsLast()
        return not first, not last