PLCOpenEditor initial commit. 31/01/07.
authoretisserant
Wed, 31 Jan 2007 16:31:39 +0100
changeset 0 b622defdfd98
child 1 e9d01d824086
PLCOpenEditor initial commit. 31/01/07.
.project
FBDViewer.py
GenerateProgram.py
Images/action.png
Images/action.svg
Images/block.png
Images/block.svg
Images/branch.png
Images/branch.svg
Images/coil.png
Images/coil.svg
Images/comment.png
Images/comment.svg
Images/connection.png
Images/connection.svg
Images/contact.png
Images/contact.svg
Images/divergence.png
Images/divergence.svg
Images/initial_step.png
Images/initial_step.svg
Images/jump.png
Images/jump.svg
Images/select.png
Images/select.svg
Images/step.png
Images/step.svg
Images/transition.png
Images/transition.svg
Images/variable.png
Images/variable.svg
Images/wire.png
Images/wire.svg
LDViewer.py
PLCControler.py
PLCGenerator.py
PLCOpenEditor.py
SFCViewer.py
Viewer.py
examples/example.xml
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
graphics/__init__.py
minixsv/__init__.py
minixsv/datatypes.xsd
minixsv/datatypes2.xsd
minixsv/elemtreeif.py
minixsv/minidomif.py
minixsv/pyxsval.py
minixsv/readme.txt
minixsv/xmlifbase.py
minixsv/xsStructs.xsd
minixsv/xsvalBase.py
minixsv/xsvalErrorHandler.py
minixsv/xsvalSchema.py
minixsv/xsvalSimpleTypes.py
plcopen/TC6_XML_V10.xsd
plcopen/TC6_XML_V101.pdf
plcopen/TC6_XML_V10_B.xsd
plcopen/__init__.py
plcopen/docpdf.py
plcopen/plcopen.py
plcopen/structures.py
snapshots/PLCOpenEditor_CreateBlockPopup.jpg
snapshots/PLCOpenEditor_FBDexample.jpg
snapshots/PLCOpenEditor_ILexample.jpg
snapshots/PLCOpenEditor_InterfacePopup.jpg
snapshots/PLCOpenEditor_LDexample.jpg
snapshots/PLCOpenEditor_PropertiesPopup.jpg
snapshots/PLCOpenEditor_SFCexample.jpg
snapshots/PLCOpenEditor_STexample.jpg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>plcopeneditor</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FBDViewer.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,793 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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 wxPython.wx import *
+import wx
+
+from plcopen.structures import *
+from graphics.GraphicCommons import *
+from graphics.FBD_Objects import *
+from Viewer import *
+
+class FBD_Viewer(Viewer):
+    
+    def __init__(self, parent, window, controler):
+        Viewer.__init__(self, parent, window, controler)
+
+#-------------------------------------------------------------------------------
+#                          Mouse event functions
+#-------------------------------------------------------------------------------
+
+    def OnViewerLeftDown(self, event):
+        if self.Mode == MODE_SELECTION:
+            pos = event.GetPosition()
+            if event.ControlDown() and self.SelectedElement:
+                element = self.FindElement(pos, True)
+                if element:
+                    if isinstance(self.SelectedElement, Graphic_Group):
+                        self.SelectedElement.SetSelected(False)
+                        self.SelectedElement.SelectElement(element)
+                    elif self.SelectedElement:
+                        group = Graphic_Group(self)
+                        group.SelectElement(self.SelectedElement)
+                        group.SelectElement(element)
+                        self.SelectedElement = group
+                    elements = self.SelectedElement.GetElements()
+                    if len(elements) == 0:
+                        self.SelectedElement = element
+                    elif len(elements) == 1:
+                        self.SelectedElement = elements[0]
+                    self.SelectedElement.SetSelected(True)
+            else:
+                element = self.FindElement(pos)
+                if self.SelectedElement and self.SelectedElement != element:
+                    self.SelectedElement.SetSelected(False)
+                    self.SelectedElement = None
+                    self.Refresh()
+                if element:
+                    self.SelectedElement = element
+                    self.SelectedElement.OnLeftDown(event, self.Scaling)
+                    self.Refresh()
+                else:
+                    self.rubberBand.Reset()
+                    self.rubberBand.OnLeftDown(event, self.Scaling)
+        elif self.Mode in [MODE_BLOCK,MODE_VARIABLE,MODE_CONNECTION,MODE_COMMENT]:
+            self.rubberBand.Reset()
+            self.rubberBand.OnLeftDown(event, self.Scaling)
+        elif self.Mode == MODE_WIRE:
+            pos = GetScaledEventPosition(event, self.Scaling)
+            wire = Wire(self, [wxPoint(pos.x, pos.y), EAST], [wxPoint(pos.x, pos.y), WEST])
+            wire.oldPos = pos
+            wire.Handle = (HANDLE_POINT, 0)
+            wire.ProcessDragging(0, 0)
+            wire.Handle = (HANDLE_POINT, 1)
+            self.Wires.append(wire)
+            self.Elements.append(wire)
+            if self.SelectedElement:
+                self.SelectedElement.SetSelected(False)
+            self.SelectedElement = wire
+            self.Refresh()
+        event.Skip()
+
+    def OnViewerLeftUp(self, event):
+        if self.rubberBand.IsShown():
+            if self.Mode == MODE_SELECTION:
+                elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                if len(elements) > 0:
+                    self.SelectedElement = Graphic_Group(self)
+                    self.SelectedElement.SetElements(elements)
+                    self.SelectedElement.SetSelected(True)
+                    self.Refresh()
+            elif self.Mode == MODE_BLOCK:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                wxCallAfter(self.AddNewBlock, bbox)
+            elif self.Mode == MODE_VARIABLE:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                wxCallAfter(self.AddNewVariable, bbox)
+            elif self.Mode == MODE_CONNECTION:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                wxCallAfter(self.AddNewConnection, bbox)
+            elif self.Mode == MODE_COMMENT:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                wxCallAfter(self.AddNewComment, bbox)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            self.SelectedElement.ResetPoints()
+            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.SelectedElement.GeneratePoints()
+            self.SelectedElement.RefreshModel()
+            self.SelectedElement.SetSelected(True)
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerRightUp(self, event):
+        pos = event.GetPosition()
+        element = self.FindElement(pos)
+        if element:
+            if self.SelectedElement and self.SelectedElement != element:
+                self.SelectedElement.SetSelected(False)
+            self.SelectedElement = element
+            self.SelectedElement.SetSelected(True)
+            self.SelectedElement.OnRightUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerLeftDClick(self, event):
+        if self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftDClick(event, self.Scaling)
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerMotion(self, event):
+        if self.rubberBand.IsShown():
+            self.rubberBand.OnMotion(event, self.Scaling)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            self.SelectedElement.ResetPoints()
+            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.SelectedElement.GeneratePoints()
+            self.Refresh()
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Keyboard event functions
+#-------------------------------------------------------------------------------
+
+    def OnChar(self, event):
+        keycode = event.GetKeyCode()
+        if self.Scaling:
+            scaling = self.Scaling
+        else:
+            scaling = (8, 8)
+        if keycode == WXK_DELETE and self.SelectedElement:
+            self.SelectedElement.Clean()
+            self.SelectedElement.Delete()
+            self.SelectedElement = None
+        elif keycode == WXK_LEFT and self.SelectedElement:
+            self.SelectedElement.Move(-scaling[0], 0)
+        elif keycode == WXK_RIGHT and self.SelectedElement:
+            self.SelectedElement.Move(scaling[0], 0)
+        elif keycode == WXK_UP and self.SelectedElement:
+            self.SelectedElement.Move(0, -scaling[1])
+        elif keycode == WXK_DOWN and self.SelectedElement:
+            self.SelectedElement.Move(0, scaling[1])
+        self.Refresh()
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Adding element functions
+#-------------------------------------------------------------------------------
+
+    def AddNewBlock(self, bbox):
+        dialog = BlockPropertiesDialog(self.Parent)
+        dialog.SetBlockList(self.Controler.GetBlockTypes())
+        dialog.SetMinBlockSize((bbox.width, bbox.height))
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            if "name" in values:
+                block = FBD_Block(self, values["type"], values["name"], id, values["extension"])
+            else:
+                block = FBD_Block(self, values["type"], "", id, values["extension"])
+            block.SetPosition(bbox.x, bbox.y)
+            block.SetSize(values["width"], values["height"])
+            self.Blocks.append(block)
+            self.Elements.append(block)
+            self.Controler.AddCurrentElementEditingBlock(id)
+            self.RefreshBlockModel(block)
+            self.Parent.RefreshProjectTree()
+            self.Refresh()
+        dialog.Destroy()
+    
+    def AddNewVariable(self, bbox):
+        dialog = VariablePropertiesDialog(self.Parent)
+        dialog.SetMinVariableSize((bbox.width, bbox.height))
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                varlist.append((var["Name"], var["Class"], var["Type"]))
+        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
+        if returntype:
+            varlist.append((self.Controler.GetCurrentElementEditingName(), "Output", returntype))
+        dialog.SetVariables(varlist)
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            variable = FBD_Variable(self, values["type"], values["name"], values["value_type"], id)
+            variable.SetPosition(bbox.x, bbox.y)
+            variable.SetSize(values["width"], values["height"])
+            self.Blocks.append(variable)
+            self.Elements.append(variable)
+            self.Controler.AddCurrentElementEditingVariable(id, values["type"])
+            self.RefreshVariableModel(variable)
+            self.Parent.RefreshProjectTree()
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewConnection(self, bbox):
+        dialog = ConnectionPropertiesDialog(self.Parent)
+        dialog.SetMinConnectionSize((bbox.width, bbox.height))
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            connection = FBD_Connection(self, values["type"], values["name"], id)
+            connection.SetPosition(bbox.x, bbox.y)
+            connection.SetSize(values["width"], values["height"])
+            self.Blocks.append(connection)
+            self.Elements.append(connection)
+            self.Controler.AddCurrentElementEditingConnection(id, values["type"])
+            self.RefreshConnectionModel(connection)
+            self.Parent.RefreshProjectTree()
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewComment(self, bbox):
+        dialog = wxTextEntryDialog(self.Parent, "Add a new comment", "Please enter comment text", "", wxOK|wxCANCEL|wxTE_MULTILINE)
+        if dialog.ShowModal() == wxID_OK:
+            value = dialog.GetValue()
+            id = self.GetNewId()
+            comment = Comment(self, value, id)
+            comment.SetPosition(bbox.x, bbox.y)
+            min_width, min_height = comment.GetMinSize()
+            comment.SetSize(max(min_width,bbox.width),max(min_height,bbox.height))
+            self.Elements.append(comment)
+            self.Controler.AddCurrentElementEditingComment(id)
+            self.RefreshCommentModel(comment)
+            self.Refresh()
+        dialog.Destroy()
+            
+#-------------------------------------------------------------------------------
+#                          Delete element functions
+#-------------------------------------------------------------------------------
+
+    def DeleteBlock(self, block):
+        wires = []
+        for output in block.GetConnectors()["outputs"]:
+            wires.extend([wire[0] for wire in output.GetWires()])
+        block.Clean()
+        self.Blocks.remove(block)
+        self.Elements.remove(block)
+        self.Controler.RemoveCurrentElementEditingInstance(block.GetId())
+        for wire in wires:
+            wire.RefreshModel()
+        self.Parent.RefreshProjectTree()
+
+    def DeleteVariable(self, variable):
+        wires = []
+        if self.SelectedElement.GetType() == INPUT:
+            connector = variable.GetConnector()
+            wires.extend([wire[0] for wire in connector.GetWires()])
+        variable.Clean()
+        self.Blocks.remove(self.SelectedElement)
+        self.Elements.remove(self.SelectedElement)
+        self.Controler.RemoveCurrentElementEditingInstance(variable.GetId())
+        for wire in wires:
+            wire.RefreshModel()
+        self.Parent.RefreshProjectTree()
+
+    def DeleteConnection(self, connection):
+        wires = []
+        if self.SelectedElement.GetType() == CONTINUATION:
+            connector = connection.GetConnector()
+            wires.extend([wire[0] for wire in connector.GetWires()])
+        connection.Clean()
+        self.Blocks.remove(self.SelectedElement)
+        self.Elements.remove(self.SelectedElement)
+        self.Controler.RemoveCurrentElementEditingInstance(connection.GetId())
+        for wire in wires:
+            wire.RefreshModel()
+        self.Parent.RefreshProjectTree()
+
+    def DeleteComment(self, comment):
+        self.Elements.remove(self.SelectedElement)
+        self.Controler.RemoveCurrentElementEditingInstance(comment.GetId())
+
+    def DeleteWire(self, wire):
+        connected = wire.GetConnected()
+        self.SelectedElement.Clean()
+        self.Wires.remove(self.SelectedElement)
+        self.Elements.remove(self.SelectedElement)
+        for connector in connected:
+            connector.RefreshParentBlock()
+
+#-------------------------------------------------------------------------------
+#                          Create New Block Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_BLOCKPROPERTIESDIALOG, wxID_BLOCKPROPERTIESDIALOGMAINPANEL, 
+ wxID_BLOCKPROPERTIESDIALOGNAME, wxID_BLOCKPROPERTIESDIALOGTYPETREE, 
+ wxID_BLOCKPROPERTIESDIALOGTYPEDESC, wxID_BLOCKPROPERTIESDIALOGINPUTS, 
+ wxID_BLOCKPROPERTIESDIALOGPREVIEW, wxID_BLOCKPROPERTIESDIALOGSTATICTEXT1, 
+ wxID_BLOCKPROPERTIESDIALOGSTATICTEXT2, wxID_BLOCKPROPERTIESDIALOGSTATICTEXT3, 
+ wxID_BLOCKPROPERTIESDIALOGSTATICTEXT4, 
+] = [wx.NewId() for _init_ctrls in range(11)]
+
+class BlockPropertiesDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_BLOCKPROPERTIESDIALOG,
+              name='BlockPropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(600, 360), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Block Properties')
+        self.SetClientSize(wx.Size(600, 360))
+
+        self.MainPanel = wx.Panel(id=wxID_BLOCKPROPERTIESDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(600, 320), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticbox1 = wx.StaticBox(id=wxID_BLOCKPROPERTIESDIALOGSTATICTEXT1,
+              label='Type:', name='staticBox1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(245, 280), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_BLOCKPROPERTIESDIALOGSTATICTEXT2,
+              label='Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(274, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_BLOCKPROPERTIESDIALOGSTATICTEXT2,
+              label='Inputs:', name='staticText4', parent=self.MainPanel,
+              pos=wx.Point(424, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText4 = wx.StaticText(id=wxID_BLOCKPROPERTIESDIALOGSTATICTEXT4,
+              label='Preview:', name='staticText4', parent=self.MainPanel,
+              pos=wx.Point(274, 80), size=wx.Size(100, 17), style=0)
+
+        self.TypeTree = wx.TreeCtrl(id=wxID_BLOCKPROPERTIESDIALOGTYPETREE,
+              name='TypeTree', parent=self.MainPanel, pos=wx.Point(34, 44),
+              size=wx.Size(225, 180), style=wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_SINGLE|wx.SUNKEN_BORDER)
+        EVT_TREE_SEL_CHANGED(self, wxID_BLOCKPROPERTIESDIALOGTYPETREE, self.OnTypeTreeItemSelected)
+
+        self.TypeDesc = wx.TextCtrl(id=wxID_BLOCKPROPERTIESDIALOGTYPEDESC,
+              name='TypeDesc', parent=self.MainPanel, pos=wx.Point(34, 230),
+              size=wx.Size(225, 65), style=wx.TE_READONLY|wx.TE_MULTILINE)
+
+        self.Name = wx.TextCtrl(id=wxID_BLOCKPROPERTIESDIALOGNAME, value='',
+              name='Name', parent=self.MainPanel, pos=wx.Point(274, 48),
+              size=wx.Size(145, 24), style=0)
+        EVT_TEXT(self, wxID_BLOCKPROPERTIESDIALOGNAME, self.OnNameChanged)
+
+        self.Inputs = wx.SpinCtrl(id=wxID_BLOCKPROPERTIESDIALOGINPUTS,
+              name='Inputs', parent=self.MainPanel, pos=wx.Point(424, 48),
+              size=wx.Size(145, 24), style=0, min=2, max=20)
+        EVT_SPINCTRL(self, wxID_BLOCKPROPERTIESDIALOGINPUTS, self.OnInputsChanged)
+
+        self.Preview = wx.Panel(id=wxID_BLOCKPROPERTIESDIALOGPREVIEW,
+              name='Preview', parent=self.MainPanel, pos=wx.Point(274, 104),
+              size=wx.Size(300, 200), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
+        self.Preview.SetBackgroundColour(wxColour(255,255,255))
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        self.Name.SetValue("")
+        self.Name.Enable(False)
+        self.Inputs.Enable(False)
+        self.Block = None
+        self.MinBlockSize = None
+        
+        EVT_PAINT(self, self.OnPaint)
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        selected = self.TypeTree.GetSelection()
+        if not selected.IsOk() or self.TypeTree.GetItemParent(selected) == self.TypeTree.GetRootItem() or selected == self.TypeTree.GetRootItem():
+            message = wxMessageDialog(self, "Form isn't complete. Valid block type must be selected!", "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif self.Name.IsEnabled() and self.Name.GetValue() == "":
+            message = wxMessageDialog(self, "Form isn't complete. Name must be filled!", "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def SetBlockList(self, blocktypes):
+        root = self.TypeTree.AddRoot("")
+        for category in blocktypes:
+            category_item = self.TypeTree.AppendItem(root, category["name"])
+            for blocktype in category["list"]:
+                blocktype_item = self.TypeTree.AppendItem(category_item, blocktype["name"])
+
+    def SetMinBlockSize(self, size):
+        self.MinBlockSize = size
+
+    def GetValues(self):
+        values = {}
+        values["type"] = self.TypeTree.GetItemText(self.TypeTree.GetSelection())
+        if self.Name.GetValue() != "":
+            values["name"] = self.Name.GetValue()
+        values["width"], values["height"] = self.Block.GetSize()
+        values["extension"] = self.Inputs.GetValue()
+        return values
+
+    def OnTypeTreeItemSelected(self, event):
+        self.Name.SetValue("")
+        selected = event.GetItem()
+        if self.TypeTree.GetItemParent(selected) != self.TypeTree.GetRootItem():
+            blocktype = GetBlockType(self.TypeTree.GetItemText(selected))
+            if blocktype:
+                self.Inputs.SetValue(len(blocktype["inputs"]))
+                self.Inputs.Enable(blocktype["extensible"])
+                self.Name.Enable(blocktype["type"] != "function")
+                self.TypeDesc.SetValue(blocktype["comment"])
+                wxCallAfter(self.RefreshPreview)
+            else:
+                self.Name.Enable(False)
+                self.Inputs.Enable(False)
+                self.Inputs.SetValue(2)
+                self.TypeDesc.SetValue("")
+                wxCallAfter(self.ErasePreview)
+        else:
+            self.Name.Enable(False)
+            self.Inputs.Enable(False)
+            self.Inputs.SetValue(2)
+            self.TypeDesc.SetValue("")
+            wxCallAfter(self.ErasePreview)
+        event.Skip()
+
+    def OnNameChanged(self, event):
+        if self.Name.IsEnabled():
+            self.RefreshPreview()
+        event.Skip()
+    
+    def OnInputsChanged(self, event):
+        if self.Inputs.IsEnabled():
+            self.RefreshPreview()
+        event.Skip()
+    
+    def ErasePreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        self.Block = None
+        
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        blocktype = self.TypeTree.GetItemText(self.TypeTree.GetSelection())
+        self.Block = FBD_Block(self.Preview, blocktype, self.Name.GetValue(), extension = self.Inputs.GetValue())
+        width, height = self.MinBlockSize
+        min_width, min_height = self.Block.GetMinSize()
+        width, height = max(min_width, width), max(min_height, height)
+        self.Block.SetSize(width, height)
+        clientsize = self.Preview.GetClientSize()
+        x = (clientsize.width - width) / 2
+        y = (clientsize.height - height) / 2
+        self.Block.SetPosition(x, y)
+        self.Block.Draw(dc)
+
+    def OnPaint(self, event):
+        if self.Block:
+            self.RefreshPreview()
+        else:
+            self.ErasePreview()
+
+
+#-------------------------------------------------------------------------------
+#                          Create New Variable Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_VARIABLEPROPERTIESDIALOG, wxID_VARIABLEPROPERTIESDIALOGMAINPANEL, 
+ wxID_VARIABLEPROPERTIESDIALOGNAME, wxID_VARIABLEPROPERTIESDIALOGCLASS, 
+ wxID_VARIABLEPROPERTIESDIALOGPREVIEW, wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT1,
+ wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT2, wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+class VariablePropertiesDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_VARIABLEPROPERTIESDIALOG,
+              name='VariablePropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(400, 320), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Variable Properties')
+        self.SetClientSize(wx.Size(400, 320))
+
+        self.MainPanel = wx.Panel(id=wxID_VARIABLEPROPERTIESDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(400, 280), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT1,
+              label='Class:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT2,
+              label='Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(204, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_VARIABLEPROPERTIESDIALOGSTATICTEXT3,
+              label='Preview:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 72), size=wx.Size(100, 17), style=0)
+
+        self.Class = wx.Choice(id=wxID_VARIABLEPROPERTIESDIALOGCLASS,
+              name='Class', parent=self.MainPanel, pos=wx.Point(24, 48),
+              size=wx.Size(145, 24), style=0)
+        EVT_CHOICE(self, wxID_VARIABLEPROPERTIESDIALOGCLASS, self.OnClassChanged)
+        
+        self.Name = wx.Choice(id=wxID_VARIABLEPROPERTIESDIALOGNAME,
+              name='Name', parent=self.MainPanel, pos=wx.Point(204, 48),
+              size=wx.Size(145, 24), style=0)
+        EVT_CHOICE(self, wxID_VARIABLEPROPERTIESDIALOGNAME, self.OnNameChanged)
+
+        self.Preview = wx.Panel(id=wxID_VARIABLEPROPERTIESDIALOGPREVIEW,
+              name='Preview', parent=self.MainPanel, pos=wx.Point(24, 104),
+              size=wx.Size(350, 150), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
+        self.Preview.SetBackgroundColour(wxColour(255,255,255))
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        self.Variable = None
+        self.VarList = []
+        self.MinVariableSize = None
+        self.RefreshNameList()
+        
+        for choice in ["Input", "Output", "InOut"]:
+            self.Class.Append(choice)
+        self.Class.SetStringSelection("Input")
+        
+        EVT_PAINT(self, self.OnPaint)
+
+    def RefreshNameList(self):
+        selected = self.Name.GetStringSelection()
+        self.Name.Clear()
+        for name, var_type, value_type in self.VarList:
+            if var_type in ["Local","Temp","Output","InOut"]:
+                self.Name.Append(name)
+            elif var_type == "Input" and self.Class.GetStringSelection() == "Input":
+                self.Name.Append(name)
+        if self.Name.FindString(selected) != wxNOT_FOUND:
+            self.Name.SetStringSelection(selected)
+        self.Name.Enable(self.Name.GetCount() > 0)
+            
+    def SetMinVariableSize(self, size):
+        self.MinVariableSize = size
+
+    def SetVariables(self, vars):
+        self.VarList = vars
+        self.RefreshNameList()
+        
+    def GetValues(self):
+        values = {}
+        classtype = self.Class.GetStringSelection()
+        if classtype == "Input":
+            values["type"] = INPUT
+        elif classtype == "Output":
+            values["type"] = OUTPUT
+        elif classtype == "InOut":
+            values["type"] = INOUT
+        values["name"] = self.Name.GetStringSelection()
+        values["value_type"] = ""
+        for var_name, var_type, value_type in self.VarList:
+            if var_name == values["name"]:
+                values["value_type"] = value_type
+        values["width"], values["height"] = self.Variable.GetSize()
+        return values
+
+    def OnClassChanged(self, event):
+        self.RefreshNameList()
+        self.RefreshPreview()
+        event.Skip()
+
+    def OnNameChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+        
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        name = self.Name.GetStringSelection()
+        type = ""
+        for var_name, var_type, value_type in self.VarList:
+            if var_name == name:
+                type = value_type
+        classtype = self.Class.GetStringSelection()
+        if classtype == "Input":
+            self.Variable = FBD_Variable(self.Preview, INPUT, name, type)
+        elif classtype == "Output":
+            self.Variable = FBD_Variable(self.Preview, OUTPUT, name, type)
+        elif classtype == "InOut":
+            self.Variable = FBD_Variable(self.Preview, INOUT, name, type)
+        width, height = self.MinVariableSize
+        min_width, min_height = self.Variable.GetMinSize()
+        width, height = max(min_width, width), max(min_height, height)
+        self.Variable.SetSize(width, height)
+        clientsize = self.Preview.GetClientSize()
+        x = (clientsize.width - width) / 2
+        y = (clientsize.height - height) / 2
+        self.Variable.SetPosition(x, y)
+        self.Variable.Draw(dc)
+
+    def OnPaint(self, event):
+        self.RefreshPreview()
+
+#-------------------------------------------------------------------------------
+#                          Create New Connection Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_CONNECTIONPROPERTIESDIALOG, wxID_CONNECTIONPROPERTIESDIALOGMAINPANEL, 
+ wxID_CONNECTIONPROPERTIESDIALOGNAME, wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON1, 
+ wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON2, wxID_CONNECTIONPROPERTIESDIALOGPREVIEW,
+ wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT1, wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT2, 
+ wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(9)]
+
+class ConnectionPropertiesDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_CONNECTIONPROPERTIESDIALOG,
+              name='ConnectionPropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(350, 220), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Connection Properties')
+        self.SetClientSize(wx.Size(350, 220))
+
+        self.MainPanel = wx.Panel(id=wxID_CONNECTIONPROPERTIESDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(340, 360), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT1,
+              label='Type:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT2,
+              label='Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 104), size=wx.Size(70, 17), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_CONNECTIONPROPERTIESDIALOGSTATICTEXT3,
+              label='Preview:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(174, 24), size=wx.Size(100, 17), style=0)
+
+        self.radioButton1 = wx.RadioButton(id=wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON1,
+              label='Connector', name='radioButton1', parent=self.MainPanel,
+              pos=wx.Point(24, 48), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON1, self.OnTypeChanged)
+        self.radioButton1.SetValue(True)
+
+        self.radioButton2 = wx.RadioButton(id=wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON2,
+              label='Continuation', name='radioButton2', parent=self.MainPanel, 
+              pos=wx.Point(24, 72), size=wx.Size(128, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_CONNECTIONPROPERTIESDIALOGRADIOBUTTON2, self.OnTypeChanged)
+        self.radioButton2.SetValue(False)
+        
+        self.Name = wx.TextCtrl(id=wxID_CONNECTIONPROPERTIESDIALOGNAME,
+              name='Name', parent=self.MainPanel, pos=wx.Point(24, 130),
+              size=wx.Size(145, 24), style=0)
+        EVT_TEXT(self, wxID_CONNECTIONPROPERTIESDIALOGNAME, self.OnNameChanged)
+
+        self.Preview = wx.Panel(id=wxID_CONNECTIONPROPERTIESDIALOGPREVIEW,
+              name='Preview', parent=self.MainPanel, pos=wx.Point(174, 48),
+              size=wx.Size(150, 100), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
+        self.Preview.SetBackgroundColour(wxColour(255,255,255))
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        self.Connection = None
+        self.MinConnectionSize = None
+        
+        EVT_PAINT(self, self.OnPaint)
+            
+    def SetMinConnectionSize(self, size):
+        self.MinConnectionSize = size
+        
+    def GetValues(self):
+        values = {}
+        if self.radioButton1.GetValue():
+            values["type"] = CONNECTOR
+        else:
+            values["type"] = CONTINUATION
+        values["name"] = self.Name.GetValue()
+        values["width"], values["height"] = self.Connection.GetSize()
+        return values
+
+    def OnTypeChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+
+    def OnNameChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+        
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        if self.radioButton1.GetValue():
+            self.Connection = FBD_Connector(self.Preview, CONNECTOR, self.Name.GetValue())
+        else:
+            self.Connection = FBD_Connector(self.Preview, CONTINUATION, self.Name.GetValue())
+        width, height = self.MinConnectionSize
+        min_width, min_height = self.Connection.GetMinSize()
+        width, height = max(min_width, width), max(min_height, height)
+        self.Connection.SetSize(width, height)
+        clientsize = self.Preview.GetClientSize()
+        x = (clientsize.width - width) / 2
+        y = (clientsize.height - height) / 2
+        self.Connection.SetPosition(x, y)
+        self.Connection.Draw(dc)
+
+    def OnPaint(self, event):
+        self.RefreshPreview()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GenerateProgram.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,35 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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
+
+
+"""
+Class implementing a generator for PLC program code
+"""
+
+class PLCGenerator:
+    
+    # Create a rubberband by indicated on which window it must be drawn
+    def __init__(self, controler):
+        self.drawingSurface = drawingSurface
+        self.Reset()
Binary file Images/action.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/action.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/action.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="action.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="16.854076"
+     inkscape:cy="12.933704"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 4,4 L 4,8 L 0,8 L 0,9 L 4,9 L 4,21 L 25,21 L 25,4 L 4,4 z M 5,5 L 10,5 L 10,12 L 5,12 L 5,5 z M 11,5 L 24,5 L 24,12 L 11,12 L 11,5 z M 5,13 L 10,13 L 10,20 L 5,20 L 5,13 z M 11,13 L 24,13 L 24,20 L 11,20 L 11,13 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccccccccccccccccccccccc" />
+    <text
+       xml:space="preserve"
+       style="font-size:5.20967913px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="12.412927"
+       y="9.6663799"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(0.966637,1.034515)"><tspan
+         sodipodi:role="line"
+         x="12.412927"
+         y="9.6663799"
+         id="tspan1952">ACT</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:5.0195241px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="6.0979509"
+       y="9.1481276"
+       id="text2015"
+       sodipodi:linespacing="125%"
+       transform="scale(0.914812,1.09312)"><tspan
+         sodipodi:role="line"
+         x="6.0979509"
+         y="9.1481276"
+         id="tspan2017">N</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:5.25197268px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="5.6648521"
+       y="17.801041"
+       id="text2019"
+       sodipodi:linespacing="125%"
+       transform="scale(0.993078,1.006971)"><tspan
+         sodipodi:role="line"
+         x="5.6648521"
+         y="17.801041"
+         id="tspan2023">S</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:5.12588978px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="12.846559"
+       y="16.815546"
+       id="text2027"
+       sodipodi:linespacing="125%"
+       transform="scale(0.934197,1.070438)"><tspan
+         sodipodi:role="line"
+         x="12.846559"
+         y="16.815546"
+         id="tspan2029">VAR</tspan></text>
+  </g>
+</svg>
Binary file Images/block.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/block.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/home/laurent/workspace/PLCEditor/Images/block.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/home/laurent/workspace/PLCEditor/Images"
+   sodipodi:docname="block.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="14.549819"
+     inkscape:cy="12.988169"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="17"
+       height="23"
+       x="4"
+       y="1" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 4,1 L 4,8 L 0,8 L 0,9 L 4,9 L 4,14 L 0,14 L 0,15 L 4,15 L 4,20 L 0,20 L 0,21 L 4,21 L 4,24 L 21,24 L 21,15 L 25,15 L 25,14 L 21,14 L 21,9 L 25,9 L 25,8 L 21,8 L 21,1 L 4,1 z M 5,2 L 20,2 L 20,23 L 5,23 L 5,2 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.94388533px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="7.2859559"
+       y="8.0773582"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(1.00967,0.990423)"><tspan
+         sodipodi:role="line"
+         id="tspan6443"
+         x="7.2859559"
+         y="8.0773582">FB</tspan></text>
+  </g>
+</svg>
Binary file Images/branch.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/branch.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/branch.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="branch.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="11.706522"
+     inkscape:cy="11.723796"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 16,4 L 16,13 L 17,13 L 17,9 L 19,9 L 19,8 L 17,8 L 17,4 L 16,4 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 9,4 L 9,13 L 8,13 L 8,9 L 6,9 L 6,8 L 8,8 L 8,4 L 9,4 z "
+       id="path1964"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 0,8 L 2,8 L 2,9 L 0,9 L 0,8 z "
+       id="rect3364" />
+    <path
+       style="color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 3,8 L 5,8 L 5,9 L 3,9 L 3,8 z "
+       id="path4252" />
+    <path
+       style="color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 20,8 L 22,8 L 22,9 L 20,9 L 20,8 z "
+       id="path4254" />
+    <path
+       style="color:black;fill:#999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23,8 L 25,8 L 25,9 L 23,9 L 23,8 z "
+       id="path4256" />
+    <path
+       style="color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 3,9 L 4,9 L 4,20 L 21,20 L 21,9 L 22,9 L 22,21 L 3,21 L 3,9 z "
+       id="path4258"
+       sodipodi:nodetypes="ccccccccc" />
+  </g>
+</svg>
Binary file Images/coil.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/coil.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/coil.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="coil.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8284271"
+     inkscape:cx="11.347815"
+     inkscape:cy="11.723796"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 0,9 L 0,22 L 2,22 L 2,16 L 6,16 L 6,15 L 2,15 L 2,9 L 0,9 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.87738276px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="4.5849652"
+       y="7.013639"
+       id="text6441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7478"
+         x="4.5849652"
+         y="7.013639">VAR</tspan></text>
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 25,9 L 25,22 L 23,22 L 23,16 L 19,16 L 19,15 L 23,15 L 23,9 L 25,9 z "
+       id="path1964"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.84852809;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path1984"
+       sodipodi:cx="7.25"
+       sodipodi:cy="16.5"
+       sodipodi:rx="2.25"
+       sodipodi:ry="4.5"
+       d="M 5.5467128,19.440281 A 2.25,4.5 0 0 1 5.5410496,13.572893"
+       transform="matrix(3.333333,0,0,1.666667,-10.63542,-12)"
+       sodipodi:start="2.4295312"
+       sodipodi:end="3.8497933"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.84852809;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path2879"
+       sodipodi:cx="7.25"
+       sodipodi:cy="16.5"
+       sodipodi:rx="2.25"
+       sodipodi:ry="4.5"
+       d="M 5.5467128,19.440281 A 2.25,4.5 0 0 1 5.5410496,13.572893"
+       transform="matrix(-3.333333,0,0,1.666667,35.63541,-12)"
+       sodipodi:start="2.4295312"
+       sodipodi:end="3.8497933"
+       sodipodi:open="true" />
+  </g>
+</svg>
Binary file Images/comment.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/comment.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/comment.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="comment.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="14.549819"
+     inkscape:cy="12.988169"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="25"
+       height="17"
+       x="0"
+       y="4" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 0,4 L 0,21 L 25,21 L 25,4 L 0,4 z M 1,5 L 24,5 L 24,20 L 1,20 L 1,5 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.97013044px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="3.5190985"
+       y="12.316453"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(1.034596,0.966561)"><tspan
+         sodipodi:role="line"
+         x="3.5190985"
+         y="12.316453"
+         id="tspan1988">CMT</tspan></text>
+    <rect
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect1996"
+       width="1"
+       height="1"
+       x="8"
+       y="16" />
+    <rect
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect1998"
+       width="1"
+       height="1"
+       x="12"
+       y="16" />
+    <rect
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect2000"
+       width="1"
+       height="1"
+       x="16"
+       y="16" />
+  </g>
+</svg>
Binary file Images/connection.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/connection.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCEditor/Images/connection.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCEditor/Images"
+   sodipodi:docname="connection.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="14.549819"
+     inkscape:cy="12.988169"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="false"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="21"
+       height="13"
+       x="8.8817842e-16"
+       y="6" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 0,6 L 0,19 L 21,18.955806 L 21,12.955806 L 25,12.955806 L 25,11.955806 L 21,11.955806 L 21,5.955806 L 0,6 z M 1,7 L 20,6.955806 L 20,17.955806 L 1,18 L 1,7 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.87738276px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="8.3926907"
+       y="15.104307"
+       id="text6441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7478"
+         x="8.3926907"
+         y="15.104307">C</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 0.51386409,6.5268353 L 6.4523494,12.574524 L 0.48613591,18.513864"
+       id="path1949"
+       sodipodi:nodetypes="ccc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 14.527728,6.5129709 L 20.466214,12.56066 L 14.5,18.5"
+       id="path1951"
+       sodipodi:nodetypes="ccc" />
+  </g>
+</svg>
Binary file Images/contact.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/contact.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/contact.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="contact.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="11.711467"
+     inkscape:cy="11.723796"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 18,9 L 18,22 L 20,22 L 20,16 L 25,16 L 25,15 L 20,15 L 20,9 L 18,9 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.87738276px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="4.5849652"
+       y="7.013639"
+       id="text6441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7478"
+         x="4.5849652"
+         y="7.013639">VAR</tspan></text>
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 7,9 L 7,22 L 5,22 L 5,16 L 0,16 L 0,15 L 5,15 L 5,9 L 7,9 z "
+       id="path1964"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+  </g>
+</svg>
Binary file Images/divergence.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/divergence.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/divergence.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="divergence.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32.000001"
+     inkscape:cx="16.854076"
+     inkscape:cy="9.7985002"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23,5 L 13,5 L 13,1 L 12,1 L 12,5 L 2,5 L 2,11 L 3,11 L 3,7 L 8,7 L 8,11 L 9,11 L 9,7 L 16,7 L 16,11 L 17,11 L 17,7 L 22,7 L 22,11 L 23,11 L 23,5 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 25,19 L 0,19 L 0,20 L 2,20 L 2,24 L 3,24 L 3,20 L 8,20 L 8,24 L 9,24 L 9,20 L 16,20 L 16,24 L 17,24 L 17,20 L 22,20 L 22,24 L 23,24 L 23,20 L 25,20 L 25,19 z "
+       id="path1921"
+       sodipodi:nodetypes="ccccccccccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 25,17 L 13,17 L 13,13 L 12,13 L 12,17 L 0,17 L 0,18 L 25,18 L 25,17 z "
+       id="path1923"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+  </g>
+</svg>
Binary file Images/initial_step.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/initial_step.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/initial_step.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="initial_step.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="16.854076"
+     inkscape:cy="12.933704"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="23"
+       height="18"
+       x="1"
+       y="2" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 25,1 L 0,1 L 0,21 L 12,21 L 12,25 L 13,25 L 13,21 L 25,21 L 25,1 z M 24,2 L 24,20 L 1,20 L 1,2 L 24,2 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:5.06193972px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="3.8652179"
+       y="12.22568"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(0.945951,1.057138)"><tspan
+         sodipodi:role="line"
+         id="tspan7478"
+         x="3.8652179"
+         y="12.22568">START</tspan></text>
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23,3 L 2,3 L 2,19 L 23,19 L 23,3 z M 22,4 L 22,18 L 3,18 L 3,4 L 22,4 z "
+       id="path1932"
+       sodipodi:nodetypes="cccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+  </g>
+</svg>
Binary file Images/jump.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/jump.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/jump.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="jump.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="14.549819"
+     inkscape:cy="12.988169"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <text
+       xml:space="preserve"
+       style="font-size:6.94388819px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="14.255835"
+       y="15.189672"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(1.00967,0.990423)"><tspan
+         sodipodi:role="line"
+         id="tspan6443"
+         x="14.255835"
+         y="15.189672">JP</tspan></text>
+    <path
+       style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 8,4 L 8,11 L 3,8 L 8.5606601,20 L 14,8 L 9,11 L 9,4 L 8,4 z "
+       id="path1941"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
Binary file Images/select.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/select.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/home/laurent/workspace/PLCEditor/Images/select.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/home/laurent/workspace/PLCEditor/Images"
+   sodipodi:docname="select.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient4588">
+      <stop
+         style="stop-color:#494949;stop-opacity:1;"
+         offset="0"
+         id="stop4590" />
+      <stop
+         style="stop-color:#262626;stop-opacity:0;"
+         offset="1"
+         id="stop4592" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4588"
+       id="radialGradient4594"
+       cx="15"
+       cy="16.40625"
+       fx="15"
+       fy="16.40625"
+       r="12.5625"
+       gradientTransform="matrix(0.93933,2.771444e-7,-2.74398e-7,0.930021,-2.994365,-0.94731)"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="11.313709"
+     inkscape:cx="8"
+     inkscape:cy="14.740814"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1.64947593px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 2.6283661,2.4679989 L 7.2706314,20.013812 L 10.667852,13.66663 L 19.21384,22.248439 L 22.408805,18.700948 L 13.827648,10.431836 L 20.775403,7.2626952 L 2.6283661,2.4679989 z "
+       id="path1872"
+       sodipodi:nodetypes="cccccccc" />
+  </g>
+</svg>
Binary file Images/step.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/step.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/step.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="step.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="16.854076"
+     inkscape:cy="12.933704"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="17"
+       height="15"
+       x="3"
+       y="5" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 21,4 L 12,4 L 12,0 L 11,0 L 11,4 L 2,4 L 2,21 L 11,21 L 11,25 L 12,25 L 12,21 L 21,21 L 21,13 L 25,13 L 25,12 L 21,12 L 21,4 z M 20,5 L 20,20 L 3,20 L 3,5 L 20,5 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:5.08002424px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="4.9849925"
+       y="13.696054"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(0.942584,1.060914)"><tspan
+         sodipodi:role="line"
+         x="4.9849925"
+         y="13.696054"
+         id="tspan1952">STEP</tspan></text>
+  </g>
+</svg>
Binary file Images/transition.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/transition.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/transition.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images"
+   sodipodi:docname="transition.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32.000001"
+     inkscape:cx="16.854076"
+     inkscape:cy="12.933704"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 15,11 L 8,11 L 8,7 L 7,7 L 7,11 L 0,11 L 0,14 L 7,14 L 7,18 L 8,18 L 8,14 L 15,14 L 15,13 L 19,13 L 19,12 L 15,12 L 15,11 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:8.45267963px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="22.675333"
+       y="14.086612"
+       id="text6441"
+       sodipodi:linespacing="125%"
+       transform="scale(0.880413,1.13583)"><tspan
+         sodipodi:role="line"
+         x="22.675333"
+         y="14.086612"
+         id="tspan1952">T</tspan></text>
+  </g>
+</svg>
Binary file Images/variable.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/variable.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/home/laurent/workspace/PLCEditor/Images/variable.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/home/laurent/workspace/PLCEditor/Images"
+   sodipodi:docname="variable.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627417"
+     inkscape:cx="14.549819"
+     inkscape:cy="12.988169"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect6341"
+       width="21"
+       height="13"
+       x="8.8817842e-16"
+       y="6" />
+    <path
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 0,6 L 0,19 L 21,18.955806 L 21,12.955806 L 25,12.955806 L 25,11.955806 L 21,11.955806 L 21,5.955806 L 0,6 z M 1,7 L 20,6.955806 L 20,17.955806 L 1,18 L 1,7 z "
+       id="rect4559"
+       sodipodi:nodetypes="cccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <text
+       xml:space="preserve"
+       style="font-size:6.87738276px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="2.2035112"
+       y="15.013638"
+       id="text6441"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7478"
+         x="2.2035112"
+         y="15.013638">VAR</tspan></text>
+  </g>
+</svg>
Binary file Images/wire.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/wire.svg	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="25"
+   height="25"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.44"
+   version="1.0"
+   inkscape:export-filename="/home/laurent/workspace/PLCEditor/Images/connection.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/home/laurent/workspace/PLCEditor/Images"
+   sodipodi:docname="connection.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="18.31884"
+     inkscape:cy="19.407604"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="25px"
+     height="25px"
+     showgrid="true"
+     inkscape:grid-points="true"
+     inkscape:window-width="1272"
+     inkscape:window-height="960"
+     inkscape:window-x="0"
+     inkscape:window-y="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path7255"
+       sodipodi:cx="2"
+       sodipodi:cy="2"
+       sodipodi:rx="2"
+       sodipodi:ry="2"
+       d="M 4 2 A 2 2 0 1 1  0,2 A 2 2 0 1 1  4 2 z"
+       transform="matrix(1.25,0,0,1.265625,0,9.9375)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;color:black;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path8146"
+       sodipodi:cx="2"
+       sodipodi:cy="2"
+       sodipodi:rx="2"
+       sodipodi:ry="2"
+       d="M 4 2 A 2 2 0 1 1  0,2 A 2 2 0 1 1  4 2 z"
+       transform="matrix(1.25,0,0,1.25,20,20)" />
+    <path
+       style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 2,11 L 3,11 L 3,1 L 12,1 L 12,23 L 21,23.03125 L 21,22.03125 L 13,22 L 13,0 L 2,0 L 2,11 z "
+       id="path8148"
+       sodipodi:nodetypes="ccccccccccc" />
+  </g>
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LDViewer.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,1184 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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 wxPython.wx import *
+import wx
+from types import *
+
+from plcopen.structures import *
+from graphics.GraphicCommons import *
+from graphics.FBD_Objects import *
+from Viewer import *
+
+def ExtractNextBlocks(block, block_list):
+    current_list = [block]
+    while len(current_list) > 0:
+        next_list = []
+        for current in current_list:
+            connectors = current.GetConnectors()
+            input_connectors = []
+            if isinstance(current, LD_PowerRail) and current.GetType() == RIGHTRAIL:
+                input_connectors = connectors
+            else:
+                if "inputs" in connectors:
+                    input_connectors = connectors["inputs"]
+                if "input" in connectors:
+                    input_connectors = [connectors["input"]]
+            for connector in input_connectors:
+                for wire, handle in connector.GetWires():
+                    next = wire.EndConnected.GetParentBlock()
+                    if not isinstance(next, LD_PowerRail) and next not in block_list:
+                        block_list.append(next)
+                        next_list.append(next)
+        current_list = next_list
+    
+def CalcBranchSize(elements, stop):
+    branch_size = 0
+    stop_list = [stop]
+    ExtractNextBlocks(stop, stop_list)
+    element_tree = {}
+    for element in elements:
+        if element not in element_tree:
+            element_tree[element] = {"parents":["start"], "children":[], "weight":None}
+            GenerateTree(element, element_tree, stop_list)
+        elif element_tree[element]:
+            element_tree[element]["parents"].append("start")
+    for element, values in element_tree.items():
+        if values and values["children"] == ["stop"]:
+            CalcWeight(element, element_tree)
+            if values["weight"]:
+                branch_size += values["weight"]
+            else:
+                return 1
+    return branch_size
+
+def RemoveElement(remove, element_tree):
+    if remove in element_tree and element_tree[remove]:
+        for child in element_tree[remove]["children"]:
+            if child != "stop":
+                RemoveElement(child, element_tree)
+        element_tree[remove] = None
+
+def GenerateTree(element, element_tree, stop_list):
+    if element in element_tree:
+        connectors = element.GetConnectors()
+        input_connectors = []
+        if isinstance(element, LD_PowerRail) and element.GetType() == RIGHTRAIL:
+            input_connectors = connectors
+        else:
+            if "inputs" in connectors:
+                input_connectors = connectors["inputs"]
+            if "input" in connectors:
+                input_connectors = [connectors["input"]]
+        for connector in input_connectors:
+            for wire, handle in connector.GetWires():
+                next = wire.EndConnected.GetParentBlock()
+                if isinstance(next, LD_PowerRail) and next.GetType() == LEFTRAIL or next in stop_list:
+                    for remove in element_tree[element]["children"]:
+                        RemoveElement(remove, element_tree)
+                    element_tree[element]["children"] = ["stop"]
+                elif element_tree[element]["children"] == ["stop"]:
+                    element_tree[next] = None
+                elif next not in element_tree or element_tree[next]:
+                    element_tree[element]["children"].append(next)
+                    if next in element_tree:
+                        element_tree[next]["parents"].append(element)
+                    else:
+                        element_tree[next] = {"parents":[element], "children":[], "weight":None}
+                        GenerateTree(next, element_tree, stop_list)
+
+def CalcWeight(element, element_tree):
+    weight = 0
+    parts = None
+    if element in element_tree:
+        for parent in element_tree[element]["parents"]:
+            if parent == "start":
+                weight += 1
+            elif parent in element_tree:
+                if not parts:
+                    parts = len(element_tree[parent]["children"])
+                else:
+                    parts = min(parts, len(element_tree[parent]["children"]))
+                if not element_tree[parent]["weight"]:
+                    CalcWeight(parent, element_tree)
+                if element_tree[parent]["weight"]:
+                    weight += element_tree[parent]["weight"]
+                else:
+                    element_tree[element]["weight"] = None
+                    return
+            else:
+                element_tree[element]["weight"] = None
+                return
+        if not parts:
+            parts = 1
+        element_tree[element]["weight"] = max(1, weight / parts)
+
+
+#-------------------------------------------------------------------------------
+#                     Ladder Diagram Graphic elements Viewer class
+#-------------------------------------------------------------------------------
+
+"""
+Class derived from Viewer class that implements a Viewer of Ladder Diagram
+"""
+
+class LD_Viewer(Viewer):
+
+    def __init__(self, parent, window, controler):
+        Viewer.__init__(self, parent, window, controler)
+        self.Rungs = []
+        self.Comments = []
+
+#-------------------------------------------------------------------------------
+#                          Refresh functions
+#-------------------------------------------------------------------------------
+
+    def RefreshView(self):
+        Viewer.RefreshView(self)
+        for i, rung in enumerate(self.Rungs):
+            bbox = rung.GetBoundingBox()
+            if i < len(self.Comments):
+                pos = self.Comments[i].GetPosition()
+                if pos[1] > bbox.y:
+                    self.Comment.insert(i, None)
+            else:
+                self.Comment.insert(i, None)
+    
+    def loadInstance(self, instance, ids):
+        Viewer.loadInstance(self, instance, ids)
+        if instance["type"] == "leftPowerRail":
+            element = self.FindElementById(instance["id"])
+            rung = Graphic_Group(self)
+            rung.SelectElement(element)
+            self.Rungs.append(rung)
+        elif instance["type"] == "rightPowerRail":
+            rungs = []
+            for connector in instance["connectors"]:
+                for link in connector["links"]:
+                    connected = self.FindElementById(link["refLocalId"])
+                    rung = self.FindRung(connected)
+                    if rung not in rungs:
+                        rungs.append(rung)
+            if len(rungs) > 1:
+                raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"]
+            element = self.FindElementById(instance["id"])
+            self.Rungs[rungs[0]].SelectElement(element)
+            for connector in element.GetConnectors():
+                for wire, num in connector.GetWires():
+                    self.Rungs[rungs[0]].SelectElement(wire)
+            self.RefreshPosition(element)
+        elif instance["type"] in ["contact", "coil"]:
+            rungs = []
+            for link in instance["connectors"]["input"]["links"]:
+                connected = self.FindElementById(link["refLocalId"])
+                rung = self.FindRung(connected)
+                if rung not in rungs:
+                    rungs.append(rung)
+            if len(rungs) > 1:
+                raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"]
+            element = self.FindElementById(instance["id"])
+            self.Rungs[rungs[0]].SelectElement(element)
+            for wire, num in element.GetConnectors()["input"].GetWires():
+                self.Rungs[rungs[0]].SelectElement(wire)
+            self.RefreshPosition(element)
+        elif instance["type"] == "comment":
+            element = self.FindElementById(instance["id"])
+            pos = element.GetPosition()
+            i = 0
+            inserted = False
+            while i < len(self.Comments) and not inserted: 
+                ipos = self.Comments[i].GetPosition()
+                if pos[1] < ipos[1]:
+                    self.Comments.insert(i, element)
+                    inserted = True
+                i += 1
+            if not inserted:
+                self.Comments.append(element)
+
+#-------------------------------------------------------------------------------
+#                          Search Element functions
+#-------------------------------------------------------------------------------
+
+    def FindRung(self, element):
+        for i, rung in enumerate(self.Rungs):
+            if rung.IsElementIn(element):
+                return i
+        return None
+
+    def FindElement(self, pos):
+        elements = []
+        for element in self.Elements:
+            if element.HitTest(pos) or element.TestHandle(pos) != (0, 0):
+                elements.append(element)
+        if len(elements) == 1:
+            return elements[0]
+        elif len(elements) > 1:
+            group = Graphic_Group(self)
+            for element in elements:
+                if element in self.Blocks:
+                    return element
+                group.SelectElement(element)
+            return group
+        return None
+
+    def SearchElements(self, bbox):
+        elements = []
+        for element in self.Blocks:
+            element_bbox = element.GetBoundingBox()
+            if element_bbox.x >= bbox.x and element_bbox.y >= bbox.y and element_bbox.x + element_bbox.width <= bbox.x + bbox.width and element_bbox.y + element_bbox.height <= bbox.y + bbox.height:
+                elements.append(element)
+        return elements
+
+#-------------------------------------------------------------------------------
+#                          Mouse event functions
+#-------------------------------------------------------------------------------
+
+    def OnViewerLeftDown(self, event):
+        if self.Mode == MODE_SELECTION:
+            pos = event.GetPosition()
+            element = self.FindElement(pos)
+            if self.SelectedElement:
+                if self.SelectedElement in self.Elements:
+                    if self.SelectedElement != element:
+                        if self.SelectedElement in self.Wires:
+                            self.SelectedElement.SetSelectedSegment(None)
+                        else:
+                            self.SelectedElement.SetSelected(False)
+                    else:
+                        self.SelectedElement = None
+                elif element and element not in self.Elements:
+                    if self.SelectedElement.GetElements() != element.GetElements():
+                        for elt in self.SelectedElement.GetElements():
+                            if elt in self.Wires:
+                                elt.SetSelectedSegment(None)
+                        self.SelectedElement.SetSelected(False)
+                        self.SelectedElement = None
+                else:
+                    for elt in self.SelectedElement.GetElements():
+                        if elt in self.Wires:
+                            elt.SetSelectedSegment(None)
+                    self.SelectedElement.SetSelected(False)
+                    self.SelectedElement = None
+                self.Refresh()
+            if element:
+                self.SelectedElement = element
+                self.SelectedElement.OnLeftDown(event, self.Scaling)
+                self.Refresh()
+            else:
+                self.rubberBand.Reset()
+                self.rubberBand.OnLeftDown(event, self.Scaling)
+        event.Skip()
+
+    def OnViewerLeftUp(self, event):
+        if self.rubberBand.IsShown():
+            if self.Mode == MODE_SELECTION:
+                elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                if len(elements) > 0:
+                    self.SelectedElement = Graphic_Group(self)
+                    self.SelectedElement.SetElements(elements)
+                    self.SelectedElement.SetSelected(True)
+                    self.Refresh()
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            if self.SelectedElement in self.Elements:
+                if self.SelectedElement in self.Wires:
+                    result = self.SelectedElement.TestSegment(event.GetPosition(), True)
+                    if result and result[1] in [EAST, WEST]:
+                        self.SelectedElement.SetSelectedSegment(result[0])
+                else:
+                    self.SelectedElement.OnLeftUp(event, self.Scaling)
+            else:
+                for element in self.SelectedElement.GetElements():
+                    if element in self.Wires:
+                        result = element.TestSegment(event.GetPosition(), True)
+                        if result and result[1] in [EAST, WEST]:
+                            element.SetSelectedSegment(result[0])
+                    else:
+                        element.OnLeftUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        event.Skip()
+
+    def OnViewerRightUp(self, event):
+        pos = event.GetPosition()
+        element = self.FindElement(pos)
+        if element:
+            if self.SelectedElement and self.SelectedElement != element:
+                self.SelectedElement.SetSelected(False)
+            self.SelectedElement = element
+            if self.SelectedElement in self.Wires:
+                self.SelectedElement.SetSelectedSegment(0)
+            else:
+                self.SelectedElement.SetSelected(True)
+                self.SelectedElement.OnRightUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        event.Skip()
+
+    def OnViewerLeftDClick(self, event):
+        if self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftDClick(event, self.Scaling)
+            self.Refresh()
+        event.Skip()
+
+    def OnViewerMotion(self, event):
+        if self.rubberBand.IsShown():
+            self.rubberBand.OnMotion(event, self.Scaling)
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Keyboard event functions
+#-------------------------------------------------------------------------------
+
+    def OnChar(self, event):
+        keycode = event.GetKeyCode()
+        if keycode == WXK_DELETE and self.SelectedElement:
+            if self.SelectedElement in self.Blocks:
+                self.SelectedElement.Delete()
+            elif self.SelectedElement in self.Wires:
+                self.DeleteWire(self.SelectedElement)
+            elif self.SelectedElement not in self.Elements:
+                all_wires = True
+                for element in self.SelectedElement.GetElements():
+                    all_wires &= element in self.Wires
+                if all_wires:
+                    self.DeleteWire(self.SelectedElement)
+                else:
+                    self.SelectedElement.Delete()
+        self.Refresh()
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Adding element functions
+#-------------------------------------------------------------------------------
+
+    def AddRung(self):
+        dialog = LDElementDialog(self.Parent, "coil")
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                if var["Type"] != "Input" and var["Value"] == "BOOL":
+                    varlist.append(var["Name"])
+        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
+        if returntype == "BOOL":
+            varlist.append(self.Controler.GetCurrentElementEditingName())
+        dialog.SetVariables(varlist)
+        dialog.SetValues({"name":"","type":COIL_NORMAL})
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            startx, starty = LD_OFFSET[0], 0
+            if len(self.Rungs) > 0:
+                bbox = self.Rungs[-1].GetBoundingBox()
+                starty = bbox.y + bbox.height
+            starty += LD_OFFSET[1]
+            rung = Graphic_Group(self)
+            # Create comment
+            id = self.GetNewId()
+            comment = Comment(self, "Commentaire", id)
+            comment.SetPosition(startx, starty)
+            comment.SetSize(LD_COMMENT_DEFAULTSIZE[0], LD_COMMENT_DEFAULTSIZE[1])
+            self.Elements.append(comment)
+            self.Comments.append(comment)
+            self.Controler.AddCurrentElementEditingComment(id)
+            self.RefreshCommentModel(comment)
+            starty += LD_COMMENT_DEFAULTSIZE[1] + LD_OFFSET[1]
+            # Create LeftPowerRail
+            id = self.GetNewId()
+            leftpowerrail = LD_PowerRail(self, LEFTRAIL, id)
+            leftpowerrail.SetPosition(startx, starty)
+            self.Elements.append(leftpowerrail)
+            self.Blocks.append(leftpowerrail)
+            rung.SelectElement(leftpowerrail)
+            self.Controler.AddCurrentElementEditingPowerRail(id, LEFTRAIL)
+            self.RefreshPowerRailModel(leftpowerrail)
+            # Create Coil
+            id = self.GetNewId()
+            coil = LD_Coil(self, values["type"], values["name"], id)
+            coil.SetPosition(startx, starty + (LD_LINE_SIZE - LD_ELEMENT_SIZE[1]) / 2)
+            self.Elements.append(coil)
+            self.Blocks.append(coil)
+            rung.SelectElement(coil)
+            self.Controler.AddCurrentElementEditingCoil(id)
+            # Create Wire between LeftPowerRail and Coil
+            wire = Wire(self)
+            start_connector = coil.GetConnectors()["input"]
+            end_connector = leftpowerrail.GetConnectors()[0]
+            start_connector.Connect((wire, 0), False)
+            end_connector.Connect((wire, -1), False)
+            wire.ConnectStartPoint(None, start_connector)
+            wire.ConnectEndPoint(None, end_connector)
+            self.Wires.append(wire)
+            self.Elements.append(wire)
+            rung.SelectElement(wire)
+            # Create RightPowerRail
+            id = self.GetNewId()
+            rightpowerrail = LD_PowerRail(self, RIGHTRAIL, id)
+            rightpowerrail.SetPosition(startx, starty)
+            self.Elements.append(rightpowerrail)
+            self.Blocks.append(rightpowerrail)
+            rung.SelectElement(rightpowerrail)
+            self.Controler.AddCurrentElementEditingPowerRail(id, RIGHTRAIL)
+            # Create Wire between LeftPowerRail and Coil
+            wire = Wire(self)
+            start_connector = rightpowerrail.GetConnectors()[0]
+            end_connector = coil.GetConnectors()["output"]
+            start_connector.Connect((wire, 0), False)
+            end_connector.Connect((wire, -1), False)
+            wire.ConnectStartPoint(None, start_connector)
+            wire.ConnectEndPoint(None, end_connector)
+            self.Wires.append(wire)
+            self.Elements.append(wire)
+            rung.SelectElement(wire)
+            self.RefreshPosition(coil)
+            self.Rungs.append(rung)
+            self.Refresh()
+
+    def AddContact(self):
+        wires = []
+        if self.SelectedElement in self.Wires:
+            left_element = self.SelectedElement.EndConnected
+            if not isinstance(left_element.GetParentBlock(), LD_Coil):
+                wires.append(self.SelectedElement)
+        elif self.SelectedElement and self.SelectedElement not in self.Elements:
+            if False not in [element in self.Wires for element in self.SelectedElement.GetElements()]:
+                for element in self.SelectedElement.GetElements():
+                    wires.append(element)
+        if len(wires) > 0:
+            dialog = LDElementDialog(self.Parent, "contact")
+            varlist = []
+            vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+            if vars:
+                for var in vars:
+                    if var["Type"] != "Output" and var["Value"] == "BOOL":
+                        varlist.append(var["Name"])
+            dialog.SetVariables(varlist)
+            dialog.SetValues({"name":"","type":CONTACT_NORMAL})
+            if dialog.ShowModal() == wxID_OK:
+                values = dialog.GetValues()
+                points = wires[0].GetSelectedSegmentPoints()
+                id = self.GetNewId()
+                contact = LD_Contact(self, values["type"], values["name"], id)
+                contact.SetPosition(0, points[0].y - (LD_ELEMENT_SIZE[1] + 1) / 2)
+                self.Elements.append(contact)
+                self.Blocks.append(contact)
+                self.Controler.AddCurrentElementEditingContact(id)
+                rungindex = self.FindRung(wires[0])
+                rung = self.Rungs[rungindex]
+                old_bbox = rung.GetBoundingBox()
+                rung.SelectElement(contact)
+                connectors = contact.GetConnectors()
+                left_elements = []
+                right_elements = []
+                left_index = []
+                right_index = []
+                for wire in wires:
+                    if wire.EndConnected not in left_elements:
+                        left_elements.append(wire.EndConnected)
+                        left_index.append(wire.EndConnected.GetWireIndex(wire))
+                    else:
+                        idx = left_elements.index(wire.EndConnected)
+                        left_index[idx] = min(left_index[idx], wire.EndConnected.GetWireIndex(wire))
+                    if wire.StartConnected not in right_elements:
+                        right_elements.append(wire.StartConnected)
+                        right_index.append(wire.StartConnected.GetWireIndex(wire))
+                    else:
+                        idx = right_elements.index(wire.StartConnected)
+                        right_index[idx] = min(right_index[idx], wire.StartConnected.GetWireIndex(wire))
+                    wire.SetSelectedSegment(None)
+                    wire.Clean()
+                    rung.SelectElement(wire)
+                    self.Wires.remove(wire)
+                    self.Elements.remove(wire)
+                wires = []
+                right_wires = []
+                for i, left_element in enumerate(left_elements):
+                    wire = Wire(self)
+                    wires.append(wire)
+                    connectors["input"].Connect((wire, 0), False)
+                    left_element.InsertConnect(left_index[i], (wire, -1), False)
+                    wire.ConnectStartPoint(None, connectors["input"])
+                    wire.ConnectEndPoint(None, left_element)
+                for i, right_element in enumerate(right_elements):
+                    wire = Wire(self)
+                    wires.append(wire)
+                    right_wires.append(wire)
+                    right_element.InsertConnect(right_index[i], (wire, 0), False)
+                    connectors["output"].Connect((wire, -1), False)
+                    wire.ConnectStartPoint(None, right_element)
+                    wire.ConnectEndPoint(None, connectors["output"])
+                right_wires.reverse()
+                for wire in wires:
+                    self.Wires.append(wire)
+                    self.Elements.append(wire)
+                    rung.SelectElement(wire)
+                self.RefreshPosition(contact)
+                if len(right_wires) > 1:
+                    group = Graphic_Group(self)
+                    group.SetSelected(False)
+                    for wire in right_wires:
+                        wire.SetSelectedSegment(-1)
+                        group.SelectElement(wire)
+                    self.SelectedElement = group
+                else:
+                    right_wires[0].SetSelectedSegment(-1)
+                    self.SelectedElement = right_wires[0]
+                rung.RefreshBoundingBox()
+                new_bbox = rung.GetBoundingBox()
+                self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
+                self.Refresh()
+
+    def AddBranch(self):
+        blocks = []
+        if self.SelectedElement in self.Blocks:
+            blocks = [self.SelectedElement]
+        elif self.SelectedElement not in self.Elements:
+            elements = self.SelectedElement.GetElements()
+            for element in elements:
+                if isinstance(element, (LD_PowerRail, LD_Coil)):
+                    return
+                blocks.append(element)
+        if len(blocks) > 0:
+            blocks_infos = []
+            left_elements = []
+            left_index = []
+            right_elements = []
+            right_index = []
+            for block in blocks:
+                connectors = block.GetConnectors()
+                block_infos = {"inputs":[],"outputs":[],"lefts":[],"rights":[]}
+                if "inputs" in connectors:
+                    block_infos["inputs"] = connectors["inputs"]
+                if "outputs" in connectors:
+                    block_infos["outputs"] = connectors["outputs"]
+                if "input" in connectors:
+                    block_infos["inputs"] = [connectors["input"]]
+                if "output" in connectors:
+                    block_infos["outputs"] = [connectors["output"]]
+                for connector in block_infos["inputs"]:
+                    for wire, handle in connector.GetWires():
+                        found = False
+                        for infos in blocks_infos:
+                            if wire.EndConnected in infos["outputs"]:
+                                for left_element in infos["lefts"]:
+                                    if left_element not in block_infos["lefts"]:
+                                        block_infos["lefts"].append(left_element)
+                                found = True
+                        if not found and wire.EndConnected not in block_infos["lefts"]:
+                            block_infos["lefts"].append(wire.EndConnected)
+                            if wire.EndConnected not in left_elements:
+                                left_elements.append(wire.EndConnected)
+                                left_index.append(wire.EndConnected.GetWireIndex(wire))
+                            else:
+                                index = left_elements.index(wire.EndConnected)
+                                left_index[index] = max(left_index[index], wire.EndConnected.GetWireIndex(wire))
+                for connector in block_infos["outputs"]:
+                    for wire, handle in connector.GetWires():
+                        found = False
+                        for infos in blocks_infos:
+                            if wire.StartConnected in infos["inputs"]:
+                                for right_element in infos["rights"]:
+                                    if right_element not in block_infos["rights"]:
+                                        block_infos["rights"].append(right_element)
+                                found = True
+                        if not found and wire.StartConnected not in block_infos["rights"]:
+                            block_infos["rights"].append(wire.StartConnected)
+                            if wire.StartConnected not in right_elements:
+                                right_elements.append(wire.StartConnected)
+                                right_index.append(wire.StartConnected.GetWireIndex(wire))
+                            else:
+                                index = right_elements.index(wire.StartConnected)
+                                right_index[index] = max(right_index[index], wire.StartConnected.GetWireIndex(wire))
+                for connector in block_infos["inputs"]:
+                    for infos in blocks_infos:
+                        if connector in infos["rights"]:
+                            infos["rights"].remove(connector)
+                            if connector in right_elements:
+                                index = right_elements.index(connector)
+                                right_elements.pop(index)
+                                right_index.pop(index)
+                            for right_element in block_infos["rights"]:
+                                if right_element not in infos["rights"]:
+                                    infos["rights"].append(right_element)
+                for connector in block_infos["outputs"]:
+                    for infos in blocks_infos:
+                        if connector in infos["lefts"]:
+                            infos["lefts"].remove(connector)
+                            if connector in left_elements:
+                                index = left_elements.index(connector)
+                                left_elements.pop(index)
+                                left_index.pop(index)
+                            for left_element in block_infos["lefts"]:
+                                if left_element not in infos["lefts"]:
+                                    infos["lefts"].append(left_element)
+                blocks_infos.append(block_infos)
+            for infos in blocks_infos:
+                left_elements = [element for element in infos["lefts"]]
+                for left_element in left_elements:
+                    if isinstance(left_element.GetParentBlock(), LD_PowerRail):
+                        infos["lefts"].remove(left_element)
+                        if "LD_PowerRail" not in infos["lefts"]:
+                            infos["lefts"].append("LD_PowerRail")
+                right_elements = [element for element in infos["rights"]]
+                for right_element in right_elements:
+                    if isinstance(right_element.GetParentBlock(), LD_PowerRail):
+                        infos["rights"].remove(tight_element)
+                        if "LD_PowerRail" not in infos["rights"]:
+                            infos["rights"].append("LD_PowerRail")
+                infos["lefts"].sort()
+                infos["rights"].sort()
+            lefts = blocks_infos[0]["lefts"]
+            rights = blocks_infos[0]["rights"]
+            good = True
+            for infos in blocks_infos[1:]:
+                good &= infos["lefts"] == lefts
+                good &= infos["rights"] == rights
+            if good:
+                rungindex = self.FindRung(blocks[0])
+                rung = self.Rungs[rungindex]
+                old_bbox = rung.GetBoundingBox()
+                left_powerrail = True
+                right_powerrail = True
+                for element in left_elements:
+                    left_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail)
+                for element in right_elements:
+                    right_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail)
+                if not left_powerrail or not right_powerrail:
+                    if left_powerrail:
+                        powerrail = left_elements[0].GetParentBlock()
+                        index = 0
+                        for left_element in left_elements: 
+                            index = max(index, powerrail.GetConnectorIndex(left_element))
+                        if powerrail.IsNullConnector(index + 1):
+                            powerrail.DeleteConnector(index + 1)
+                        powerrail.InsertConnector(index + 1)
+                        powerrail.RefreshModel()
+                        connectors = powerrail.GetConnectors()
+                        for i, right_element in enumerate(right_elements):
+                            new_wire = Wire(self)
+                            right_element.InsertConnect(right_index[i] + 1, (new_wire, 0), False)
+                            connectors[index + 1].Connect((new_wire, -1), False)
+                            new_wire.ConnectStartPoint(None, right_element)
+                            new_wire.ConnectEndPoint(None, connectors[index + 1])
+                            self.Wires.append(new_wire)
+                            self.Elements.append(new_wire)
+                            rung.SelectElement(new_wire)
+                        right_elements.reverse()
+                    elif right_powerrail:
+                        pass
+                    else:
+                        left_elements.reverse()
+                        right_elements.reverse()
+                        wires = []
+                        for i, left_element in enumerate(left_elements):
+                            for j, right_element in enumerate(right_elements):
+                                exist = False
+                                for wire, handle in right_element.GetWires():
+                                    exist |= wire.EndConnected == left_element
+                                if not exist:
+                                    new_wire = Wire(self)
+                                    wires.append(new_wire)
+                                    right_element.InsertConnect(right_index[j] + 1, (new_wire, 0), False)
+                                    left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False)
+                                    new_wire.ConnectStartPoint(None, right_element)
+                                    new_wire.ConnectEndPoint(None, left_element)
+                        wires.reverse()
+                        for wire in wires:
+                            self.Wires.append(wire)
+                            self.Elements.append(wire)
+                            rung.SelectElement(wire)
+                        right_elements.reverse()
+                for block in blocks:
+                    self.RefreshPosition(block)
+                for right_element in right_elements:
+                    self.RefreshPosition(right_element.GetParentBlock())
+                self.SelectedElement.RefreshBoundingBox()
+                rung.RefreshBoundingBox()
+                new_bbox = rung.GetBoundingBox()
+                self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
+                self.Refresh()
+
+#-------------------------------------------------------------------------------
+#                          Delete element functions
+#-------------------------------------------------------------------------------
+
+    def DeleteContact(self, contact):
+        rungindex = self.FindRung(contact)
+        rung = self.Rungs[rungindex]
+        old_bbox = rung.GetBoundingBox()
+        connectors = contact.GetConnectors()
+        input_wires = [wire for wire, handle in connectors["input"].GetWires()]
+        output_wires = [wire for wire, handle in connectors["output"].GetWires()]
+        left_elements = [(wire.EndConnected, wire.EndConnected.GetWireIndex(wire)) for wire in input_wires]
+        right_elements = [(wire.StartConnected, wire.StartConnected.GetWireIndex(wire)) for wire in output_wires]
+        for wire in input_wires:
+            wire.Clean()
+            rung.SelectElement(wire)
+            self.Wires.remove(wire)
+            self.Elements.remove(wire)
+        for wire in output_wires:
+            wire.Clean()
+            rung.SelectElement(wire)
+            self.Wires.remove(wire)
+            self.Elements.remove(wire)
+        rung.SelectElement(contact)
+        contact.Clean()
+        left_elements.reverse()
+        right_elements.reverse()
+        powerrail = len(left_elements) == 1 and isinstance(left_elements[0][0].GetParentBlock(), LD_PowerRail)
+        for left_element, left_index in left_elements:
+            for right_element, right_index in right_elements:
+                wire_removed = []
+                for wire, handle in right_element.GetWires():
+                    if wire.EndConnected == left_element:
+                        wire_removed.append(wire)
+                    elif isinstance(wire.EndConnected.GetParentBlock(), LD_PowerRail) and powerrail:
+                        left_powerrail = wire.EndConnected.GetParentBlock()
+                        index = left_powerrail.GetConnectorIndex(wire.EndConnected)
+                        left_powerrail.DeleteConnector(index)
+                        wire_removed.append(wire)
+                for wire in wire_removed:
+                    wire.Clean()
+                    self.Wires.remove(wire)
+                    self.Elements.remove(wire)
+                    rung.SelectElement(wire)
+        wires = []
+        for left_element, left_index in left_elements:
+            for right_element, right_index in right_elements:
+                wire = Wire(self)
+                wires.append(wire)
+                right_element.InsertConnect(right_index, (wire, 0), False)
+                left_element.InsertConnect(left_index, (wire, -1), False)
+                wire.ConnectStartPoint(None, right_element)
+                wire.ConnectEndPoint(None, left_element)
+        wires.reverse()
+        for wire in wires:
+            self.Wires.append(wire)
+            self.Elements.append(wire)
+            rung.SelectElement(wire)
+        right_elements.reverse()
+        for right_element, right_index in right_elements:
+            self.RefreshPosition(right_element.GetParentBlock())
+        self.Blocks.remove(contact)
+        self.Elements.remove(contact)
+        self.Controler.RemoveCurrentElementEditingInstance(contact.GetId())
+        rung.RefreshBoundingBox()
+        new_bbox = rung.GetBoundingBox()
+        self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
+        self.SelectedElement = None
+
+    def DeleteCoil(self, coil):
+        rungindex = self.FindRung(coil)
+        rung = self.Rungs[rungindex]
+        bbox = rung.GetBoundingBox()
+        for element in rung.GetElements():
+            if element in self.Wires:
+                element.Clean()
+                self.Wires.remove(element)
+                self.Elements.remove(element)
+        for element in rung.GetElements():
+            if element in self.Blocks:
+                self.Controler.RemoveCurrentElementEditingInstance(element.GetId())
+                self.Blocks.remove(element)
+                self.Elements.remove(element)
+        self.Controler.RemoveCurrentElementEditingInstance(self.Comments[rungindex].GetId())
+        self.Elements.remove(self.Comments[rungindex])
+        self.Comments.pop(rungindex)
+        self.Rungs.pop(rungindex)
+        if rungindex < len(self.Rungs):
+            next_bbox = self.Rungs[rungindex].GetBoundingBox()
+            self.RefreshRungs(bbox.y - next_bbox.y, rungindex)
+        self.SelectedElement = None
+
+    def DeleteWire(self, wire):
+        wires = []
+        left_elements = []
+        right_elements = []
+        if wire in self.Wires:
+            wires = [wire]
+        elif wire not in self.Elements:
+            for element in wire.GetElements():
+                if element in self.Wires:
+                    wires.append(element)
+                else:
+                    wires = []
+                    break
+        if len(wires) > 0:
+            rungindex = self.FindRung(wires[0])
+            rung = self.Rungs[rungindex]
+            old_bbox = rung.GetBoundingBox()
+            for wire in wires:
+                connections = wire.GetSelectedSegmentConnections()
+                left_block = wire.EndConnected.GetParentBlock()
+                if wire.EndConnected not in left_elements:
+                    left_elements.append(wire.EndConnected)
+                if wire.StartConnected not in right_elements:
+                    right_elements.append(wire.StartConnected)
+                if connections == (False, False) or connections == (False, True) and isinstance(left_block, LD_PowerRail):
+                    wire.Clean()
+                    self.Wires.remove(wire)
+                    self.Elements.remove(wire)
+                    rung.SelectElement(wire)
+            for left_element in left_elements:
+                left_block = left_element.GetParentBlock()
+                if isinstance(left_block, LD_PowerRail):
+                    if len(left_element.GetWires()) == 0:
+                        index = left_block.GetConnectorIndex(left_element)
+                        left_block.DeleteConnector(index)
+                else:
+                    connectors = left_block.GetConnectors()
+                    output_connectors = []
+                    if "outputs" in connectors:
+                        output_connectors = connectors["outputs"]
+                    if "output" in connectors:
+                        output_connectors = [connectors["output"]]
+                    for connector in output_connectors:
+                        for wire, handle in connector.GetWires():
+                            self.RefreshPosition(wire.StartConnected.GetParentBlock())
+            for right_element in right_elements:
+                self.RefreshPosition(right_element.GetParentBlock())
+            rung.RefreshBoundingBox()
+            new_bbox = rung.GetBoundingBox()
+            self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
+            self.SelectedElement = None
+
+#-------------------------------------------------------------------------------
+#                        Refresh element position functions
+#-------------------------------------------------------------------------------
+
+    def RefreshPosition(self, element):
+        if isinstance(element, LD_PowerRail) and element.GetType() == LEFTRAIL:
+            element.RefreshModel()
+            return
+        connectors = element.GetConnectors()
+        input_connectors = []
+        output_connectors = []
+        if isinstance(element, LD_PowerRail) and element.GetType() == RIGHTRAIL:
+            input_connectors = connectors
+        else:
+            if "inputs" in connectors:
+                input_connectors = connectors["inputs"]
+            if "outputs" in connectors:
+                output_connectors = connectors["outputs"]
+            if "input" in connectors:
+                input_connectors = [connectors["input"]]
+            if "output" in connectors:
+                output_connectors = [connectors["output"]]
+        position = element.GetPosition()
+        minx = 0
+        onlyone = []
+        for connector in input_connectors:
+            onlyone.append(len(connector.GetWires()) == 1)
+            for wire, handle in connector.GetWires():
+                onlyone[-1] &= len(wire.EndConnected.GetWires()) == 1
+                leftblock = wire.EndConnected.GetParentBlock()
+                pos = leftblock.GetPosition()
+                size = leftblock.GetSize()
+                minx = max(minx, pos[0] + size[0])
+        if isinstance(element, LD_Coil):
+            interval = LD_WIRECOIL_SIZE
+        else:
+            interval = LD_WIRE_SIZE
+        if False in onlyone:
+            interval += LD_WIRE_SIZE
+        movex = minx + interval - position[0]
+        element.Move(movex, 0)
+        for i, connector in enumerate(input_connectors):
+            startpoint = connector.GetPosition(False)
+            previous_blocks = []
+            block_list = []
+            start_offset = 0
+            if not onlyone[i]:
+                middlepoint = minx + LD_WIRE_SIZE
+            for j, (wire, handle) in enumerate(connector.GetWires()):
+                block = wire.EndConnected.GetParentBlock()
+                endpoint = wire.EndConnected.GetPosition(False)
+                if j == 0:
+                    if not onlyone[i] and wire.EndConnected.GetWireIndex(wire) > 0:
+                        start_offset = endpoint.y - startpoint.y
+                    offset = start_offset
+                else:
+                    offset = start_offset + LD_LINE_SIZE * CalcBranchSize(previous_blocks, block)
+                if block in block_list:
+                    wires = wire.EndConnected.GetWires()
+                    endmiddlepoint = wires[0][0].StartConnected.GetPosition(False)[0] - LD_WIRE_SIZE
+                    points = [startpoint, wxPoint(middlepoint, startpoint.y),
+                              wxPoint(middlepoint, startpoint.y + offset),
+                              wxPoint(endmiddlepoint, startpoint.y + offset),
+                              wxPoint(endmiddlepoint, endpoint.y), endpoint]
+                else:
+                    if startpoint.y + offset != endpoint.y:
+                        if isinstance(block, LD_PowerRail):
+                            index = block.GetConnectorIndex(wire.EndConnected)
+                            if index:
+                                diff = (startpoint.y - endpoint.y) / LD_LINE_SIZE
+                                for k in xrange(abs(diff)):
+                                    if diff < 0:
+                                        block.DeleteConnector(index - 1 - k)
+                                    else:
+                                        block.InsertConnector(index + k, False)
+                        else:
+                            block.Move(0, startpoint.y + offset - endpoint.y)
+                            self.RefreshPosition(block)
+                        endpoint = wire.EndConnected.GetPosition(False)
+                    if not onlyone[i]:
+                        points = [startpoint, wxPoint(middlepoint, startpoint.y),
+                                  wxPoint(middlepoint, endpoint.y), endpoint]
+                    else:
+                        points = [startpoint, endpoint]
+                wire.SetPoints(points)
+                previous_blocks.append(block)
+                ExtractNextBlocks(block, block_list)
+        element.RefreshModel(False)
+        for connector in output_connectors:
+            for wire, handle in connector.GetWires():
+                self.RefreshPosition(wire.StartConnected.GetParentBlock())
+    
+    def RefreshRungs(self, movey, fromidx):
+        if movey != 0:
+            for i in xrange(fromidx, len(self.Rungs)):
+                self.Comments[i].Move(0, movey)
+                self.Comments[i].RefreshModel()
+                self.Rungs[i].Move(0, movey)
+                for element in self.Rungs[i].GetElements():
+                    if element in self.Blocks:
+                        self.RefreshPosition(element)
+
+#-------------------------------------------------------------------------------
+#                          Edit element content functions
+#-------------------------------------------------------------------------------
+
+    def EditContactContent(self, contact):
+        dialog = LDElementDialog(self.Parent, "contact")
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                if var["Type"] != "Output" and var["Value"] == "BOOL":
+                    varlist.append(var["Name"])
+        dialog.SetVariables(varlist)
+        dialog.SetValues({"name":contact.GetName(),"type":contact.GetType()})
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            contact.SetName(values["name"])
+            contact.SetType(values["type"])
+            contact.RefreshModel(False)
+            self.Refresh()
+        dialog.Destroy()
+
+    def EditCoilContent(self, coil):
+        dialog = LDElementDialog(self.Parent, "coil")
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                if var["Type"] != "Input" and var["Value"] == "BOOL":
+                    varlist.append(var["Name"])
+        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
+        if returntype == "BOOL":
+            varlist.append(self.Controler.GetCurrentElementEditingName())
+        dialog.SetVariables(varlist)
+        dialog.SetValues({"name":coil.GetName(),"type":coil.GetType()})
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            coil.SetName(values["name"])
+            coil.SetType(values["type"])
+            coil.RefreshModel(False)
+            self.Refresh()
+        dialog.Destroy()
+
+#-------------------------------------------------------------------------------
+#                        Edit Ladder Element Properties Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_LDELEMENTDIALOG, wxID_LDELEMENTDIALOGMAINPANEL, 
+ wxID_LDELEMENTDIALOGNAME, wxID_LDELEMENTDIALOGRADIOBUTTON1, 
+ wxID_LDELEMENTDIALOGRADIOBUTTON2, wxID_LDELEMENTDIALOGRADIOBUTTON3,
+ wxID_LDELEMENTDIALOGRADIOBUTTON4, wxID_LDELEMENTDIALOGPREVIEW,
+ wxID_LDELEMENTDIALOGSTATICTEXT1, wxID_LDELEMENTDIALOGSTATICTEXT2, 
+ wxID_LDELEMENTDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(11)]
+
+class LDElementDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt, title, labels):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_LDELEMENTDIALOG,
+              name='VariablePropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(350, 260), style=wx.DEFAULT_DIALOG_STYLE,
+              title=title)
+        self.SetClientSize(wx.Size(350, 260))
+
+        self.MainPanel = wx.Panel(id=wxID_LDELEMENTDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(340, 200), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT1,
+              label='Type:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(70, 17), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT2,
+              label='Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 150), size=wx.Size(70, 17), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT3,
+              label='Preview:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(174, 24), size=wx.Size(100, 17), style=0)
+
+        self.radioButton1 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON1,
+              label=labels[0], name='radioButton1', parent=self.MainPanel,
+              pos=wx.Point(24, 48), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON1, self.OnTypeChanged)
+        self.radioButton1.SetValue(True)
+
+        self.radioButton2 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON2,
+              label=labels[1], name='radioButton2', parent=self.MainPanel, 
+              pos=wx.Point(24, 72), size=wx.Size(128, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON2, self.OnTypeChanged)
+
+        self.radioButton3 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON3,
+              label=labels[2], name='radioButton3', parent=self.MainPanel,
+              pos=wx.Point(24, 96), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON3, self.OnTypeChanged)
+
+        self.radioButton4 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON4,
+              label=labels[3], name='radioButton4', parent=self.MainPanel, 
+              pos=wx.Point(24, 120), size=wx.Size(128, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON4, self.OnTypeChanged)
+
+        self.Name = wx.Choice(id=wxID_LDELEMENTDIALOGNAME,
+              name='Name', parent=self.MainPanel, pos=wx.Point(24, 174),
+              size=wx.Size(145, 24), style=0)
+        EVT_CHOICE(self, wxID_LDELEMENTDIALOGNAME, self.OnNameChanged)
+
+        self.Preview = wx.Panel(id=wxID_LDELEMENTDIALOGPREVIEW,
+              name='Preview', parent=self.MainPanel, pos=wx.Point(174, 48),
+              size=wx.Size(150, 150), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
+        self.Preview.SetBackgroundColour(wxColour(255,255,255))
+
+        self._init_sizers()
+
+    def __init__(self, parent, type):
+        self.Type = type
+        if type == "contact":
+            self._init_ctrls(parent, "Edit Contact Values", ['Normal','Reverse','Rising Edge','Falling Edge'])
+            self.Element = LD_Contact(self.Preview, CONTACT_NORMAL, "")
+        elif type == "coil":
+            self._init_ctrls(parent, "Edit Coil Values", ['Normal','Reverse','Set','Reset'])
+            self.Element = LD_Coil(self.Preview, COIL_NORMAL, "")
+        self.Element.SetPosition((150 - LD_ELEMENT_SIZE[0]) / 2, (150 - LD_ELEMENT_SIZE[1]) / 2)
+
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+
+        EVT_PAINT(self, self.OnPaint)
+
+    def SetVariables(self, vars):
+        self.Name.Clear()
+        for name in vars:
+            self.Name.Append(name)
+        self.Name.Enable(self.Name.GetCount() > 0)
+
+    def SetValues(self, values):
+        for name, value in values.items():
+            if name == "name":
+                self.Element.SetName(value)
+                self.Name.SetStringSelection(value)
+            elif name == "type":
+                self.Element.SetType(value)
+                if self.Type == "contact":
+                    if value == CONTACT_NORMAL:
+                        self.radioButton1.SetValue(True)
+                    elif value == CONTACT_REVERSE:
+                        self.radioButton2.SetValue(True)
+                    elif value == CONTACT_RISING:
+                        self.radioButton3.SetValue(True)
+                    elif value == CONTACT_FALLING:
+                        self.radioButton4.SetValue(True)
+                elif self.Type == "coil":
+                    if value == COIL_NORMAL:
+                        self.radioButton1.SetValue(True)
+                    elif value == COIL_REVERSE:
+                        self.radioButton2.SetValue(True)
+                    elif value == COIL_SET:
+                        self.radioButton3.SetValue(True)
+                    elif value == COIL_RESET:
+                        self.radioButton4.SetValue(True)
+
+    def GetValues(self):
+        values = {}
+        values["name"] = self.Element.GetName()
+        values["type"] = self.Element.GetType()
+        return values
+
+    def OnTypeChanged(self, event):
+        if self.Type == "contact":
+            if self.radioButton1.GetValue():
+                self.Element.SetType(CONTACT_NORMAL)
+            elif self.radioButton2.GetValue():
+                self.Element.SetType(CONTACT_REVERSE)
+            elif self.radioButton3.GetValue():
+                self.Element.SetType(CONTACT_RISING)
+            elif self.radioButton4.GetValue():
+                self.Element.SetType(CONTACT_FALLING)
+        elif self.Type == "coil":
+            if self.radioButton1.GetValue():
+                self.Element.SetType(COIL_NORMAL)
+            elif self.radioButton2.GetValue():
+                self.Element.SetType(COIL_REVERSE)
+            elif self.radioButton3.GetValue():
+                self.Element.SetType(COIL_SET)
+            elif self.radioButton4.GetValue():
+                self.Element.SetType(COIL_RESET)
+        self.RefreshPreview()
+        event.Skip()
+
+    def OnNameChanged(self, event):
+        self.Element.SetName(self.Name.GetStringSelection())
+        self.RefreshPreview()
+        event.Skip()
+
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        self.Element.Draw(dc)
+
+    def OnPaint(self, event):
+        self.RefreshPreview()
+        event.Skip()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PLCControler.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,1827 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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
+import cPickle
+import os,sys,re
+
+from plcopen import plcopen
+from plcopen.structures import *
+from graphics.GraphicCommons import *
+from PLCGenerator import *
+
+[ITEM_UNEDITABLE, ITEM_PROJECT, ITEM_POU, ITEM_CLASS, ITEM_VARIABLE,
+ ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE] = range(9)
+
+#-------------------------------------------------------------------------------
+#                         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.Project = None
+        self.ProjectBuffer = None
+        self.FilePath = ""
+        self.FileName = ""
+        self.ElementsOpened = []
+        self.CurrentElementEditing = None
+        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)
+        # Initialize the project buffer
+        self.ProjectBuffer = UndoBuffer(self.Copy(self.Project))
+    
+    # Change project name
+    def SetProjectName(self, name):
+        self.Project.setName(name)
+    
+    # Return project name
+    def GetProjectName(self):
+        return self.Project.getName()
+    
+    # Return project pou names
+    def GetProjectPouNames(self):
+        return [pou.getName() for pou in self.Project.getPous()]
+    
+    # Return project pou names
+    def GetProjectConfigNames(self):
+        return [config.getName() for config in self.Project.getConfigurations()]
+    
+    # Return file path if project is an open file
+    def GetFilePath(self):
+        return self.FilePath
+    
+    # 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, values):
+        self.Project.setFileHeader(values)
+    
+    # Return project properties
+    def GetProjectProperties(self):
+        return self.Project.getFileHeader()
+    
+    # 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}
+                var_types = {"Input": {"name": "Input", "type": ITEM_CLASS, "values": []},
+                         "Output": {"name": "Output", "type": ITEM_CLASS, "values": []},
+                         "InOut": {"name": "InOut", "type": ITEM_CLASS, "values": []},
+                         "External": {"name": "External", "type": ITEM_CLASS, "values": []},
+                         "Local": {"name": "Local", "type": ITEM_CLASS, "values": []},
+                         "Temp": {"name": "Temp", "type": ITEM_CLASS, "values": []},
+                         "Global": {"name": "Global", "type": ITEM_CLASS, "values": []}}
+                for var in self.GetPouInterfaceVars(pou):
+                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
+                    if var["Class"] in var_types.keys():
+                        var_types[var["Class"]]["values"].append(var_values)
+                pou_values = []
+                pou_values.append({"name": "Interface", "type": ITEM_CLASS, 
+                    "values": [var_types["Input"], var_types["Output"], var_types["InOut"], var_types["External"]]})
+                pou_values.append({"name": "Variables", "type": ITEM_CLASS, 
+                    "values": [var_types["Local"], var_types["Temp"]]})
+                if pou_type == "program":
+                    pou_values.append(var_types["Global"])
+                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": []}
+                config_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
+                for var in self.GetConfigurationGlobalVars(config_name):
+                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
+                    config_vars["values"].append(var_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": []}
+                    resource_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
+                    for var in self.GetConfigurationResourceGlobalVars(config_name, resource_name):
+                        var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
+                        resource_vars["values"].append(var_values)
+                    resource_infos["values"].append(resource_vars)
+                    resources["values"].append(resource_infos)
+                config_infos["values"] = [config_vars, 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()
+                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):
+        if self.Project:
+            program = GenerateCurrentProgram(self.Project)
+            programfile = open("test.st", "w")
+            programfile.write(program)
+            programfile.close()
+
+#-------------------------------------------------------------------------------
+#                        Project Pous management functions
+#-------------------------------------------------------------------------------
+    
+    # Add a Pou to Project
+    def ProjectAddPou(self, name, pou_type, body_type):
+        # Add the pou to project
+        self.Project.appendPou(name, pou_type, body_type)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # Remove a pou from project
+    def ProjectRemovePou(self, name):
+        removed = None
+        # Search if the pou removed is currently opened
+        for i, pou in enumerate(self.ElementsOpened):
+            if pou == name:
+                removed = i
+        # If found, remove pou from list of opened pous and actualize current edited
+        if removed != None:
+            self.ElementsOpened.pop(removed)
+            if self.CurrentElementEditing > removed:
+                self.CurrentElementEditing -= 1
+            if len(self.ElementsOpened) > 0:
+                self.CurrentElementEditing = max(0, min(self.CurrentElementEditing, len(self.ElementsOpened) - 1))
+            else:
+                self.CurrentElementEditing = None
+        # Remove pou from project
+        self.Project.removePou(name)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # Add a configuration to Project
+    def ProjectAddConfiguration(self, name):
+        self.Project.addConfiguration(name)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # Remove a configuration from project
+    def ProjectRemoveConfiguration(self, name):
+        self.Project.removeConfiguration(name)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # Add a resource to a configuration of the Project
+    def ProjectAddConfigurationResource(self, config, name):
+        self.Project.addConfigurationResource(config, name)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # Remove a resource from a configuration of the project
+    def ProjectRemoveConfigurationResource(self, config, name):
+        self.Project.removeConfigurationResource(config, name)
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # 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)
+    
+    # Add a Transition 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)
+        
+    # 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)
+        # If pou is currently opened, change its name in the list of opened pous
+        if old_name in self.ElementsOpened:
+            idx = self.ElementsOpened.index(old_name)
+            self.ElementsOpened[idx] = new_name
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+    
+    # 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)
+        # If pou transition is currently opened, change its name in the list of opened elements
+        old_computedname = self.ComputePouTransitionName(pou_name, old_name)
+        new_computedname = self.ComputePouTransitionName(pou_name, new_name)
+        if old_computedname in self.ElementsOpened:
+            idx = self.ElementsOpened.index(old_computedname)
+            self.ElementsOpened[idx] = new_computedname
+    
+    # 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)
+        # If pou action is currently opened, change its name in the list of opened elements
+        old_computedname = self.ComputePouActionName(pou_name, old_name)
+        new_computedname = self.ComputePouActionName(pou_name, new_name)
+        if old_computedname in self.ElementsOpened:
+            idx = self.ElementsOpened.index(old_computedname)
+            self.ElementsOpened[idx] = new_computedname
+
+    # 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)
+        # If configuration is currently opened, change its name in the list of opened elements
+        for idx, element in enumerate(self.ElementsOpened):
+            self.ElementsOpened[idx] = element.replace(old_name, new_name)
+
+    # 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)
+        # If resource is currently opened, change its name in the list of opened elements
+        old_computedname = self.ComputeConfigurationResourceName(config_name, old_name)
+        new_computedname = self.ComputeConfigurationResourceName(config_name, new_name)
+        if old_computedname in self.ElementsOpened:
+            idx = self.ElementsOpened.index(old_computedname)
+            self.ElementsOpened[idx] = new_computedname
+    
+    # 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 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 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"]):
+                current_type = (var["Class"], var["Retain"], var["Constant"])
+                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()
+            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"])
+            # 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","Type":var.getType().getValue(),
+                        "Location":var.getAddress()}
+                    initial = var.getInitialValue()
+                    if initial:
+                        tempvar["Initial Value"] = initial.getValue()
+                    else:
+                        tempvar["Initial Value"] = ""
+                    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","Type":var.getType().getValue(),
+                        "Location":var.getAddress()}
+                    initial = var.getInitialValue()
+                    if initial:
+                        tempvar["Initial Value"] = initial.getValue()
+                    else:
+                        tempvar["Initial Value"] = ""
+                    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,"Type":var.getType().getValue(),
+                        "Location":var.getAddress()}
+                    initial = var.getInitialValue()
+                    if initial:
+                        tempvar["Initial Value"] = initial.getValue()
+                    else:
+                        tempvar["Initial Value"] = ""
+                    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.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()
+    
+    # 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" : ""}
+                    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):
+        if self.CurrentElementEditing != None:
+            current_name = self.ElementsOpened[self.CurrentElementEditing]
+            words = current_name.split("::")
+            if len(words) == 1:
+                name = current_name
+            else:
+                name = words[1]
+            blocktypes = [category for category in BlockTypes[:-1]]
+            blocktypes.append({"name" : "User-defined POUs", "list": []})
+            if self.Project:
+                pou = self.Project.getPou(name)
+                name = pou.getName()
+                type = pou.pouType.getValue()
+                for blocktype in BlockTypes[-1]["list"]:
+                    if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] == "functionBlock"):
+                        blocktypes[-1]["list"].append(blocktype)
+            return blocktypes
+        return []
+
+    # Return Block types checking for recursion
+    def GetBlockResource(self):
+        blocktypes = []
+        for category in BlockTypes[:-1]:
+            for blocktype in category["list"]:
+                if blocktype["type"] != "function":
+                    blocktypes.append(blocktype["name"])
+        if self.Project:
+            for pou in self.Project.getPous():
+                if pou.pouType.getValue() != "function":
+                    blocktypes.append(pou.getName())
+        return blocktypes
+
+#-------------------------------------------------------------------------------
+#                       Project opened Pous management functions
+#-------------------------------------------------------------------------------
+    
+    # Return the list of pou names
+    def GetElementsOpenedNames(self):
+        names = []
+        for pou_name in self.ElementsOpened:
+            words = pou_name.split("::")
+            if len(words) == 1:
+                names.append(pou_name)
+            else:
+                names.append("%s-%s"%(words[1],words[2]))
+        return names
+    
+    # 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 ComputeConfigurationResourceName(self, config, resource):
+        return "R::%s::%s" % (config, resource)
+    
+    # Open a pou by giving its name
+    def OpenElementEditing(self, name):
+        # If pou not opened yet
+        if name not in self.ElementsOpened:
+            # Add pou name to list of pou opened and make it current editing
+            self.ElementsOpened.append(name)
+            self.CurrentElementEditing = len(self.ElementsOpened) - 1
+            return self.CurrentElementEditing
+        return None
+
+    # Open a pou transition by giving pou and transition names
+    def OpenPouTransitionEditing(self, pou, transition):
+        return self.OpenElementEditing(self.ComputePouTransitionName(pou, transition))
+
+    # Open a pou action by giving pou and action names
+    def OpenPouActionEditing(self, pou, action):
+        return self.OpenElementEditing(self.ComputePouActionName(pou, action))
+
+    # Open a configuration resource by giving configuration and resource names
+    def OpenConfigurationResourceEditing(self, config, resource):
+        return self.OpenElementEditing(self.ComputeConfigurationResourceName(config, resource))
+
+    # Return if pou given by name is opened
+    def IsElementEditing(self, name):
+        return name in self.ElementsOpened
+
+    # Return if pou transition given by pou and transition names is opened
+    def IsPouTransitionEditing(self, pou, transition):
+        return self.ComputePouTransitionName(pou, transition) in self.ElementsOpened
+
+    # Return if pou action given by pou and action names is opened
+    def IsPouActionEditing(self, pou, action):
+        return self.ComputePouActionName(pou, action) in self.ElementsOpened
+
+    # Return if pou action given by pou and action names is opened
+    def IsConfigurationResourceEditing(self, pou, action):
+        return self.ComputeConfigurationResourceName(config, resource) in self.ElementsOpened
+
+    # Close current pou editing
+    def CloseElementEditing(self):
+        # Remove pou from list of pou opened
+        self.ElementsOpened.pop(self.CurrentElementEditing)
+        # Update index of current pou editing
+        if len(self.ElementsOpened) > 0:
+            self.CurrentElementEditing = min(self.CurrentElementEditing, len(self.ElementsOpened) - 1)
+        else:
+            self.CurrentElementEditing = None
+
+    # Change current pou editing for pou given by name
+    def ChangeElementEditing(self, name):
+        # Verify that pou is opened
+        if name in self.ElementsOpened:
+            # Change current pou editing
+            self.CurrentElementEditing = self.ElementsOpened.index(name)
+            return self.CurrentElementEditing
+        return None
+
+    # Change current pou editing for transition given by pou and transition names
+    def ChangePouTransitionEditing(self, pou, transition):
+        return self.ChangeElementEditing(self.ComputePouTransitionName(pou, transition))
+
+    # Change current pou editing for action given by pou and action names
+    def ChangePouActionEditing(self, pou, action):
+        return self.ChangeElementEditing(self.ComputePouActionName(pou, action))
+
+    # Change current pou editing for action given by configuration and resource names
+    def ChangeConfigurationResourceEditing(self, config, resource):
+        return self.ChangeElementEditing(self.ComputeConfigurationResourceName(config, resource))
+
+#-------------------------------------------------------------------------------
+#                       Project opened Pous management functions
+#-------------------------------------------------------------------------------
+
+    # Return current pou editing
+    def GetCurrentElementEditing(self):
+        # Verify that there's one editing and return it
+        if self.CurrentElementEditing != None:
+            name = self.ElementsOpened[self.CurrentElementEditing]
+            words = name.split("::")
+            if len(words) == 1:
+                return self.Project.getPou(name)
+            else:
+                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] == 'R':
+                    result = self.Project.getConfigurationResource(words[1], words[2])
+                    return result
+        return None
+    
+    # Return current pou editing name
+    def GetCurrentElementEditingName(self):
+        # Verify that there's one editing and return its name
+        if self.CurrentElementEditing != None:
+            name = self.ElementsOpened[self.CurrentElementEditing]
+            words = name.split("::")
+            if len(words) == 1:
+                return name
+            else:
+                return words[2]
+        return None
+    
+    # Replace the index of current pou editing by the one given
+    def RefreshCurrentElementEditing(self, index):
+        self.CurrentElementEditing = index
+
+    # Return language in which current pou editing is written
+    def GetCurrentElementEditingBodyType(self):
+        if self.CurrentElementEditing != None:
+            name = self.ElementsOpened[self.CurrentElementEditing]
+            words = name.split("::")
+            if len(words) == 1:
+                return self.GetPouBodyType(name)
+            else:
+                if 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 variables of the current pou editing
+    def GetCurrentElementEditingInterfaceVars(self):
+        if self.CurrentElementEditing != None:
+            current_name = self.ElementsOpened[self.CurrentElementEditing]
+            words = current_name.split("::")
+            if len(words) == 1:
+                pou = self.Project.getPou(current_name)
+                return self.GetPouInterfaceVars(pou)
+            else:
+                pou = self.Project.getPou(words[1])
+                return self.GetPouInterfaceVars(pou)
+        return []
+
+    # Return the return type of the current pou editing
+    def GetCurrentElementEditingInterfaceReturnType(self):
+        if self.CurrentElementEditing != None:
+            current_name = self.ElementsOpened[self.CurrentElementEditing]
+            words = current_name.split("::")
+            if len(words) == 1:
+                pou = self.Project.getPou(current_name)
+                return self.GetPouInterfaceReturnType(pou)
+            elif words[0] == 'T':
+                return "BOOL"
+        return None
+    
+    # Change the text of the current pou editing
+    def SetCurrentElementEditingText(self, text):
+        if self.CurrentElementEditing != None:
+            self.GetCurrentElementEditing().setText(text)
+            self.RefreshPouUsingTree()
+    
+    # Return the current pou editing text
+    def GetCurrentElementEditingText(self):
+        if self.CurrentElementEditing != None:
+            return self.GetCurrentElementEditing().getText()
+        return ""
+
+    # Return the current pou editing transitions
+    def GetCurrentElementEditingTransitions(self):
+        if self.CurrentElementEditing != None:
+            pou = self.GetCurrentElementEditing()
+            if pou.getBodyType() == "SFC":
+                transitions = []
+                for transition in pou.getTransitionList():
+                    transitions.append(transition.getName())
+                return transitions
+        return []
+
+    # Return the current pou editing transitions
+    def GetCurrentElementEditingActions(self):
+        if self.CurrentElementEditing != None:
+            pou = self.GetCurrentElementEditing()
+            if pou.getBodyType() == "SFC":
+                actions = []
+                for action in pou.getActionList():
+                    actions.append(action.getName())
+                return actions
+        return []
+
+    # Return the current pou editing informations
+    def GetCurrentElementEditingInstanceInfos(self, id = None, exclude = []):
+        infos = {}
+        # if id is defined
+        if id != None:
+            instance = self.GetCurrentElementEditing().getInstance(id)
+        else:
+            instance = self.GetCurrentElementEditing().getRandomInstance(exclude)
+        if instance:
+            if id != 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()
+                infos["connectors"] = {"inputs":[],"outputs":[]}
+                for variable in instance.inputVariables.getVariable():
+                    connector = {}
+                    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()}
+                            connector["links"].append(dic)
+                    infos["connectors"]["inputs"].append(connector)
+                for variable in instance.outputVariables.getVariable():
+                    connector = {}
+                    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.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
+                infos["type"] = "input"
+                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.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
+                infos["type"] = "output"
+                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()}
+                        infos["connector"]["links"].append(dic)
+            elif isinstance(instance, plcopen.inOutVariable):
+                infos["name"] = instance.getExpression()
+                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
+                infos["type"] = "inout"
+                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()}
+                        infos["connectors"]["input"]["links"].append(dic)
+            elif isinstance(instance, plcopen.continuation):
+                infos["name"] = instance.getName()
+                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
+                infos["type"] = "continuation"
+                infos["connector"] = {}
+                infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
+            elif isinstance(instance, plcopen.connector):
+                infos["name"] = instance.getName()
+                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
+                infos["type"] = "connection"
+                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()}
+                        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()}
+                        connector["links"].append(dic)
+                    infos["connectors"].append(connector)
+            elif isinstance(instance, plcopen.contact):
+                infos["type"] = "contact"
+                infos["name"] = instance.getVariable()
+                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()}
+                        infos["connectors"]["input"]["links"].append(dic)
+                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
+            elif isinstance(instance, plcopen.coil):
+                infos["type"] = "coil"
+                infos["name"] = instance.getVariable()
+                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()}
+                        infos["connectors"]["input"]["links"].append(dic)
+                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
+            elif isinstance(instance, plcopen.step):
+                infos["type"] = "step"
+                infos["name"] = instance.getName()
+                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()}
+                            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()
+                infos["condition_type"] = condition["type"]
+                infos["condition"] = condition["value"]
+                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()}
+                        infos["connectors"]["input"]["links"].append(dic)
+                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
+            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()}
+                        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()}
+                            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()}
+                        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()}
+                        infos["connector"]["links"].append(dic)
+            return infos
+        return False
+    
+    # Return the variable type of the given pou
+    def GetPouVarValueType(self, pou, varname):
+        for type, varlist in pou.getVars():
+            for var in varlist.getVariable():
+                if var.getName() == varname:
+                    return var.getType()
+        return ""
+    
+    def SetConnectionWires(self, connection, connector):
+        wires = connector.GetWires()
+        idx = 0
+        for wire, handle in wires:
+            points = wire.GetPoints(handle != 0)
+            if handle == 0:
+                refLocalId = wire.GetConnectedId(-1)
+            else:
+                refLocalId = wire.GetConnectedId(0)
+            if refLocalId != None:
+                connection.addConnection()
+                connection.setConnectionId(idx, refLocalId)
+                connection.setConnectionPoints(idx, points)
+                idx += 1
+    
+    def AddCurrentElementEditingBlock(self, id):
+        block = plcopen.block()
+        block.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("block", block)
+        self.RefreshPouUsingTree()
+    
+    def SetCurrentElementEditingBlockInfos(self, id, infos):
+        block = self.GetCurrentElementEditing().getInstance(id)
+        for param, value in infos.items():
+            if param == "name":
+                block.setInstanceName(value)
+            elif param == "type":
+                block.setTypeName(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 AddCurrentElementEditingVariable(self, id, type):
+        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)
+        self.GetCurrentElementEditing().addInstance(name, variable)
+        
+    def SetCurrentElementEditingVariableInfos(self, id, infos):
+        variable = self.GetCurrentElementEditing().getInstance(id)
+        for param, value in infos.items():
+            if param == "name":
+                variable.setExpression(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 AddCurrentElementEditingConnection(self, id, type):
+        if type == CONNECTOR:
+            name = "connector"
+            connection = plcopen.connector()
+        elif type == CONTINUATION:
+            name = "continuation"
+            connection = plcopen.continuation()
+        connection.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance(name, connection)
+        
+    def SetCurrentElementEditingConnectionInfos(self, id, infos):
+        connection = self.GetCurrentElementEditing().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 AddCurrentElementEditingComment(self, id):
+        comment = plcopen.comment()
+        comment.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("comment", comment)
+    
+    def SetCurrentElementEditingCommentInfos(self, id, infos):
+        comment = self.GetCurrentElementEditing().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 AddCurrentElementEditingPowerRail(self, id, type):
+        if type == LEFTRAIL:
+            name = "leftPowerRail"
+            powerrail = plcopen.leftPowerRail()
+        elif type == RIGHTRAIL:
+            name = "rightPowerRail"
+            powerrail = plcopen.rightPowerRail()
+        powerrail.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance(name, powerrail)
+    
+    def SetCurrentElementEditingPowerRailInfos(self, id, infos):
+        powerrail = self.GetCurrentElementEditing().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 AddCurrentElementEditingContact(self, id):
+        contact = plcopen.contact()
+        contact.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("contact", contact)
+
+    def SetCurrentElementEditingContactInfos(self, id, infos):
+        contact = self.GetCurrentElementEditing().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 AddCurrentElementEditingCoil(self, id):
+        coil = plcopen.coil()
+        coil.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("coil", coil)
+
+    def SetCurrentElementEditingCoilInfos(self, id, infos):
+        coil = self.GetCurrentElementEditing().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 AddCurrentElementEditingStep(self, id):
+        step = plcopen.step()
+        step.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("step", step)
+    
+    def SetCurrentElementEditingStepInfos(self, id, infos):
+        step = self.GetCurrentElementEditing().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 AddCurrentElementEditingTransition(self, id):
+        transition = plcopen.transition()
+        transition.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("transition", transition)
+    
+    def SetCurrentElementEditingTransitionInfos(self, id, infos):
+        transition = self.GetCurrentElementEditing().getInstance(id)
+        for param, value in infos.items():
+            if param == "type" and "condition" in infos:
+                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 == "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)
+    
+    def AddCurrentElementEditingDivergence(self, id, type):
+        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)
+        self.GetCurrentElementEditing().addInstance(name, divergence)
+    
+    def SetCurrentElementEditingDivergenceInfos(self, id, infos):
+        divergence = self.GetCurrentElementEditing().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 AddCurrentElementEditingJump(self, id):
+        jump = plcopen.jumpStep()
+        jump.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("jumpStep", jump)
+    
+    def SetCurrentElementEditingJumpInfos(self, id, infos):
+        jump = self.GetCurrentElementEditing().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 AddCurrentElementEditingActionBlock(self, id):
+        actionBlock = plcopen.actionBlock()
+        actionBlock.setLocalId(id)
+        self.GetCurrentElementEditing().addInstance("actionBlock", actionBlock)
+    
+    def SetCurrentElementEditingActionBlockInfos(self, id, infos):
+        actionBlock = self.GetCurrentElementEditing().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 RemoveCurrentElementEditingInstance(self, id):
+        self.GetCurrentElementEditing().removeInstance(id)
+        self.RefreshPouUsingTree()
+
+    def GetCurrentResourceEditingVariables(self):
+        varlist = []
+        name = self.ElementsOpened[self.CurrentElementEditing]
+        words = name.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 SetCurrentResourceEditingInfos(self, tasks, instances):
+        resource = self.GetCurrentElementEditing()
+        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"])
+            if task["Interval"] != "":
+                new_task.setInterval(task["Interval"])
+            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 GetCurrentResourceEditingInfos(self):
+        resource = self.GetCurrentElementEditing()
+        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:
+                new_task["Interval"] = interval
+            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 sys:
+            sys.stdout = plcopen.HolePseudoFile()
+        tree = pyxsval.parseAndValidate(filepath, "plcopen/TC6_XML_V10_B.xsd")
+        if sys:
+            sys.stdout = sys.__stdout__
+        
+        self.Project = plcopen.project()
+        self.Project.loadXMLTree(tree.getTree().childNodes[0])
+        self.UndoBuffer = UndoBuffer(self.Copy(self.Project), True)
+        self.SetFilePath(filepath)
+        self.ElementsOpened = []
+        self.CurrentElementEditing = None
+        self.RefreshPouUsingTree()
+        self.RefreshBlockTypes()
+
+    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 sys:
+                sys.stdout = plcopen.HolePseudoFile()
+            pyxsval.parseAndValidateString(text, open("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.UndoBuffer.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.UndoBuffer.Buffering(self.Copy(self))
+
+    def ProjectIsSaved(self):
+        return self.UndoBuffer.IsCurrentSaved()
+
+    def LoadPrevious(self):
+        self.Project = self.Copy(self.UndoBuffer.Previous())
+        self.RefreshElementsOpened()
+    
+    def LoadNext(self):
+        self.Project = self.Copy(self.UndoBuffer.Next())
+        self.RefreshElementsOpened()
+    
+    def GetBufferState(self):
+        first = self.UndoBuffer.IsFirst()
+        last = self.UndoBuffer.IsLast()
+        return not first, not last
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PLCGenerator.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,422 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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 plcopen import plcopen
+from plcopen.structures import *
+from types import *
+
+varTypeNames = {"localVars" : "VAR", "tempVars" : "VAR_TEMP", "inputVars" : "VAR_INPUT", 
+                "outputVars" : "VAR_OUTPUT", "inOutVars" : "VAR_IN_OUT", "externalVars" : "VAR_EXTERNAL",
+                "globalVars" : "VAR_GLOBAL", "accessVars" : "VAR_ACCESS"}
+"""
+Module implementing methods for generating PLC programs in ST or IL
+"""
+
+class PouProgram:
+    
+    def __init__(self, name, type):
+        self.Name = name
+        self.Type = type
+        self.Interface = {}
+        self.Steps = {}
+        self.Transitions = {}
+        self.Order = []
+        self.Program = ""
+    
+    def GenerateInterface(self, interface):
+        if self.Type == "FUNCTION":
+            self.Interface["returnType"] = interface.getReturnType().getValue()
+        for varlist in interface.getContent():
+            variables = {}
+            for var in varlist["value"].getVariable():
+                type = var.getType().getValue()
+                if type not in variables:
+                    variables[type] = []
+                variables[type].append(var.getName())
+            self.Interface[(varTypeNames[varlist["name"]], varlist["value"].getRetain(), 
+                            varlist["value"].getConstant())] = variables
+    
+    def GenerateProgram(self, pou):
+        body = pou.getBody()
+        body_content = body.getContent()
+        body_type = body_content["name"]
+        if body_type in ["IL","ST"]:
+            self.Program = "%s\n"%body_content["value"].getText()
+        elif body_type == "FBD":
+            for instance in body.getContentInstances():
+                if isinstance(instance, plcopen.outVariable):
+                    var = instance.getExpression()
+                    connections = instance.connectionPointIn.getConnections()
+                    if connections and len(connections) == 1:
+                        expression = self.ComputeFBDExpression(body, connections[0])
+                        self.Program += "  %s := %s;\n"%(var, expression)
+        elif body_type == "LD":
+            for instance in body.getContentInstances():
+                if isinstance(instance, plcopen.coil):
+                    paths = self.GenerateLDPaths(instance, body)
+                    variable = self.ExtractModifier(instance, instance.getVariable())
+                    expression = self.ComputeLDExpression(paths, True)
+                    self.Program += "  %s := %s;\n"%(variable, expression)
+        elif body_type == "SFC":
+            for instance in body.getContentInstances():
+                if isinstance(instance, plcopen.step):
+                    self.GenerateSFCSteps(instance, pou)
+                elif isinstance(instance, plcopen.actionBlock):
+                    self.GenerateSFCActions(instance, pou)
+                elif isinstance(instance, plcopen.transition):
+                    self.GenerateSFCTransitions(instance, pou)
+                elif isinstance(instance, plcopen.jumpStep):
+                    self.GenerateSFCJump(instance, pou)
+            for name, values in self.Steps.items():
+                if values['initial']:
+                    self.GenerateSFCStepOrder(name, [])
+            steps_type = "ARRAY [1..%d] OF BOOL"%len(self.Order)
+            if ("VAR", False, False) not in self.Interface:
+                self.Interface[("VAR", False, False)] = {}
+            if steps_type not in self.Interface[("VAR", False, False)]:
+                self.Interface[("VAR", False, False)][steps_type] = ["Steps"]
+            else:
+                self.Interface[("VAR", False, False)][steps_type].append("Steps")
+            for index, name in enumerate(self.Order):
+                values = self.Steps[name]
+                self.Program += "  IF Steps[%d] THEN\n"%index
+                for action in values["actions"]:
+                    if action["qualifier"] == "N":
+                        for line in action["content"].splitlines():
+                            self.Program += "  %s\n"%line
+                    elif action["qualifier"] == "S":
+                        if "R_TRIG" not in self.Interface[("VAR", False, False)]:
+                            self.Interface[("VAR", False, False)]["R_TRIG"] = []
+                        i = 1
+                        name = "R_TRIG%d"%i
+                        while name in self.Interface[("VAR", False, False)]["R_TRIG"]:
+                            i += 1
+                            name = "R_TRIG%d"%i
+                        self.Interface[("VAR", False, False)]["R_TRIG"].append(name)
+                        self.Program += "    IF %s(CLK := Steps[%d]) THEN\n"%(name, index)
+                        self.Program += "      %s := TRUE;\n"%action["content"]
+                for transition in values["transitions"]:
+                    if transition["compute"] != '':
+                        self.Program += "    %s %s"%(transition["condition"], transition["compute"])
+                    self.Program += "    IF %s THEN\n"%transition["condition"]
+                    for target in transition["targets"]:
+                        self.Program += "      Steps[%d] := TRUE;\n"%self.Order.index(target)
+                    self.Program += "      Steps[%d] := FALSE;\n"%index
+    
+    def ComputeFBDExpression(self, body, link):
+        localid = link.getRefLocalId()
+        instance = body.getContentInstance(localid)
+        if isinstance(instance, plcopen.inVariable):
+            return instance.getExpression()
+        elif isinstance(instance, plcopen.block):
+            name = instance.getInstanceName()
+            type = instance.getTypeName()
+            block_infos = GetBlockType(type)
+            if block_infos["type"] == "function":
+                vars = []
+                for variable in instance.inputVariables.getVariable():
+                    connections = variable.connectionPointIn.getConnections()
+                    if connections and len(connections) == 1:
+                        value = self.ComputeFBDExpression(body, connections[0])
+                        vars.append(self.ExtractModifier(variable, value))
+                variable = instance.outputVariables.getVariable()[0]
+                return self.ExtractModifier(variable, "%s(%s)"%(type, ", ".join(vars)))
+            elif block_infos["type"] == "functionBlock":
+                if ("VAR", False, False) not in self.Interface:
+                    self.Interface[("VAR", False, False)] = {}
+                if type not in self.Interface[("VAR", False, False)]:
+                    self.Interface[("VAR", False, False)][type] = []
+                if name not in self.Interface[("VAR", False, False)][type]:
+                    self.Interface[("VAR", False, False)][type].append(name)
+                    vars = []
+                    for variable in instance.inputVariables.getVariable():
+                        connections = variable.connectionPointIn.getConnections()
+                        if connections and len(connections) == 1:
+                            parameter = variable.getFormalParameter()
+                            value = self.ComputeFBDExpression(body, connections[0])
+                            vars.append(self.ExtractModifier(variable, "%s := %s"%(parameter, value)))
+                    self.Program += "  %s(%s);\n"%(name, ", ".join(vars))
+                connectionPoint = link.getPosition()[-1]
+                for variable in instance.outputVariables.getVariable():
+                    blockPointx, blockPointy = variable.connectionPointOut.getRelPosition()
+                    if instance.getX() + blockPointx == connectionPoint.getX() and instance.getY() + blockPointy == connectionPoint.getY():
+                        return self.ExtractModifier(variable, "%s.%s"%(name, variable.getFormalParameter()))
+                raise ValueError, "No output variable found"
+
+    def GenerateLDPaths(self, instance, body):
+        paths = []
+        variable = self.ExtractModifier(instance, instance.getVariable())
+        connections = instance.connectionPointIn.getConnections()
+        for connection in connections:
+            localId = connection.getRefLocalId()
+            next = body.getContentInstance(localId)
+            if isinstance(next, plcopen.leftPowerRail):
+                paths.append(None)
+            else:
+                paths.append(self.GenerateLDPaths(next, body))
+        if isinstance(instance, plcopen.coil):
+            if len(paths) > 1:
+                return tuple(paths)
+            else:
+                return paths
+        else:
+            if len(paths) > 1:
+                return [variable, tuple(paths)]
+            elif type(paths[0]) == ListType:
+                return [variable] + paths[0]
+            elif paths[0]:
+                return [variable, paths[0]]
+            else:
+                return variable
+
+    def GenerateSFCSteps(self, step, pou):
+        step_name = step.getName()
+        if step_name not in self.Steps:
+            step_infos = {"initial" : step.getInitialStep(), "transitions" : [], "actions" : []}
+            self.Steps[step_name] = step_infos
+            if step.connectionPointIn:
+                instances = []
+                connections = step.connectionPointIn.getConnections()
+                if len(connections) == 1:
+                    instanceLocalId = connections[0].getRefLocalId()
+                    instance = pou.body.getContentInstance(instanceLocalId)
+                    if isinstance(instance, plcopen.transition):
+                        self.GenerateSFCTransitions(instance, pou)
+                        instances.append(instance)
+                    elif isinstance(instance, plcopen.selectionConvergence):
+                        for connectionPointIn in instance.getConnectionPointIn():
+                            divergence_connections = connectionPointIn.getConnections()
+                            if len(divergence_connections) == 1:
+                                transitionLocalId = connections[0].getRefLocalId()
+                                transition = pou.body.getContentInstance(transitionLocalId)
+                                self.GenerateSFCTransitions(transition, pou)
+                                instances.append(transition)
+                for instance in instances:
+                    self.Transitions[instance]["targets"].append(step_name)
+    
+    def GenerateSFCJump(self, jump, pou):
+        jump_target = jump.getTargetName()
+        if jump.connectionPointIn:
+            instances = []
+            connections = jump.connectionPointIn.getConnections()
+            if len(connections) == 1:
+                instanceLocalId = connections[0].getRefLocalId()
+                instance = pou.body.getContentInstance(instanceLocalId)
+                if isinstance(instance, plcopen.transition):
+                    self.GenerateSFCTransitions(instance, pou)
+                    instances.append(instance)
+                elif isinstance(instance, plcopen.selectionConvergence):
+                    for connectionPointIn in instance.getConnectionPointIn():
+                        divergence_connections = connectionPointIn.getConnections()
+                        if len(divergence_connections) == 1:
+                            transitionLocalId = divergence_connections[0].getRefLocalId()
+                            transition = pou.body.getContentInstance(transitionLocalId)
+                            self.GenerateSFCTransitions(transition, pou)
+                            instances.append(transition)
+            for instance in instances:
+                self.Transitions[instance]["targets"].append(jump_target)
+    
+    def GenerateSFCActions(self, actionBlock, pou):
+        connections = actionBlock.connectionPointIn.getConnections()
+        if len(connections) == 1:
+            stepLocalId = connections[0].getRefLocalId()
+            step = pou.body.getContentInstance(stepLocalId)
+            step_name = step.getName()
+            if step_name not in self.Steps:
+                self.GenerateSFCSteps(step, pou)
+            if step_name in self.Steps:
+                actions = actionBlock.getActions()
+                for action in actions:
+                    action_infos = {"qualifier" : action["qualifier"], "content" : ""}
+                    if action["type"] == "inline":
+                        action_infos["content"] = action["value"]
+                    elif action["type"] == "reference":
+                        actionContent = pou.getAction(action["value"])
+                        if actionContent:
+                            actionType = actionContent.getBodyType()
+                            actionBody = actionContent.getBody()
+                            if actionType in ["ST", "IL"]:
+                                action_infos["content"] = actionContent.getText()
+                            elif actionType == "FBD":
+                                for instance in actionBody.getContentInstances():
+                                    if isinstance(instance, plcopen.outVariable):
+                                        var = instance.getExpression()
+                                        connections = instance.connectionPointIn.getConnections()
+                                        if connections and len(connections) == 1:
+                                            expression = self.ComputeFBDExpression(actionBody, connections[0])
+                                            action_infos["content"] = self.Program + "  %s := %s;"%(var, expression)
+                                            self.Program = ""
+                            elif actionType == "LD":
+                                for instance in actionbody.getContentInstances():
+                                    if isinstance(instance, plcopen.coil):
+                                        paths = self.GenerateLDPaths(instance, actionBody)
+                                        variable = self.ExtractModifier(instance, instance.getVariable())
+                                        expression = self.ComputeLDExpression(paths, True)
+                                        action_infos["content"] = self.Program + "  %s := %s;"%(variable, expression)
+                                        self.Program = ""
+                        else:
+                            action_infos["content"] = action["value"]
+                    self.Steps[step_name]["actions"].append(action_infos)
+                        
+    def GenerateSFCTransitions(self, transition, pou):
+        if transition not in self.Transitions:
+            connections = transition.connectionPointIn.getConnections()
+            if len(connections) == 1:
+                instanceLocalId = connections[0].getRefLocalId()
+                instance = pou.body.getContentInstance(instanceLocalId)
+                if isinstance(instance, plcopen.step):
+                    step_name = instance.getName()
+                    if step_name not in self.Steps:
+                        self.GenerateSFCSteps(instance, pou)
+                elif isinstance(instance, plcopen.selectionDivergence):
+                    divergence_connections = instance.connectionPointIn.getConnections()
+                    if len(divergence_connections) == 1:
+                        stepLocalId = divergence_connections[0].getRefLocalId()
+                        divergence_instance = pou.body.getContentInstance(stepLocalId)
+                        if isinstance(divergence_instance, plcopen.step):
+                            step_name = divergence_instance.getName()
+                            if step_name not in self.Steps:
+                                self.GenerateSFCSteps(divergence_instance, pou)
+                if step_name in self.Steps:
+                    transition_infos = {"targets" : []}
+                    transitionValues = transition.getConditionContent()
+                    transition_infos["condition"] = transitionValues["value"]
+                    if transitionValues["type"] == "inline":
+                        transition_infos["compute"] = ""
+                    else:
+                        transitionContent = pou.getTransition(transitionValues["value"])
+                        transitionType = transitionContent.getBodyType()
+                        transitionBody = transitionContent.getBody()
+                        if transitionType in ["ST", "IL"]:
+                            transition_infos["compute"] = "%s\n"%transitionContent.getText()
+                        elif conditionType == "FBD":
+                            for instance in conditionBody.getContentInstances():
+                                if isinstance(instance, plcopen.outVariable):
+                                    var = instance.getExpression()
+                                    connections = instance.connectionPointIn.getConnections()
+                                    if connections and len(connections) == 1:
+                                        expression = self.ComputeFBDExpression(actionBody, connections[0])
+                                        transition_infos["compute"] = self.Program + ":= %s;\n"%(var, expression)
+                                        self.Program = ""
+                        elif actionType == "LD":
+                            for instance in conditionbody.getContentInstances():
+                                if isinstance(instance, plcopen.coil):
+                                    paths = self.GenerateLDPaths(instance, conditionBody)
+                                    variable = self.ExtractModifier(instance, instance.getVariable())
+                                    expression = self.ComputeLDExpression(paths, True)
+                                    transition_infos["compute"] = self.Program + ":= %s;\n"%(variable, expression)
+                                    self.Program = ""
+                    self.Steps[step_name]["transitions"].append(transition_infos)
+                    self.Transitions[transition] = transition_infos
+
+    def GenerateSFCStepOrder(self, name, path):
+        self.Order.append(name)
+        for transition in self.Steps[name]["transitions"]:
+            for target in transition["targets"]:
+                if target not in self.Order or target not in path:
+                    if target in self.Order:
+                        self.Order.remove(target)
+                    self.GenerateSFCStepOrder(target, path + [name])
+
+    def ComputeLDExpression(self, paths, first = False):
+        if type(paths) == TupleType:
+            if None in paths:
+                return "TRUE"
+            else:
+                var = [self.ComputeLDExpression(path) for path in paths]
+                if first:
+                    return " OR ".join(var)
+                else:
+                    return "(%s)"%" OR ".join(var)
+        elif type(paths) == ListType:
+            var = [self.ComputeLDExpression(path) for path in paths]
+            return " AND ".join(var)
+        else:
+            return paths
+
+    def ExtractModifier(self, variable, text):
+        if variable.getNegated():
+            return "NOT(%s)"%text
+        else:
+            edge = variable.getEdge()
+            if edge:
+                if edge.getValue() == "rising":
+                    return self.AddTrigger("R_TRIG", text)
+                elif edge.getValue() == "falling":
+                    return self.AddTrigger("F_TRIG", text)
+        return text
+    
+    def AddTrigger(self, edge, text):
+        if ("VAR", False, False) not in self.Interface:
+            self.Interface[("VAR", False, False)] = {}
+        if type not in self.Interface[("VAR", False, False)]:
+            self.Interface[("VAR", False, False)][edge] = []
+        i = 1
+        name = "%s%d"%(edge, i)
+        while name in self.Interface[("VAR", False, False)][edge]:
+            i += 1
+            name = "%s%d"%(edge, i)
+        self.Interface[("VAR", False, False)][edge].append(name)
+        self.Program += "  %s(CLK := %s);\n"%(name, text)
+        return "%s.Q"%name
+    
+    def GenerateSTProgram(self):
+        program = ""
+        if "returnType" in self.Interface:
+            program += "%s %s : %s\n"%(self.Type, self.Name, self.Interface["returnType"])
+        else:
+            program += "%s %s\n"%(self.Type, self.Name)
+        for values, variables in self.Interface.items():
+            if values != "returnType":
+                program += "  %s"%values[0]
+                if values[1]:
+                    program += " RETAIN"
+                if values[2]:
+                    program += " CONSTANT"
+                program += "\n"
+                for vartype, list in variables.items():
+                    program += "    %s : %s;\n"%(", ".join(list), vartype)
+                program += "  END_%s\n"%values[0]
+        program += "\n"
+        program += self.Program
+        program += "END_%s\n\n"%self.Type
+        return program
+    
+def GenerateCurrentProgram(project):
+    program = ""
+    for pou in project.getPous():
+        pou_type = pou.getPouType().getValue()
+        if pou_type == "function":
+            pou_program = PouProgram(pou.getName(), "FUNCTION")
+        elif pou_type == "functionBlock":
+            pou_program = PouProgram(pou.getName(), "FUNCTION_BLOCK")
+        elif pou_type == "program":
+            pou_program = PouProgram(pou.getName(), "PROGRAM")
+        else:
+            raise ValueError, "Undefined pou type"
+        pou_program.GenerateInterface(pou.getInterface())
+        pou_program.GenerateProgram(pou)
+        program += pou_program.GenerateSTProgram()
+    return program
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PLCOpenEditor.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,2216 @@
+#Boa:Frame:PLCOpenEditor
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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 wxPython.wx import *
+from wxPython.grid import *
+from time import localtime
+from datetime import datetime
+import wx
+
+from SFCViewer import *
+from FBDViewer import *
+from LDViewer import *
+from Viewer import *
+from PLCControler import *
+from plcopen import OpenPDFDoc
+from plcopen.structures import *
+
+import os, re, platform, sys, time, traceback, getopt
+
+__version__ = "$Revision$"
+
+def create(parent):
+    return PLCOpenEditor(parent)
+
+def usage():
+    print "\nUsage of PLCOpenEditor.py :"
+    print "\n   %s [Filepath]\n"%sys.argv[0]
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
+except getopt.GetoptError:
+    # print help information and exit:
+    usage()
+    sys.exit(2)
+
+for o, a in opts:
+    if o in ("-h", "--help"):
+        usage()
+        sys.exit()
+
+fileOpen = None
+if len(args) > 1:
+    usage()
+    sys.exit()
+elif len(args) == 1:
+    fileOpen = args[0]
+
+
+# Test if identifier is valid
+def TestIdentifier(identifier):
+     if identifier[0].isdigit():
+        return False
+     words = identifier.split('_')
+     for i, word in enumerate(words):
+         if len(word) == 0 and i != 0:
+             return False
+         if len(word) != 0 and not word.isalnum():
+             return False
+     return True
+
+[wxID_PLCOPENEDITOR, wxID_PLCOPENEDITORPROJECTTREE, 
+ wxID_PLCOPENEDITORSPLITTERWINDOW1, wxID_PLCOPENEDITORTABSOPENED,
+ wxID_PLCOPENEDITORDEFAULTTOOLBAR, wxID_PLCOPENEDITORSFCTOOLBAR,
+ wxID_PLCOPENEDITORFBDTOOLBAR, wxID_PLCOPENEDITORLDTOOLBAR,
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+[wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0, 
+] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(1)]
+
+[wxID_PLCOPENEDITORSFCTOOLBARITEMS0, wxID_PLCOPENEDITORSFCTOOLBARITEMS1, 
+ wxID_PLCOPENEDITORSFCTOOLBARITEMS2, wxID_PLCOPENEDITORSFCTOOLBARITEMS3, 
+ wxID_PLCOPENEDITORSFCTOOLBARITEMS4, wxID_PLCOPENEDITORSFCTOOLBARITEMS5,
+ wxID_PLCOPENEDITORSFCTOOLBARITEMS6,
+] = [wx.NewId() for _init_coll_SFCToolBar_Items in range(7)]
+
+[wxID_PLCOPENEDITORFBDTOOLBARITEMS0, wxID_PLCOPENEDITORFBDTOOLBARITEMS1, 
+ wxID_PLCOPENEDITORFBDTOOLBARITEMS2, wxID_PLCOPENEDITORFBDTOOLBARITEMS3, 
+ wxID_PLCOPENEDITORFBDTOOLBARITEMS4, wxID_PLCOPENEDITORFBDTOOLBARITEMS5,
+] = [wx.NewId() for _init_coll_FBDToolBar_Items in range(6)]
+
+[wxID_PLCOPENEDITORLDTOOLBARITEMS0, wxID_PLCOPENEDITORLDTOOLBARITEMS1, 
+ wxID_PLCOPENEDITORLDTOOLBARITEMS2, wxID_PLCOPENEDITORLDTOOLBARITEMS3, 
+ wxID_PLCOPENEDITORLDTOOLBARITEMS4,
+] = [wx.NewId() for _init_coll_LDToolBar_Items in range(5)]
+
+[wxID_PLCOPENEDITORFILEMENUITEMS0, wxID_PLCOPENEDITORFILEMENUITEMS1, 
+ wxID_PLCOPENEDITORFILEMENUITEMS2, wxID_PLCOPENEDITORFILEMENUITEMS3, 
+ wxID_PLCOPENEDITORFILEMENUITEMS5, wxID_PLCOPENEDITORFILEMENUITEMS6, 
+ wxID_PLCOPENEDITORFILEMENUITEMS7, wxID_PLCOPENEDITORFILEMENUITEMS9, 
+ wxID_PLCOPENEDITORFILEMENUITEMS11,
+] = [wx.NewId() for _init_coll_FileMenu_Items in range(9)]
+
+[wxID_PLCOPENEDITORHELPMENUITEMS0, wxID_PLCOPENEDITORHELPMENUITEMS1, 
+ wxID_PLCOPENEDITORHELPMENUITEMS2, wxID_PLCOPENEDITORHELPMENUITEMS3, 
+] = [wx.NewId() for _init_coll_HelpMenu_Items in range(4)]
+
+[wxID_PLCOPENEDITORSFCMENUITEMS0, wxID_PLCOPENEDITORSFCMENUITEMS1, 
+ wxID_PLCOPENEDITORSFCMENUITEMS2, wxID_PLCOPENEDITORSFCMENUITEMS3,
+] = [wx.NewId() for _init_coll_HelpMenu_Items in range(4)]
+
+[wxID_PLCOPENEDITORCONFIGMENUITEMS0, wxID_PLCOPENEDITORCONFIGMENUITEMS1, 
+] = [wx.NewId() for _init_coll_HelpMenu_Items in range(2)]
+
+[wxID_PLCOPENEDITOREDITMENUITEMS0, wxID_PLCOPENEDITOREDITMENUITEMS1, 
+ wxID_PLCOPENEDITOREDITMENUITEMS11, wxID_PLCOPENEDITOREDITMENUITEMS12, 
+ wxID_PLCOPENEDITOREDITMENUITEMS2, wxID_PLCOPENEDITOREDITMENUITEMS4, 
+ wxID_PLCOPENEDITOREDITMENUITEMS5, wxID_PLCOPENEDITOREDITMENUITEMS6, 
+ wxID_PLCOPENEDITOREDITMENUITEMS8, wxID_PLCOPENEDITOREDITMENUITEMS9, 
+] = [wx.NewId() for _init_coll_EditMenu_Items in range(10)]
+
+[wxID_PLCOPENEDITORSFCMENUITEMS0, wxID_PLCOPENEDITORSFCMENUITEMS1, 
+ wxID_PLCOPENEDITORSFCMENUITEMS2, wxID_PLCOPENEDITORSFCMENUITEMS3, 
+] = [wx.NewId() for _init_coll_SFCMenu_Items in range(4)]
+
+[wxID_PLCOPENEDITORCONFIGMENUITEMS0, wxID_PLCOPENEDITORCONFIGMENUITEMS1, 
+] = [wx.NewId() for _init_coll_ConfigMenu_Items in range(2)]
+
+class PLCOpenEditor(wx.Frame):
+    _custom_classes = {'wx.SashWindow' : ['Viewer']}
+    
+    def _init_coll_EditMenu_Items(self, parent):
+        # generated method, don't edit
+
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS0,
+              kind=wx.ITEM_NORMAL, text=u'Refresh\tCTRL+R')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS1,
+              kind=wx.ITEM_NORMAL, text=u'Undo\tCTRL+Z')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS2,
+              kind=wx.ITEM_NORMAL, text=u'Redo\tCTRL+Y')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS4,
+              kind=wx.ITEM_NORMAL, text=u'Cut\tCTRL+X')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS5,
+              kind=wx.ITEM_NORMAL, text=u'Copy\tCTRL+C')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS6,
+              kind=wx.ITEM_NORMAL, text=u'Paste\tCTRL+V')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS8,
+              kind=wx.ITEM_NORMAL, text=u'Add POU')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS9,
+              kind=wx.ITEM_NORMAL, text=u'Remove POU')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS11,
+              kind=wx.ITEM_NORMAL, text=u'Add Configuration')
+        parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS12,
+              kind=wx.ITEM_NORMAL, text=u'Remove Configuration')
+        self.Bind(wx.EVT_MENU, self.OnRefreshMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS0)
+        self.Bind(wx.EVT_MENU, self.OnCutMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS4)
+        self.Bind(wx.EVT_MENU, self.OnCopyMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS5)
+        self.Bind(wx.EVT_MENU, self.OnPasteMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS6)
+        self.Bind(wx.EVT_MENU, self.OnAddPouMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS8)
+        self.Bind(wx.EVT_MENU, self.OnRemovePouMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS9)
+        self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS11)
+        self.Bind(wx.EVT_MENU, self.OnRemoveConfigurationMenu,
+              id=wxID_PLCOPENEDITOREDITMENUITEMS12)
+
+    def _init_coll_menuBar1_Menus(self, parent):
+        # generated method, don't edit
+
+        parent.Append(menu=self.FileMenu, title=u'File')
+        parent.Append(menu=self.EditMenu, title=u'Edit')
+        parent.Append(menu=self.HelpMenu, title=u'Help')
+
+    def _init_coll_ConfigMenu_Items(self, parent):
+        # generated method, don't edit
+
+        parent.Append(help='', id=wxID_PLCOPENEDITORCONFIGMENUITEMS0,
+              kind=wx.ITEM_NORMAL, text=u'Add Resource')
+        parent.Append(help='', id=wxID_PLCOPENEDITORCONFIGMENUITEMS1,
+              kind=wx.ITEM_NORMAL, text=u'Remove Resource')
+        self.Bind(wx.EVT_MENU, self.OnAddResourceMenu,
+              id=wxID_PLCOPENEDITORCONFIGMENUITEMS0)
+        self.Bind(wx.EVT_MENU, self.OnRemoveResourceMenu,
+              id=wxID_PLCOPENEDITORCONFIGMENUITEMS1)
+
+    def _init_coll_HelpMenu_Items(self, parent):
+        # generated method, don't edit
+
+        parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS0,
+              kind=wx.ITEM_NORMAL, text=u'PLCOpenEditor\tF1')
+        parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS1,
+              kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2')
+        parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS2,
+              kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3')
+        parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS3,
+              kind=wx.ITEM_NORMAL, text=u'About')
+        self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu,
+              id=wxID_PLCOPENEDITORHELPMENUITEMS1)
+
+    def _init_coll_FileMenu_Items(self, parent):
+        # generated method, don't edit
+
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS0,
+              kind=wx.ITEM_NORMAL, text=u'New\tCTRL+N')
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS1,
+              kind=wx.ITEM_NORMAL, text=u'Open\tCTRL+O')
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS2,
+              kind=wx.ITEM_NORMAL, text=u'Close Tab\tCTRL+W')
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS3,
+              kind=wx.ITEM_NORMAL, text=u'Close Project')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS5,
+              kind=wx.ITEM_NORMAL, text=u'Save\tCTRL+S')
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS6,
+              kind=wx.ITEM_NORMAL, text=u'Save As...\tCTRL+SHIFT+S')
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS7,
+              kind=wx.ITEM_NORMAL, text=u'Generate Program\tCTRL+G')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS9,
+              kind=wx.ITEM_NORMAL, text=u'Properties')
+        parent.AppendSeparator()
+        parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS11,
+              kind=wx.ITEM_NORMAL, text=u'Quit\tCTRL+Q')
+        self.Bind(wx.EVT_MENU, self.OnNewProjectMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS0)
+        self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS1)
+        self.Bind(wx.EVT_MENU, self.OnCloseTabMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS2)
+        self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS3)
+        self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS5)
+        self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS6)
+        self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS7)
+        self.Bind(wx.EVT_MENU, self.OnQuitMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS11)
+
+    def _init_coll_SFCMenu_Items(self, parent):
+        # generated method, don't edit
+
+        parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS0,
+              kind=wx.ITEM_NORMAL, text=u'Add Transition')
+        parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS1,
+              kind=wx.ITEM_NORMAL, text=u'Add Action')
+        parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS2,
+              kind=wx.ITEM_NORMAL, text=u'Remove Transition')
+        parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS3,
+              kind=wx.ITEM_NORMAL, text=u'Remove Action')
+        self.Bind(wx.EVT_MENU, self.OnAddPouTransitionMenu,
+              id=wxID_PLCOPENEDITORSFCMENUITEMS0)
+        self.Bind(wx.EVT_MENU, self.OnAddPouActionMenu,
+              id=wxID_PLCOPENEDITORSFCMENUITEMS1)
+        self.Bind(wx.EVT_MENU, self.OnRemovePouTransitionMenu,
+              id=wxID_PLCOPENEDITORSFCMENUITEMS2)
+        self.Bind(wx.EVT_MENU, self.OnRemovePouActionMenu,
+              id=wxID_PLCOPENEDITORSFCMENUITEMS3)
+
+    def _init_utils(self):
+        # generated method, don't edit
+        self.menuBar1 = wx.MenuBar()
+
+        self.FileMenu = wx.Menu(title=u'')
+
+        self.EditMenu = wx.Menu(title=u'')
+
+        self.HelpMenu = wx.Menu(title='')
+
+        self.SFCMenu = wx.Menu(title='')
+
+        self.ConfigMenu = wx.Menu(title='')
+
+        self._init_coll_menuBar1_Menus(self.menuBar1)
+        self._init_coll_FileMenu_Items(self.FileMenu)
+        self._init_coll_EditMenu_Items(self.EditMenu)
+        self._init_coll_HelpMenu_Items(self.HelpMenu)
+        self._init_coll_SFCMenu_Items(self.SFCMenu)
+        self._init_coll_ConfigMenu_Items(self.ConfigMenu)
+
+    def _init_coll_MainGridSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.splitterWindow1, 0, border=0, flag=wxGROW)
+
+    def _init_coll_MainGridSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0)
+
+        self._init_coll_MainGridSizer_Growables(self.MainGridSizer)
+        self._init_coll_MainGridSizer_Items(self.MainGridSizer)
+
+        self.SetSizer(self.MainGridSizer)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Frame.__init__(self, id=wxID_PLCOPENEDITOR, name=u'PLCOpenEditor',
+              parent=prnt, pos=wx.Point(235, 287), size=wx.Size(1000, 600),
+              style=wx.DEFAULT_FRAME_STYLE, title=u'PLCOpenEditor')
+        self._init_utils()
+        self.SetClientSize(wx.Size(1000, 600))
+        self.SetMenuBar(self.menuBar1)
+        self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
+              id=wxID_PLCOPENEDITORPROJECTTREE)
+        self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnProjectTreeItemEndEdit,
+              id=wxID_PLCOPENEDITORPROJECTTREE)
+        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated,
+              id=wxID_PLCOPENEDITORPROJECTTREE)
+        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected,
+              id=wxID_PLCOPENEDITORPROJECTTREE)
+        
+        self.splitterWindow1 = wx.SplitterWindow(id=wxID_PLCOPENEDITORSPLITTERWINDOW1,
+              name='splitterWindow1', parent=self, point=wx.Point(0, 0),
+              size=wx.Size(-1, -1), style=wx.SP_3D)
+        self.splitterWindow1.SetNeedUpdating(True)
+        self.splitterWindow1.SetMinimumPaneSize(1)
+
+        self.TabsOpened = wx.Notebook(id=wxID_PLCOPENEDITORTABSOPENED,
+              name='TabsOpened', parent=self.splitterWindow1, pos=wx.Point(0,
+              0), size=wx.Size(-1, -1), style=0)
+        self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
+              self.OnPouSelectedChanged, id=wxID_PLCOPENEDITORTABSOPENED)
+
+        self.ProjectTree = wx.TreeCtrl(id=wxID_PLCOPENEDITORPROJECTTREE,
+              name='treeCtrl1', parent=self.splitterWindow1, pos=wx.Point(0, 0),
+              size=wx.Size(-1, -1),
+              style=wx.TR_HAS_BUTTONS|wx.TR_EDIT_LABELS|wx.TR_SINGLE|wx.SUNKEN_BORDER)
+        self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
+        self.splitterWindow1.SplitVertically(self.ProjectTree, self.TabsOpened,
+              200)
+              
+        self._init_sizers()
+
+    def init_coll_DefaultToolBar_Items(self, parent):
+        parent.AddRadioTool(wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0, 
+              wxBitmap('Images/select.png'), wxNullBitmap, "Select an object")
+        self.Bind(wx.EVT_TOOL, self.OnSelectionTool, 
+              id=wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0)
+
+    def init_coll_SFCToolBar_Items(self, parent):
+        parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS0, 
+              wxBitmap('Images/select.png'), wxNullBitmap, "Select an object")
+        parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS1, 
+              wxBitmap('Images/comment.png'), wxNullBitmap, "Create a new comment")
+        parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS2, 
+              wxBitmap('Images/initial_step.png'), wxNullBitmap, "Create a new initial step")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS3, 
+              wxBitmap('Images/step.png'), "Create a new step")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS4, 
+              wxBitmap('Images/action.png'), "Add action block to step")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS5, 
+              wxBitmap('Images/divergence.png'), "Create a new divergence")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS6, 
+              wxBitmap('Images/jump.png'), "Create a new jump")
+        self.Bind(wx.EVT_TOOL, self.OnSelectionTool, 
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS0)
+        self.Bind(wx.EVT_TOOL, self.OnCommentTool, 
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS1)
+        self.Bind(wx.EVT_TOOL, self.OnSFCInitialStepTool,
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS2)
+        self.Bind(wx.EVT_TOOL, self.OnSFCStepTool,
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS3)
+        self.Bind(wx.EVT_TOOL, self.OnSFCActionBlockTool,
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS4)
+        self.Bind(wx.EVT_TOOL, self.OnSFCDivergenceTool,
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS5)
+        self.Bind(wx.EVT_TOOL, self.OnSFCJumpTool,
+              id=wxID_PLCOPENEDITORSFCTOOLBARITEMS6)
+
+    def init_coll_FBDToolBar_Items(self, parent):
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS0, 
+              wxBitmap('Images/select.png'), wxNullBitmap, "Select an object")
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS1, 
+              wxBitmap('Images/comment.png'), wxNullBitmap, "Create a new comment")
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS2, 
+              wxBitmap('Images/variable.png'), wxNullBitmap, "Create a new variable")
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS3, 
+              wxBitmap('Images/block.png'), wxNullBitmap, "Create a new block")
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS4, 
+              wxBitmap('Images/connection.png'), wxNullBitmap, "Create a new connection")
+        parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS5, 
+              wxBitmap('Images/wire.png'), wxNullBitmap, "Create a new wire")
+        self.Bind(wx.EVT_TOOL, self.OnSelectionTool, 
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS0)
+        self.Bind(wx.EVT_TOOL, self.OnCommentTool, 
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS1)
+        self.Bind(wx.EVT_TOOL, self.OnFBDVariableTool,
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS2)
+        self.Bind(wx.EVT_TOOL, self.OnFBDBlockTool,
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS3)
+        self.Bind(wx.EVT_TOOL, self.OnFBDConnectionTool, 
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS4)
+        self.Bind(wx.EVT_TOOL, self.OnWireTool, 
+              id=wxID_PLCOPENEDITORFBDTOOLBARITEMS5)
+    
+    def init_coll_LDToolBar_Items(self, parent):
+        parent.AddRadioTool(wxID_PLCOPENEDITORLDTOOLBARITEMS0, 
+              wxBitmap('Images/select.png'), wxNullBitmap, "Select an object")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS1, 
+              wxBitmap('Images/coil.png'), "Create a new rung")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS2, 
+              wxBitmap('Images/contact.png'), "Create a new contact")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS3, 
+              wxBitmap('Images/block.png'), "Create a new block")
+        parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS4, 
+              wxBitmap('Images/branch.png'), "Create a new branch")
+        self.Bind(wx.EVT_TOOL, self.OnSelectionTool, 
+              id=wxID_PLCOPENEDITORLDTOOLBARITEMS0)
+        self.Bind(wx.EVT_TOOL, self.OnLDCoilTool,
+              id=wxID_PLCOPENEDITORLDTOOLBARITEMS1)
+        self.Bind(wx.EVT_TOOL, self.OnLDContactTool,
+              id=wxID_PLCOPENEDITORLDTOOLBARITEMS2)
+        self.Bind(wx.EVT_TOOL, self.OnLDBlockTool, 
+              id=wxID_PLCOPENEDITORLDTOOLBARITEMS3)
+        self.Bind(wx.EVT_TOOL, self.OnLDBranchTool, 
+              id=wxID_PLCOPENEDITORLDTOOLBARITEMS4)
+    
+    def init_toolbars(self, parent):
+        self.DefaultToolBar = wxToolBar(id=wxID_PLCOPENEDITORDEFAULTTOOLBAR, name='DefaultToolBar',
+              parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0),
+              style=wxTB_HORIZONTAL | wxNO_BORDER)
+
+        self.SFCToolBar = wxToolBar(id=wxID_PLCOPENEDITORSFCTOOLBAR, name='SFCToolBar',
+              parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0),
+              style=wxTB_HORIZONTAL | wxNO_BORDER)
+        
+        self.FBDToolBar = wxToolBar(id=wxID_PLCOPENEDITORFBDTOOLBAR, name='FBDToolBar',
+              parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0),
+              style=wxTB_HORIZONTAL | wxNO_BORDER)
+        
+        self.LDToolBar = wxToolBar(id=wxID_PLCOPENEDITORLDTOOLBAR, name='LDToolBar',
+              parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0),
+              style=wxTB_HORIZONTAL | wxNO_BORDER)
+              
+        self.init_coll_DefaultToolBar_Items(self.DefaultToolBar)
+        self.init_coll_SFCToolBar_Items(self.SFCToolBar)
+        self.init_coll_FBDToolBar_Items(self.FBDToolBar)
+        self.init_coll_LDToolBar_Items(self.LDToolBar)
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.init_toolbars(self)
+        
+        self.Controler = PLCControler()
+        
+        if fileOpen:
+            self.Controler.OpenXMLFile(fileOpen)
+            self.RefreshProjectTree()
+
+        self.RefreshFileMenu()
+        self.RefreshEditMenu()
+        self.RefreshToolBar()
+
+    def RefreshFileMenu(self):
+        if self.Controler.HasOpenedProject():
+            if self.TabsOpened.GetPageCount() > 0:
+                self.FileMenu.FindItemByPosition(2).Enable(True)
+            else:
+                self.FileMenu.FindItemByPosition(2).Enable(False)
+            self.FileMenu.FindItemByPosition(3).Enable(True)
+            self.FileMenu.FindItemByPosition(5).Enable(True)
+            self.FileMenu.FindItemByPosition(6).Enable(True)
+            self.FileMenu.FindItemByPosition(7).Enable(True)
+            self.FileMenu.FindItemByPosition(9).Enable(True)
+        else:
+            self.FileMenu.FindItemByPosition(2).Enable(False)
+            self.FileMenu.FindItemByPosition(3).Enable(False)
+            self.FileMenu.FindItemByPosition(5).Enable(False)
+            self.FileMenu.FindItemByPosition(6).Enable(False)
+            self.FileMenu.FindItemByPosition(7).Enable(False)
+            self.FileMenu.FindItemByPosition(9).Enable(False)
+
+    def RefreshEditMenu(self):
+        self.EditMenu.FindItemByPosition(1).Enable(False)
+        self.EditMenu.FindItemByPosition(2).Enable(False)
+        if self.Controler.HasOpenedProject():
+            if self.TabsOpened.GetPageCount() > 0:
+                self.EditMenu.FindItemByPosition(0).Enable(True)
+            else:
+                self.EditMenu.FindItemByPosition(0).Enable(False)
+            self.EditMenu.FindItemByPosition(8).Enable(True)
+            self.EditMenu.FindItemByPosition(9).Enable(True)
+        else:
+            self.EditMenu.FindItemByPosition(0).Enable(False)
+            self.EditMenu.FindItemByPosition(8).Enable(False)
+            self.EditMenu.FindItemByPosition(9).Enable(False)
+        bodytype = self.Controler.GetCurrentElementEditingBodyType()
+        if bodytype in ["LD","ST"]:
+            self.EditMenu.FindItemByPosition(4).Enable(True)
+            self.EditMenu.FindItemByPosition(5).Enable(True)
+            self.EditMenu.FindItemByPosition(6).Enable(True)
+        else:
+            self.EditMenu.FindItemByPosition(4).Enable(False)
+            self.EditMenu.FindItemByPosition(5).Enable(False)
+            self.EditMenu.FindItemByPosition(6).Enable(False)
+
+    def OnNewProjectMenu(self, event):
+        dialog = ProjectDialog(self)
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            projectname = values.pop("projectName")
+            values["creationDateTime"] = datetime(*localtime()[:6])
+            self.Controler.CreateNewProject(projectname)
+            self.Controler.SetProjectProperties(values)
+            self.RefreshFileMenu()
+            self.RefreshEditMenu()
+            self.RefreshProjectTree()
+        event.Skip()
+
+    def OnOpenProjectMenu(self, event):
+        filepath = self.Controler.GetFilePath()
+        if filepath != "":
+            directory = os.path.dirname(filepath)
+        else:
+            directory = os.getcwd()
+        dialog = wxFileDialog(self, "Choose a file", directory, "",  "PLCOpen files (*.xml)|*.xml|All files|*.*", wxOPEN)
+        if dialog.ShowModal() == wxID_OK:
+            filepath = dialog.GetPath()
+            if os.path.isfile(filepath):
+                self.Controler.OpenXMLFile(filepath)
+                self.TabsOpened.DeleteAllPages()
+                self.RefreshProjectTree()
+            self.RefreshFileMenu()
+            self.RefreshEditMenu()
+            self.RefreshToolBar()
+        dialog.Destroy()
+        event.Skip()
+
+    def OnCloseTabMenu(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected >= 0:
+            self.Controler.CloseElementEditing()
+            self.TabsOpened.DeletePage(selected)
+            if self.TabsOpened.GetPageCount() > 0:
+                self.TabsOpened.SetSelection(min(selected, self.TabsOpened.GetPageCount() - 1))
+            self.RefreshFileMenu()
+            self.RefreshEditMenu()
+            self.RefreshToolBar()
+        event.Skip()
+    
+    def OnCloseProjectMenu(self, event):
+        self.Controler.Reset()
+        self.TabsOpened.DeleteAllPages()
+        self.ProjectTree.DeleteAllItems()
+        self.RefreshFileMenu()
+        self.RefreshEditMenu()
+        self.RefreshToolBar()
+        event.Skip()
+
+    def OnSaveProjectMenu(self, event):
+        self.SaveProject()
+        event.Skip()
+
+    def OnSaveProjectAsMenu(self, event):
+        self.SaveProjectAs()
+        event.Skip()
+
+    def OnGenerateProgramMenu(self, event):
+        self.Controler.GenerateProgram()
+        event.Skip()
+
+    def SaveProject(self):
+        result = self.Controler.SaveXMLFile()
+        if not result:
+            self.SaveProjectAs()
+    
+    def SaveProjectAs(self):
+        filepath = self.Controler.GetFilePath()
+        if filepath != "":
+            directory, filename = os.path.split(filepath)
+        else:
+            directory, filename = os.getcwd(), "%s.od"%self.Controler.GetProjectName()
+        dialog = wxFileDialog(self, "Choose a file", directory, filename,  "PLCOpen files (*.xml)|*.xml|All files|*.*", wxSAVE|wxOVERWRITE_PROMPT)
+        if dialog.ShowModal() == wxID_OK:
+            filepath = dialog.GetPath()
+            if os.path.isdir(os.path.dirname(filepath)):
+                result = self.Controler.SaveXMLFile(filepath)
+                if not result:
+                    message = wxMessageDialog(self, "Can't save project to file %s!"%filepath, "Error", wxOK|wxICON_ERROR)
+                    message.ShowModal()
+                    message.Destroy()
+            else:
+                message = wxMessageDialog(self, "%s is not a valid folder!"%os.path.dirname(filepath), "Error", wxOK|wxICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+        dialog.Destroy()
+
+    def OnQuitMenu(self, event):
+        self.Close()
+        event.Skip()
+
+    def OnSelectionTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_SELECTION)
+        event.Skip()
+    
+    def OnCommentTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT)
+        event.Skip()
+
+    def OnWireTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_WIRE)
+        event.Skip()
+    
+    def OnSFCInitialStepTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_INITIAL_STEP)
+        event.Skip()
+    
+    def OnSFCStepTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddStep()
+        event.Skip()
+
+    def OnSFCActionBlockTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddStepAction()
+        event.Skip()
+
+    def OnSFCDivergenceTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddDivergence()
+        event.Skip()
+    
+    def OnSFCJumpTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddJump()
+        event.Skip()
+    
+    def OnFBDVariableTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_VARIABLE)
+        event.Skip()
+    
+    def OnFBDBlockTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_BLOCK)
+        event.Skip()
+        
+    def OnFBDConnectionTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_CONNECTION)
+        event.Skip()
+
+    def OnLDCoilTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddRung()
+        event.Skip()
+    
+    def OnLDContactTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddContact()
+        event.Skip()
+    
+    def OnLDBlockTool(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            pass
+        event.Skip()
+    
+    def OnLDBranchTool(self, event): 
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).AddBranch()
+        event.Skip()
+        
+    def OnPouSelectedChanged(self, event):
+        selected = event.GetSelection()
+        if selected >= 0:
+            self.Controler.RefreshCurrentElementEditing(selected)
+            found = False
+            name = self.TabsOpened.GetPageText(selected)
+            root = self.ProjectTree.GetRootItem()
+            item, root_cookie = self.ProjectTree.GetFirstChild(root)
+            while item.IsOk() and not found:
+                if self.ProjectTree.GetItemText(item) == name:
+                    self.ProjectTree.SelectItem(item)
+                item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+            self.RefreshFileMenu()
+            self.RefreshEditMenu()
+            self.RefreshToolBar()
+        event.Skip()
+
+    def OnProjectTreeItemEndEdit(self, event):
+        new_name = event.GetLabel()
+        if new_name != "":
+            if TestIdentifier(new_name):
+                item = event.GetItem()
+                itemtype = self.ProjectTree.GetPyData(item)
+                if itemtype == ITEM_PROJECT:
+                    self.Controler.SetProjectName(new_name)
+                elif itemtype == ITEM_POU:
+                    old_name = self.ProjectTree.GetItemText(item)
+                    self.Controler.ChangePouName(old_name, new_name)
+                    self.RefreshTabsOpenedTitles()
+                elif itemtype == ITEM_TRANSITION:
+                    old_name = self.ProjectTree.GetItemText(item)
+                    parent = self.ProjectTree.GetItemParent(item)
+                    grandparent = self.ProjectTree.GetItemParent(parent)
+                    grandparent_name = self.ProjectTree.GetItemText(grandparent)
+                    self.Controler.ChangePouTransitionName(grandparent_name, old_name, new_name)
+                    self.RefreshTabsOpenedTitles()
+                elif itemtype == ITEM_ACTION:
+                    old_name = self.ProjectTree.GetItemText(item)
+                    parent = self.ProjectTree.GetItemParent(item)
+                    grandparent = self.ProjectTree.GetItemParent(parent)
+                    grandparent_name = self.ProjectTree.GetItemText(grandparent)
+                    self.Controler.ChangePouActionName(grandparent_name, old_name, new_name)
+                    self.RefreshTabsOpenedTitles()
+                wxCallAfter(self.RefreshProjectTree)
+                event.Skip()
+            else:
+                message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%new_name, "Error", wxOK|wxICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+                item = event.GetItem()
+                wxCallAfter(self.ProjectTree.EditLabel, item)
+                event.Veto()
+
+    def OnProjectTreeItemBeginEdit(self, event):
+        selected = event.GetItem()
+        if self.ProjectTree.GetPyData(selected) == ITEM_UNEDITABLE:
+            event.Veto()
+        else:
+            event.Skip()
+    
+    def OnProjectTreeItemActivated(self, event):
+        selected = event.GetItem()
+        if self.ProjectTree.IsExpanded(selected):
+            self.ProjectTree.Collapse(selected)
+        else:
+            self.ProjectTree.Expand(selected)
+        name = self.ProjectTree.GetItemText(selected)
+        data = self.ProjectTree.GetPyData(selected)
+        if name == "Properties":
+            old_values = self.Controler.GetProjectProperties()
+            old_values["projectName"] = self.Controler.GetProjectName()
+            dialog = ProjectDialog(self)
+            dialog.SetValues(old_values)
+            if dialog.ShowModal() == wxID_OK:
+                new_values = dialog.GetValues()
+                projectname = new_values.pop("projectName")
+                new_values["creationDateTime"] = old_values["creationDateTime"]
+                self.Controler.SetProjectName(projectname)
+                self.Controler.SetProjectProperties(new_values)
+                self.RefreshProjectTree()
+            dialog.Destroy()
+        elif data == ITEM_CLASS:
+            item = self.ProjectTree.GetItemParent(selected)
+            item_type = self.ProjectTree.GetPyData(item)
+            while item_type != ITEM_POU:
+                item = self.ProjectTree.GetItemParent(item)
+                item_type = self.ProjectTree.GetPyData(item)
+            pou_name = self.ProjectTree.GetItemText(item)
+            dialog = EditVariableDialog(self, pou_name, self.Controler.GetPouType(pou_name), name)
+            values = {}
+            values["returnType"] = self.Controler.GetPouInterfaceReturnTypeByName(pou_name)
+            values["data"] = self.Controler.GetPouInterfaceVarsByName(pou_name)
+            dialog.SetValues(values)
+            if dialog.ShowModal() == wxID_OK:
+                if not self.Controler.PouIsUsed(pou_name):
+                    new_values = dialog.GetValues()
+                    if "returnType" in new_values:
+                        self.Controler.SetPouInterfaceReturnType(pou_name, new_values["returnType"])
+                    self.Controler.SetPouInterfaceVars(pou_name, new_values["data"])
+                    pou_names = self.Controler.GetElementsOpenedNames()
+                    if pou_name in pou_names:
+                        window = self.TabsOpened.GetPage(pou_names.index(pou_name))
+                        if isinstance(window, TextViewer):
+                            varlist = []
+                            if "returnType" in new_values:
+                                varlist.append(name)
+                            for var in new_values["data"]:
+                                varlist.append(var["Name"])
+                            window.SetVariables(varlist)
+                else:
+                    message = wxMessageDialog(self, "\"%s\" is used by one or more POUs. Its interface can't be changed!"%pou_name, "Error", wxOK|wxICON_ERROR)
+                    message.ShowModal()
+                    message.Destroy()
+            dialog.Destroy()
+        elif name == "Global Vars":
+            parent = self.ProjectTree.GetItemParent(selected)
+            parent_name = self.ProjectTree.GetItemText(parent)
+            dialog = EditVariableDialog(self, parent_name, None)
+            if self.ProjectTree.GetPyData(parent) == ITEM_CONFIGURATION:
+                values = {"data" : self.Controler.GetConfigurationGlobalVars(parent_name)}
+                dialog.SetValues(values)
+                if dialog.ShowModal() == wxID_OK:
+                    new_values = dialog.GetValues()
+                    self.Controler.SetConfigurationGlobalVars(parent_name, new_values["data"])
+            else:
+                config = self.ProjectTree.GetItemParent(parent)
+                config_name = self.ProjectTree.GetItemText(config)
+                values = {"data" : self.Controler.GetConfigurationResourceGlobalVars(config_name, parent_name)}
+                dialog.SetValues(values)
+                if dialog.ShowModal() == wxID_OK:
+                    new_values = dialog.GetValues()
+                    self.Controler.SetConfigurationResourceGlobalVars(config_name, parent_name, new_values["data"])
+        elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
+            if data == ITEM_POU:
+                idx = self.Controler.OpenElementEditing(name)
+                language = self.Controler.GetPouBodyType(name)
+                varlist = []
+                returnType = self.Controler.GetPouInterfaceReturnTypeByName(name)
+                if returnType:
+                    varlist.append(name)
+                vars = self.Controler.GetPouInterfaceVarsByName(name)
+                if vars:
+                    for var in vars:
+                        varlist.append(var["Name"])
+            else:
+                parent = self.ProjectTree.GetItemParent(selected)
+                parent_name = self.ProjectTree.GetItemText(parent)
+                grandparent = self.ProjectTree.GetItemParent(parent)
+                grandparent_name = self.ProjectTree.GetItemText(grandparent)
+                if data == ITEM_TRANSITION:
+                    idx = self.Controler.OpenPouTransitionEditing(grandparent_name, name)
+                    language = self.Controler.GetTransitionBodyType(grandparent_name, name)
+                elif data == ITEM_ACTION:
+                    idx = self.Controler.OpenPouActionEditing(grandparent_name, name)
+                    language = self.Controler.GetActionBodyType(grandparent_name, name)
+                varlist = [name]
+                vars = self.Controler.GetPouInterfaceVarsByName(grandparent_name)
+                if vars:
+                    for var in vars:
+                        varlist.append(var["Name"])
+            if idx != None:
+                if language == "FBD":
+                    new_window = FBD_Viewer(self.TabsOpened, self, self.Controler)
+                elif language == "LD":
+                    new_window = LD_Viewer(self.TabsOpened, self, self.Controler)
+                elif language == "SFC":
+                    new_window = SFC_Viewer(self.TabsOpened, self, self.Controler)
+                elif language in ["IL", "ST"]:
+                    new_window = TextViewer(self.TabsOpened, self, self.Controler)
+                    if language == "IL":
+                        new_window.SetKeywords(IL_KEYWORDS)
+                    else:
+                        new_window.SetKeywords(ST_KEYWORDS)
+                    new_window.SetVariables(varlist)
+                    new_window.SetFunctions(self.Controler.GetBlockTypes())
+                else:
+                    return
+                new_window.RefreshView()
+                self.TabsOpened.AddPage(new_window, "")
+                self.TabsOpened.SetSelection(idx)
+                self.RefreshTabsOpenedTitles()
+                self.RefreshFileMenu()
+                self.RefreshEditMenu()
+                self.RefreshToolBar()
+            else:
+                if data == ITEM_POU:
+                    idx = self.Controler.ChangeElementEditing(name)
+                elif data == ITEM_TRANSITION:
+                    idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name)
+                elif data == ITEM_ACTION:
+                    idx = self.Controler.ChangePouActionEditing(grandparent_name, name)
+                if idx != None:
+                    self.TabsOpened.SetSelection(idx)
+                    self.RefreshFileMenu()
+                    self.RefreshEditMenu()
+                    self.RefreshToolBar()
+        elif data == ITEM_RESOURCE:
+            item = self.ProjectTree.GetItemParent(selected)
+            item_type = self.ProjectTree.GetPyData(item)
+            while item_type != ITEM_CONFIGURATION:
+                item = self.ProjectTree.GetItemParent(item)
+                item_type = self.ProjectTree.GetPyData(item)
+            config_name = self.ProjectTree.GetItemText(item)
+            idx = self.Controler.OpenConfigurationResourceEditing(config_name, name)
+            if idx != None:
+                new_window = ResourceEditor(self.TabsOpened, self, self.Controler)
+                new_window.RefreshView()
+                self.TabsOpened.AddPage(new_window, "")
+                self.TabsOpened.SetSelection(idx)
+                self.RefreshTabsOpenedTitles()
+                self.RefreshFileMenu()
+                self.RefreshEditMenu()
+                self.RefreshToolBar()
+            else:
+                idx = self.Controler.ChangeConfigurationResourceEditing(parent_name, name)
+                if idx != None:
+                    self.TabsOpened.SetSelection(idx)
+                    self.RefreshFileMenu()
+                    self.RefreshEditMenu()
+                    self.RefreshToolBar()
+    
+    def OnProjectTreeRightUp(self, event):
+        selected = self.ProjectTree.GetSelection()
+        if self.ProjectTree.GetPyData(selected) == ITEM_POU:
+            name = self.ProjectTree.GetItemText(selected)
+            if self.Controler.GetPouBodyType(name) == "SFC":
+                self.PopupMenu(self.SFCMenu)
+        elif self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION:
+            self.PopupMenu(self.ConfigMenu)
+        event.Skip()
+    
+    def OnProjectTreeItemSelected(self, event):
+        selected = event.GetItem()
+        name = self.ProjectTree.GetItemText(selected)
+        if self.ProjectTree.GetItemParent(selected) == self.ProjectTree.GetRootItem() and name != "Properties":
+            if self.Controler.IsElementEditing(name):
+                idx = self.Controler.ChangeElementEditing(name)
+                if idx != None:
+                    self.TabsOpened.SetSelection(idx)
+                    self.RefreshFileMenu()
+                    self.RefreshEditMenu()
+                    self.RefreshToolBar()
+        else:
+            name = self.ProjectTree.GetItemText(selected)
+            parent = self.ProjectTree.GetItemParent(selected)
+            parent_name = self.ProjectTree.GetItemText(parent)
+            grandparent = self.ProjectTree.GetItemParent(parent)
+            grandparent_name = self.ProjectTree.GetItemText(grandparent)
+            if parent_name == "Transitions":
+                idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name)
+                if idx != None:
+                    self.TabsOpened.SetSelection(idx)
+                    self.RefreshFileMenu()
+                    self.RefreshEditMenu()
+                    self.RefreshToolBar()
+            elif parent_name == "Action":
+                idx = self.Controler.ChangePouActionEditing(grandparent_name, name)
+                if idx != None:
+                    self.TabsOpened.SetSelection(idx)
+                    self.RefreshFileMenu()
+                    self.RefreshEditMenu()
+                    self.RefreshToolBar()
+        event.Skip()
+
+    def RefreshProjectTree(self):
+        infos = self.Controler.GetProjectInfos()
+        root = self.ProjectTree.GetRootItem()
+        self.GenerateTreeBranch(root, infos)
+        self.ProjectTree.Expand(self.ProjectTree.GetRootItem())
+
+    def GenerateTreeBranch(self, root, infos):
+        to_delete = []
+        if root.IsOk():
+            self.ProjectTree.SetItemText(root, infos["name"])
+        else:
+            root = self.ProjectTree.AddRoot(infos["name"])
+        self.ProjectTree.SetPyData(root, infos["type"])
+        item, root_cookie = self.ProjectTree.GetFirstChild(root)
+        if len(infos["values"]) > 0:
+            for values in infos["values"]:
+                if not item.IsOk():
+                    item = self.ProjectTree.AppendItem(root, "")
+                    item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+                self.GenerateTreeBranch(item, values)
+                item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+        while item.IsOk():
+            to_delete.append(item)
+            item, root_cookie = self.ProjectTree.GetNextChild(item, root_cookie)
+        for item in to_delete:
+            self.ProjectTree.Delete(item)
+
+    def RefreshToolBar(self):
+        language = self.Controler.GetCurrentElementEditingBodyType()
+        if language == "SFC":
+            self.SFCToolBar.ToggleTool(0, True)
+            self.SFCToolBar.Show()
+            self.SetToolBar(self.SFCToolBar)
+            self.DefaultToolBar.Hide()
+            self.FBDToolBar.Hide()
+            self.LDToolBar.Hide()
+        elif language == "FBD":
+            self.FBDToolBar.ToggleTool(0, True)
+            self.FBDToolBar.Show()
+            self.SetToolBar(self.FBDToolBar)
+            self.DefaultToolBar.Hide()
+            self.SFCToolBar.Hide()
+            self.LDToolBar.Hide()
+        elif language == "LD":
+            self.LDToolBar.ToggleTool(0, True)
+            self.LDToolBar.Show()
+            self.SetToolBar(self.LDToolBar)
+            self.DefaultToolBar.Hide()
+            self.SFCToolBar.Hide()
+            self.FBDToolBar.Hide()
+        else:
+            self.DefaultToolBar.ToggleTool(0, True)
+            self.DefaultToolBar.Show()
+            self.SetToolBar(self.DefaultToolBar)
+            self.SFCToolBar.Hide()
+            self.FBDToolBar.Hide()
+            self.LDToolBar.Hide()
+
+    def RefreshTabsOpenedTitles(self):
+        pous = self.Controler.GetElementsOpenedNames()
+        for i, pou in enumerate(pous):
+            self.TabsOpened.SetPageText(i, pou)
+    
+    def OnRefreshMenu(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).Refresh()
+        event.Skip()
+    
+    def OnCutMenu(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).Cut()
+        event.Skip()
+    
+    def OnCopyMenu(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).Copy()
+        event.Skip()
+    
+    def OnPasteMenu(self, event):
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).Paste()
+        event.Skip()
+    
+    def OnAddPouMenu(self, event):
+        dialog = PouDialog(self)
+        dialog.SetPouNames(self.Controler.GetProjectPouNames())
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"])
+            self.RefreshProjectTree()
+        dialog.Destroy()
+        event.Skip()
+
+    def OnRemovePouMenu(self, event):
+        pous = self.Controler.GetProjectPouNames()
+        dialog = wxSingleChoiceDialog(self, "Select POU to remove:", "POU Remove", pous, wxOK|wxCANCEL)
+        if dialog.ShowModal() == wxID_OK:
+            selected = dialog.GetStringSelection()
+            if not self.Controler.PouIsUsed(selected):
+                self.Controler.ProjectRemovePou(selected)
+                for i in xrange(self.TabsOpened.GetPageCount()):
+                    if self.TabsOpened.GetPageText(i) == selected:
+                        self.TabsOpened.DeletePage(i)
+                self.RefreshProjectTree()
+                self.RefreshToolBar()
+            else:
+                message = wxMessageDialog(self, "%s is used by one or more POUs. It can't be removed!"%selected, "Error", wxOK|wxICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+        event.Skip()
+
+    def OnAddConfigurationMenu(self, event):
+        dialog = wxTextEntryDialog(self, "Enter configuration name:", "Create new configuration", "", wxOK|wxCANCEL)
+        if dialog.ShowModal() == wxID_OK:
+            value = dialog.GetValue()
+            self.Controler.ProjectAddConfiguration(value)
+            self.RefreshProjectTree()
+        dialog.Destroy()
+        event.Skip()
+
+    def OnRemoveConfigurationMenu(self, event):
+        configs = self.Controler.GetProjectConfigNames()
+        dialog = wxSingleChoiceDialog(self, "Select Configuration to remove:", "Configuration Remove", configs, wxOK|wxCANCEL)
+        if dialog.ShowModal() == wxID_OK:
+            selected = dialog.GetStringSelection()
+            self.Controler.ProjectRemoveConfiguration(selected)
+            self.RefreshProjectTree()
+        event.Skip()
+
+    def OnAddPouTransitionMenu(self, event):
+        dialog = PouTransitionDialog(self)
+        dialog.SetPous(self.Controler.GetSFCPous())
+        if dialog.ShowModal() == wxID_OK: 
+            values = dialog.GetValues()
+            self.Controler.ProjectAddPouTransition(values["pouName"], values["transitionName"], values["language"])
+            self.RefreshProjectTree()
+        dialog.Destroy()
+        event.Skip()
+
+    def OnRemovePouTransitionMenu(self, event):
+        event.Skip()
+
+    def OnAddPouActionMenu(self, event):
+        dialog = PouActionDialog(self)
+        dialog.SetPous(self.Controler.GetSFCPous())
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            self.Controler.ProjectAddPouAction(values["pouName"], values["actionName"], values["language"])
+            self.RefreshProjectTree()
+        dialog.Destroy()
+        event.Skip()
+
+    def OnRemovePouActionMenu(self, event):
+        event.Skip()
+
+    def OnAddResourceMenu(self, event):
+        selected = self.ProjectTree.GetSelection()
+        if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION:
+            config_name = self.ProjectTree.GetItemText(selected)
+            dialog = wxTextEntryDialog(self, "Enter Resource name:", "Create new Resource", "", wxOK|wxCANCEL)
+            if dialog.ShowModal() == wxID_OK:
+                value = dialog.GetValue()
+                self.Controler.ProjectAddConfigurationResource(config_name, value)
+                self.RefreshProjectTree()
+            dialog.Destroy()
+        event.Skip()
+
+    def OnRemoveResourceMenu(self, event):
+        selected = self.ProjectTree.GetSelection()
+        if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION:
+            config_name = self.ProjectTree.GetItemText(selected)
+            infos = self.Controler.GetProjectInfos()
+            resources = []
+            for config in infos["configs"]:
+                if config["name"] == config_name:
+                    resources = config["resources"]
+            dialog = wxSingleChoiceDialog(self, "Select Resource to remove:", "Resource Remove", resources, wxOK|wxCANCEL)
+            if dialog.ShowModal() == wxID_OK:
+                resource = dialog.GetStringSelection()
+                self.Controler.ProjectRemoveConfigurationResource(config_name, resource)
+                self.RefreshProjectTree()
+            dialog.Destroy()
+        event.Skip()
+
+    def OnPLCOpenMenu(self, event):
+        result = OpenPDFDoc()
+        if type(result) == StringType:
+            message = wxMessageDialog(self, result, "ERROR", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        event.Skip()
+
+current_num = 0
+def GetNewNum():
+    global current_num
+    current_num += 1
+    return current_num
+
+#-------------------------------------------------------------------------------
+#                            Create Project Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_PROJECTDIALOG, wxID_PROJECTDIALOGMAINPANEL, 
+ wxID_PROJECTDIALOGPROJECTNAME, wxID_PROJECTDIALOGCOMPANYNAME, 
+ wxID_PROJECTDIALOGCOMPANYURL, wxID_PROJECTDIALOGPRODUCTNAME, 
+ wxID_PROJECTDIALOGPRODUCTVERSION, wxID_PROJECTDIALOGPRODUCTRELEASE, 
+ wxID_PROJECTDIALOGCONTENTDESCRIPTION, wxID_PROJECTDIALOGSTATICTEXT1,
+ wxID_PROJECTDIALOGSTATICTEXT2, wxID_PROJECTDIALOGSTATICTEXT3, 
+ wxID_PROJECTDIALOGSTATICTEXT4, wxID_PROJECTDIALOGSTATICTEXT5, 
+ wxID_PROJECTDIALOGSTATICTEXT6, wxID_PROJECTDIALOGSTATICTEXT7, 
+] = [wx.NewId() for _init_ctrls in range(16)]
+        
+class ProjectDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_PROJECTDIALOG,
+              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Create a new project')
+        self.SetClientSize(wx.Size(550, 450))
+
+        self.MainPanel = wx.Panel(id=wxID_PROJECTDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(450, 400), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT1,
+              label='Project Name (required):', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(215, 17), style=0)
+
+        self.ProjectName = wx.TextCtrl(id=wxID_PROJECTDIALOGPROJECTNAME,
+              name='ProjectName', parent=self.MainPanel, pos=wx.Point(224, 24), 
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT2,
+              label='Company Name (required):', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 64), size=wx.Size(215, 17), style=0)
+
+        self.CompanyName = wx.TextCtrl(id=wxID_PROJECTDIALOGCOMPANYNAME,
+              name='CompanyName', parent=self.MainPanel, pos=wx.Point(224, 64),
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT3,
+              label='Company URL (optional):', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 104), size=wx.Size(215, 17), style=0)
+
+        self.CompanyURL = wx.TextCtrl(id=wxID_PROJECTDIALOGCOMPANYURL,
+              name='CompanyURL', parent=self.MainPanel, pos=wx.Point(224, 104),
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText4 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT4,
+              label='Product Name (required):', name='staticText4', parent=self.MainPanel,
+              pos=wx.Point(24, 144), size=wx.Size(215, 17), style=0)
+
+        self.ProductName = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTNAME,
+              name='ProductName', parent=self.MainPanel, pos=wx.Point(224, 144),
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText5 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT5,
+              label='Product Version (required):', name='staticText5', parent=self.MainPanel,
+              pos=wx.Point(24, 184), size=wx.Size(215, 17), style=0)
+
+        self.ProductVersion = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTVERSION,
+              name='ProductVersion', parent=self.MainPanel, pos=wx.Point(224, 184),
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText6 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT6,
+              label='Product Release (optional):', name='staticText6', parent=self.MainPanel,
+              pos=wx.Point(24, 224), size=wx.Size(215, 17), style=0)
+
+        self.ProductRelease = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTRELEASE,
+              name='ProductRelease', parent=self.MainPanel, pos=wx.Point(224, 224),
+              size=wx.Size(295, 24), style=0)
+
+        self.staticText7 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT7,
+              label='Content Description (optional):', name='staticText7', parent=self.MainPanel,
+              pos=wx.Point(24, 264), size=wx.Size(215, 17), style=0)
+
+        self.ContentDescription = wx.TextCtrl(id=wxID_PROJECTDIALOGCONTENTDESCRIPTION,
+              name='ProductRelease', parent=self.MainPanel, pos=wx.Point(224, 264),
+              size=wx.Size(295, 120), style=wxTE_MULTILINE)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        if self.ProjectName.GetValue() == "":
+            error.append("Project Name")
+        if self.CompanyName.GetValue() == "":
+            error.append("Company Name")
+        if self.ProductName.GetValue() == "":
+            error.append("Product Name")
+        if self.ProductVersion.GetValue() == "":
+            error.append("Product Version")
+        if len(error) > 0:
+            text = ""
+            for i, item in enumerate(error):
+                if i == 0:
+                    text += item
+                elif i == len(error) - 1:
+                    text += " and %s"%item
+                else:
+                    text += ", %s"%item 
+            message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def SetValues(self, values):
+        for item, value in values.items():
+            if item == "projectName":
+                self.ProjectName.SetValue(value)
+            elif item == "companyName":
+                self.CompanyName.SetValue(value)
+            elif item == "companyURL":
+                self.CompanyURL.SetValue(value)
+            elif item == "productName":
+                self.ProductName.SetValue(value)
+            elif item == "productVersion":
+                self.ProductVersion.SetValue(value)
+            elif item == "productRelease":
+                self.ProductRelease.SetValue(value)
+            elif item == "contentDescription":
+                self.ContentDescription.SetValue(value)
+
+    def GetValues(self):
+        values = {}
+        values["projectName"] = self.ProjectName.GetValue()
+        values["companyName"] = self.CompanyName.GetValue()
+        if self.CompanyURL.GetValue() != None:
+            values["companyURL"] = self.CompanyURL.GetValue()
+        values["productName"] = self.ProductName.GetValue()
+        values["productVersion"] = self.ProductVersion.GetValue()
+        if self.ProductRelease.GetValue() != None:
+            values["productRelease"] = self.ProductRelease.GetValue()
+        if self.ProductRelease.GetValue() != None:
+            values["contentDescription"] = self.ContentDescription.GetValue()
+        return values
+
+#-------------------------------------------------------------------------------
+#                            Create Pou Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_POUDIALOG, wxID_POUDIALOGMAINPANEL, wxID_POUDIALOGPOUNAME, 
+ wxID_POUDIALOGPOUTYPE, wxID_POUDIALOGLANGUAGE, wxID_POUDIALOGSTATICTEXT1,
+ wxID_POUDIALOGSTATICTEXT2, wxID_POUDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+class PouDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_POUDIALOG,
+              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Create a new project')
+        self.SetClientSize(wx.Size(300, 200))
+
+        self.MainPanel = wx.Panel(id=wxID_POUDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(300, 200), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT1,
+              label='POU Name:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(95, 17), style=0)
+
+        self.PouName = wx.TextCtrl(id=wxID_POUDIALOGPOUNAME,
+              name='POUName', parent=self.MainPanel, pos=wx.Point(104, 24), 
+              size=wx.Size(150, 24), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT2,
+              label='POU Type:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 64), size=wx.Size(95, 17), style=0)
+
+        self.PouType = wx.Choice(id=wxID_POUDIALOGPOUTYPE,
+              name='POUType', parent=self.MainPanel, pos=wx.Point(104, 64),
+              size=wx.Size(150, 24), style=0)
+        EVT_CHOICE(self, wxID_POUDIALOGPOUTYPE, self.OnTypeChanged)
+
+        self.staticText3 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT3,
+              label='Language:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 104), size=wx.Size(95, 17), style=0)
+
+        self.Language = wx.Choice(id=wxID_POUDIALOGLANGUAGE,
+              name='Language', parent=self.MainPanel, pos=wx.Point(104, 104),
+              size=wx.Size(150, 24), style=0)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        
+        for option in ["function","functionBlock","program"]:
+            self.PouType.Append(option)
+        self.RefreshLanguage()
+
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        pou_name = self.PouName.GetValue()
+        if pou_name == "":
+            error.append("POU Name")
+        if self.PouType.GetStringSelection() == "":
+            error.append("POU Type")
+        if self.Language.GetStringSelection() == "":
+            error.append("Language")
+        if len(error) > 0:
+            text = ""
+            for i, item in enumerate(error):
+                if i == 0:
+                    text += item
+                elif i == len(error) - 1:
+                    text += " and %s"%item
+                else:
+                    text += ", %s"%item 
+            message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif not TestIdentifier(pou_name):
+            message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%pou_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif pou_name.upper() in IEC_KEYWORDS:
+            message = wxMessageDialog(self, "\"%s\" is a keyword. It can't be used!"%pou_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif pou_name.upper() in self.PouNames:
+            message = wxMessageDialog(self, "\"%s\" pou already exists!"%pou_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def RefreshLanguage(self):
+        selection = self.Language.GetStringSelection()
+        self.Language.Clear()
+        for option in ["IL","ST","LD","FBD","SFC"]:
+            if option != "SFC" or self.PouType.GetStringSelection() == "program":
+                self.Language.Append(option)
+        if self.Language.FindString(selection) != wxNOT_FOUND:
+            self.Language.SetStringSelection(selection)
+
+    def OnTypeChanged(self, event):
+        self.RefreshLanguage()
+        event.Skip()
+
+    def SetPouNames(self, pou_names):
+        self.PouNames = [pou_name.upper() for pou_name in pou_names]
+
+    def SetValues(self, values):
+        for item, value in values.items():
+            if item == "pouName":
+                self.PouName.SetValue(value)
+            elif item == "pouType":
+                self.PouType.SetStringSelection(value)
+            elif item == "language":
+                self.Language.SetStringSelection(value)
+                
+    def GetValues(self):
+        values = {}
+        values["pouName"] = self.PouName.GetValue()
+        values["pouType"] = self.PouType.GetStringSelection()
+        values["language"] = self.Language.GetStringSelection()
+        return values
+
+
+#-------------------------------------------------------------------------------
+#                          Create Pou Transition Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_POUTRANSITIONDIALOG, wxID_POUTRANSITIONDIALOGMAINPANEL, 
+ wxID_POUTRANSITIONDIALOGPOUNAME, wxID_POUTRANSITIONDIALOGTRANSITIONNAME, 
+ wxID_POUTRANSITIONDIALOGLANGUAGE, wxID_POUTRANSITIONDIALOGSTATICTEXT1,
+ wxID_POUTRANSITIONDIALOGSTATICTEXT2, wxID_POUTRANSITIONDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+class PouTransitionDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_POUTRANSITIONDIALOG,
+              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(350, 200), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Create a new project')
+        self.SetClientSize(wx.Size(350, 200))
+
+        self.MainPanel = wx.Panel(id=wxID_POUTRANSITIONDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(350, 200), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT1,
+              label='POU Name:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(145, 17), style=0)
+
+        self.PouName = wx.Choice(id=wxID_POUTRANSITIONDIALOGPOUNAME,
+              name='POUName', parent=self.MainPanel, pos=wx.Point(154, 24), 
+              size=wx.Size(150, 24), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT2,
+              label='Transition Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 64), size=wx.Size(145, 17), style=0)
+
+        self.TransitionName = wx.TextCtrl(id=wxID_POUTRANSITIONDIALOGTRANSITIONNAME,
+              name='TransitionName', parent=self.MainPanel, pos=wx.Point(154, 64),
+              size=wx.Size(150, 24), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT3,
+              label='Language:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 104), size=wx.Size(145, 17), style=0)
+
+        self.Language = wx.Choice(id=wxID_POUTRANSITIONDIALOGLANGUAGE,
+              name='Language', parent=self.MainPanel, pos=wx.Point(154, 104),
+              size=wx.Size(150, 24), style=0)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+
+        for option in ["IL","ST","LD","FBD"]:
+            self.Language.Append(option)
+        
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        if self.PouName.GetStringSelection() == "":
+            error.append("POU Name")
+        if self.TransitionName.GetValue() == "":
+            error.append("Transition Name")
+        if self.Language.GetStringSelection() == "":
+            error.append("Language")
+        if len(error) > 0:
+            text = ""
+            for i, item in enumerate(error):
+                if i == 0:
+                    text += item
+                elif i == len(error) - 1:
+                    text += " and %s"%item
+                else:
+                    text += ", %s"%item 
+            message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def SetPous(self, pous):
+        for pou in pous:
+            self.PouName.Append(pou)
+
+    def SetValues(self, values):
+        for item, value in values.items():
+            if item == "pouName":
+                self.PouName.SetStringSelection(value)
+            elif item == "transitionName":
+                self.TransitionName.SetValue(value)
+            elif item == "language":
+                self.Language.SetStringSelection(value)
+                
+    def GetValues(self):
+        values = {}
+        values["pouName"] = self.PouName.GetStringSelection()
+        values["transitionName"] = self.TransitionName.GetValue()
+        values["language"] = self.Language.GetStringSelection()
+        return values
+
+#-------------------------------------------------------------------------------
+#                          Create Pou Action Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_POUACTIONDIALOG, wxID_POUACTIONDIALOGMAINPANEL, 
+ wxID_POUACTIONDIALOGPOUNAME, wxID_POUACTIONDIALOGACTIONNAME, 
+ wxID_POUACTIONDIALOGLANGUAGE, wxID_POUACTIONDIALOGSTATICTEXT1,
+ wxID_POUACTIONDIALOGSTATICTEXT2, wxID_POUACTIONDIALOGSTATICTEXT3, 
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+class PouActionDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_POUACTIONDIALOG,
+              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(320, 200), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Create a new project')
+        self.SetClientSize(wx.Size(320, 200))
+
+        self.MainPanel = wx.Panel(id=wxID_POUACTIONDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(350, 200), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT1,
+              label='POU Name:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(145, 17), style=0)
+
+        self.PouName = wx.Choice(id=wxID_POUACTIONDIALOGPOUNAME,
+              name='POUName', parent=self.MainPanel, pos=wx.Point(124, 24), 
+              size=wx.Size(150, 24), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT2,
+              label='Action Name:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 64), size=wx.Size(145, 17), style=0)
+
+        self.ActionName = wx.TextCtrl(id=wxID_POUACTIONDIALOGACTIONNAME,
+              name='ActionName', parent=self.MainPanel, pos=wx.Point(124, 64),
+              size=wx.Size(150, 24), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT3,
+              label='Language:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 104), size=wx.Size(145, 17), style=0)
+
+        self.Language = wx.Choice(id=wxID_POUACTIONDIALOGLANGUAGE,
+              name='Language', parent=self.MainPanel, pos=wx.Point(124, 104),
+              size=wx.Size(150, 24), style=0)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+
+        for option in ["IL","ST","LD","FBD"]:
+            self.Language.Append(option)
+        
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        if self.PouName.GetStringSelection() == "":
+            error.append("POU Name")
+        if self.ActionName.GetValue() == "":
+            error.append("Action Name")
+        if self.Language.GetStringSelection() == "":
+            error.append("Language")
+        if len(error) > 0:
+            text = ""
+            for i, item in enumerate(error):
+                if i == 0:
+                    text += item
+                elif i == len(error) - 1:
+                    text += " and %s"%item
+                else:
+                    text += ", %s"%item 
+            message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def SetPous(self, pous):
+        for pou in pous:
+            self.PouName.Append(pou)
+
+    def SetValues(self, values):
+        for item, value in values.items():
+            if item == "pouName":
+                self.PouName.SetStringSelection(value)
+            elif item == "actionName":
+                self.ActionName.SetValue(value)
+            elif item == "language":
+                self.Language.SetStringSelection(value)
+                
+    def GetValues(self):
+        values = {}
+        values["pouName"] = self.PouName.GetStringSelection()
+        values["actionName"] = self.ActionName.GetValue()
+        values["language"] = self.Language.GetStringSelection()
+        return values
+
+#-------------------------------------------------------------------------------
+#                            Pou Interface Dialog
+#-------------------------------------------------------------------------------
+
+class VariableTable(wxPyGridTableBase):
+    
+    """
+    A custom wxGrid Table using user supplied data
+    """
+    def __init__(self, parent, data, colnames):
+        # The base class must be initialized *first*
+        wxPyGridTableBase.__init__(self)
+        self.data = data
+        self.colnames = colnames
+        self.Parent = parent
+        # XXX
+        # we need to store the row length and collength to
+        # see if the table has changed size
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
+    
+    def GetNumberCols(self):
+        return len(self.colnames)
+        
+    def GetNumberRows(self):
+        return len(self.data)
+
+    def GetColLabelValue(self, col):
+        if col < len(self.colnames):
+            return self.colnames[col]
+
+    def GetRowLabelValues(self, row):
+        return row
+
+    def GetValue(self, row, col):
+        if row < self.GetNumberRows():
+            name = str(self.data[row].get(self.GetColLabelValue(col), ""))
+            return name
+    
+    def GetValueByName(self, row, colname):
+        return self.data[row].get(colname)
+
+    def SetValue(self, row, col, value):
+        if col < len(self.colnames):
+            self.data[row][self.GetColLabelValue(col)] = value
+        
+    def ResetView(self, grid):
+        """
+        (wxGrid) -> Reset the grid view.   Call this to
+        update the grid if rows and columns have been added or deleted
+        """
+        grid.BeginBatch()
+        for current, new, delmsg, addmsg in [
+            (self._rows, self.GetNumberRows(), wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED),
+            (self._cols, self.GetNumberCols(), wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED),
+        ]:
+            if new < current:
+                msg = wxGridTableMessage(self,delmsg,new,current-new)
+                grid.ProcessTableMessage(msg)
+            elif new > current:
+                msg = wxGridTableMessage(self,addmsg,new-current)
+                grid.ProcessTableMessage(msg)
+                self.UpdateValues(grid)
+        grid.EndBatch()
+
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
+        # update the column rendering scheme
+        self._updateColAttrs(grid)
+
+        # update the scrollbars and the displayed part of the grid
+        grid.AdjustScrollbars()
+        grid.ForceRefresh()
+
+    def UpdateValues(self, grid):
+        """Update all displayed values"""
+        # This sends an event to the grid table to update all of the values
+        msg = wxGridTableMessage(self, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES)
+        grid.ProcessTableMessage(msg)
+
+    def _updateColAttrs(self, grid):
+        """
+        wxGrid -> update the column attributes to add the
+        appropriate renderer given the column name.
+
+        Otherwise default to the default renderer.
+        """
+        
+        for col in range(self.GetNumberCols()):
+            attr = wxGridCellAttr()
+            attr.SetAlignment(self.Parent.ColAlignements[col], wxALIGN_CENTRE)
+            grid.SetColAttr(col, attr)
+            grid.SetColSize(col, self.Parent.ColSizes[col])
+        
+        typelist = None
+        accesslist = None
+        for row in range(self.GetNumberRows()):
+            for col in range(self.GetNumberCols()):
+                editor = None
+                renderer = None
+                colname = self.GetColLabelValue(col)
+                grid.SetReadOnly(row, col, False)
+                if colname in ["Name","Initial Value","Location"]:
+                    editor = wxGridCellTextEditor()
+                    renderer = wxGridCellStringRenderer()    
+                elif colname == "Class":
+                    if len(self.Parent.ClassList) == 1:
+                        grid.SetReadOnly(row, col, True)
+                    else:
+                        editor = wxGridCellChoiceEditor()    
+                        editor.SetParameters(",".join(self.Parent.ClassList))
+                elif colname == "Type":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.TypeList)
+                elif colname in ["Retain", "Constant"]:
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.OptionList)
+                    
+                grid.SetCellEditor(row, col, editor)
+                grid.SetCellRenderer(row, col, renderer)
+                
+                grid.SetCellBackgroundColour(row, col, wxWHITE)
+    
+    def SetData(self, data):
+        self.data = data
+    
+    def GetData(self):
+        return self.data
+    
+    def GetCurrentIndex(self):
+        return self.CurrentIndex
+    
+    def SetCurrentIndex(self, index):
+        self.CurrentIndex = index
+    
+    def AppendRow(self, row_content):
+        self.data.append(row_content)
+
+    def RemoveRow(self, row_index):
+        self.data.pop(row_index)
+        
+    def MoveRow(self, row_index, move, grid):
+        new_index = max(0, min(row_index + move, len(self.data) - 1))
+        if new_index != row_index:
+            self.data.insert(new_index, self.data.pop(row_index))
+            grid.SetGridCursor(new_index, grid.GetGridCursorCol())
+
+    def Empty(self):
+        self.data = []
+        self.editors = []
+
+[wxID_EDITVARIABLEDIALOG, wxID_EDITVARIABLEDIALOGMAINPANEL, 
+ wxID_EDITVARIABLEDIALOGVARIABLESGRID, wxID_EDITVARIABLEDIALOGRETURNTYPE, 
+ wxID_EDITVARIABLEDIALOGCLASSFILTER, wxID_EDITVARIABLEDIALOGADDBUTTON,
+ wxID_EDITVARIABLEDIALOGDELETEBUTTON, wxID_EDITVARIABLEDIALOGUPBUTTON, 
+ wxID_EDITVARIABLEDIALOGDOWNBUTTON, wxID_EDITVARIABLEDIALOGSTATICTEXT1, 
+ wxID_EDITVARIABLEDIALOGSTATICTEXT2, wxID_EDITVARIABLEDIALOGSTATICTEXT3,
+] = [wx.NewId() for _init_ctrls in range(12)]
+
+class EditVariableDialog(wx.Dialog):
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
+
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+
+        self.SetSizer(self.flexGridSizer1)
+
+    def _init_ctrls(self, prnt, name):
+        # generated method, don't edit
+        wx.Dialog.__init__(self, id=wxID_EDITVARIABLEDIALOG,
+              name='EditVariableDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(600, 440), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Edit variables of %s'%name)
+        self.SetClientSize(wx.Size(600, 440))
+
+        self.MainPanel = wx.Panel(id=wxID_EDITVARIABLEDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(600, 440), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT1,
+              label='Return Type:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 29), size=wx.Size(95, 17), style=0)
+
+        self.ReturnType = wx.Choice(id=wxID_EDITVARIABLEDIALOGRETURNTYPE,
+              name='ReturnType', parent=self.MainPanel, pos=wx.Point(124, 24),
+              size=wx.Size(145, 24), style=0)
+
+        self.staticText2 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT2,
+              label='Class Filter:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(324, 29), size=wx.Size(95, 17), style=0)
+
+        self.ClassFilter = wx.Choice(id=wxID_EDITVARIABLEDIALOGCLASSFILTER,
+              name='ClassFilter', parent=self.MainPanel, pos=wx.Point(424, 24),
+              size=wx.Size(145, 24), style=0)
+        EVT_CHOICE(self, wxID_EDITVARIABLEDIALOGCLASSFILTER, self.OnClassFilter)
+
+        self.staticText3 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT3,
+              label='Variables:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(24, 60), size=wx.Size(95, 17), style=0)
+
+        self.VariablesGrid = wx.grid.Grid(id=wxID_EDITVARIABLEDIALOGVARIABLESGRID,
+              name='VariablesGrid', parent=self.MainPanel, pos=wx.Point(24, 80), 
+              size=wx.Size(550, 250), style=wxVSCROLL)
+        self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+              'Sans'))
+        self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+              False, 'Sans'))
+        self.VariablesGrid.DisableDragGridSize()
+        self.VariablesGrid.EnableScrolling(False, True)
+
+        self.AddButton = wx.Button(id=wxID_EDITVARIABLEDIALOGADDBUTTON, label='Add',
+              name='AddButton', parent=self.MainPanel, pos=wx.Point(345, 340),
+              size=wx.Size(72, 32), style=0)
+        EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGADDBUTTON, self.OnAddButton)
+
+        self.DeleteButton = wx.Button(id=wxID_EDITVARIABLEDIALOGDELETEBUTTON, label='Delete',
+              name='DeleteButton', parent=self.MainPanel, pos=wx.Point(425, 340),
+              size=wx.Size(72, 32), style=0)
+        EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGDELETEBUTTON, self.OnDeleteButton)
+
+        self.UpButton = wx.Button(id=wxID_EDITVARIABLEDIALOGUPBUTTON, label='^',
+              name='UpButton', parent=self.MainPanel, pos=wx.Point(505, 340),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGUPBUTTON, self.OnUpButton)
+
+        self.DownButton = wx.Button(id=wxID_EDITVARIABLEDIALOGDOWNBUTTON, label='v',
+              name='DownButton', parent=self.MainPanel, pos=wx.Point(545, 340),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGDOWNBUTTON, self.OnDownButton)
+
+        self._init_sizers()
+
+    def __init__(self, parent, name, pou_type, filter = "All"):
+        self._init_ctrls(parent, name)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        self.Filter = filter
+        self.FilterChoices = []
+        self.FilterChoiceTransfer = {"All" : "All", "Interface" : "Interface", 
+            "Input" : "   Input", "Output" : "   Output", "InOut" : "   InOut", 
+            "External" : "   External", "Variables" : "Variables", "Local" : "   Local",
+            "Temp" : "   Temp", "Global" : "Global", "Access" : "Access"}
+        
+        if pou_type:
+            self.DefaultValue = {"Name" : "", "Class" : "Input", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
+        else:
+            self.DefaultValue = {"Name" : "", "Class" : "Global", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
+        if not pou_type or pou_type == "program":
+            self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"])
+            if pou_type:
+                self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp","Global","Access"]
+            else:
+                self.FilterChoices = ["All","Global","Access"]
+            self.ColSizes = [80, 70, 80, 80, 80, 60, 70]
+            self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_CENTER, wxALIGN_CENTER]
+        else:
+            self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Initial Value", "Retain", "Constant"])
+            self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp"]
+            self.ColSizes = [120, 70, 80, 120, 60, 70]
+            self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_CENTER, wxALIGN_CENTER]
+        for choice in self.FilterChoices:
+            self.ClassFilter.Append(choice)
+        self.ClassFilter.SetStringSelection(self.FilterChoiceTransfer[self.Filter])
+        self.RefreshTypeList()
+        self.RefreshUpDownButtons()
+
+        self.OptionList = "Yes,No"
+        self.TypeList = ""
+        for value in TypeHierarchy.keys():
+            if not value.startswith("ANY"):
+                self.TypeList += "%s,"%value
+        self.TypeList = self.TypeList[:-1]
+        
+        if pou_type == "function":
+            for value in TypeHierarchy.keys():
+                if not value.startswith("ANY"):
+                    self.ReturnType.Append(value)
+            self.ReturnType.Enable(True)
+        else:
+            self.ReturnType.Enable(False)
+            self.staticText2.Hide()
+            self.ReturnType.Hide()
+        
+        self.VariablesGrid.SetTable(self.Table)
+        self.VariablesGrid.SetRowLabelSize(0)
+        
+        self.Table.ResetView(self.VariablesGrid)
+
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        self.VariablesGrid.SetGridCursor(0, 0)
+        error = []
+        if self.ReturnType.IsEnabled() and self.ReturnType.GetStringSelection() == "":
+            error.append("Return Type")
+        if len(error) > 0:
+            text = ""
+            for i, item in enumerate(error):
+                if i == 0:
+                    text += item
+                elif i == len(error) - 1:
+                    text += " and %s"%item
+                else:
+                    text += ", %s"%item 
+            message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def OnClassFilter(self, event):
+        reverse_transfer = {}
+        for filter, choice in self.FilterChoiceTransfer.items():
+            reverse_transfer[choice] = filter
+        self.Filter = reverse_transfer[self.ClassFilter.GetStringSelection()]
+        self.RefreshTypeList()
+        self.RefreshValues()
+        self.RefreshUpDownButtons()
+        event.Skip()
+
+    def RefreshTypeList(self):
+        if self.Filter == "All":
+            self.ClassList = [choice for choice in self.FilterChoices if choice not in ["All","Interface","Variables"]]
+        elif self.Filter == "Interface":
+            self.ClassList = ["Input","Output","InOut","External"]
+        elif self.Filter == "Variables":
+            self.ClassList = ["Local","Temp"]
+        else:
+            self.ClassList = [self.Filter]
+
+    def RefreshUpDownButtons(self):
+        if self.Filter == "All":
+            self.UpButton.Enable(True)
+            self.DownButton.Enable(True)
+        else:
+            self.UpButton.Enable(False)
+            self.DownButton.Enable(False)
+
+    def OnAddButton(self, event):
+        self.Table.AppendRow(self.DefaultValue.copy())
+        self.Table.ResetView(self.VariablesGrid)
+        event.Skip()
+
+    def OnDeleteButton(self, event):
+        row = self.VariablesGrid.GetGridCursorRow()
+        self.Table.RemoveRow(row)
+        self.Table.ResetView(self.VariablesGrid)
+        event.Skip()
+
+    def OnUpButton(self, event):
+        row = self.VariablesGrid.GetGridCursorRow()
+        self.Table.MoveRow(row, -1, self.VariablesGrid)
+        self.Table.ResetView(self.VariablesGrid)
+        event.Skip()
+
+    def OnDownButton(self, event):
+        row = self.VariablesGrid.GetGridCursorRow()
+        self.Table.MoveRow(row, 1, self.VariablesGrid)
+        self.Table.ResetView(self.VariablesGrid)
+        event.Skip()
+
+    def SetValues(self, values):
+        for item, value in values.items():
+            if item == "returnType" and value and self.ReturnType.IsEnabled():
+                self.ReturnType.SetStringSelection(value)
+            if item == "data":
+                self.Values = value
+        self.RefreshValues()
+                
+    def RefreshValues(self):
+        data = []
+        for variable in self.Values:
+            if variable["Class"] in self.ClassList:
+                data.append(variable)
+        self.Table.SetData(data)
+        self.Table.ResetView(self.VariablesGrid)
+                
+    def GetValues(self):
+        values = {}
+        if self.ReturnType.IsEnabled():
+            values["returnType"] = self.ReturnType.GetStringSelection()
+        values["data"] = self.Table.GetData()
+        return values
+
+#-------------------------------------------------------------------------------
+#                               Exception Handler
+#-------------------------------------------------------------------------------
+
+Max_Traceback_List_Size = 20
+
+def Display_Exception_Dialog(e_type,e_value,e_tb):
+    trcbck_lst = []
+    for i,line in enumerate(traceback.extract_tb(e_tb)):
+        trcbck = " " + str(i+1) + ". "
+        if line[0].find(os.getcwd()) == -1:
+            trcbck += "file : " + str(line[0]) + ",   "
+        else:
+            trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ",   "
+        trcbck += "line : " + str(line[1]) + ",   " + "function : " + str(line[2])
+        trcbck_lst.append(trcbck)
+        
+    # Allow clicking....
+    cap = wx.Window_GetCapture()
+    if cap:
+        cap.ReleaseMouse()
+
+    dlg = wx.SingleChoiceDialog(None, 
+        """
+An error happens.
+
+Click on OK for saving an error report.
+
+Please contact LOLITech at:
++33 (0)3 29 52 95 67
+bugs_PLCOpenEditor@lolitech.fr
+
+
+Error:
+""" +
+        str(e_type) + " : " + str(e_value), 
+        "Error",
+        trcbck_lst)
+    try:
+        res = (dlg.ShowModal() == wx.ID_OK)
+    finally:
+        dlg.Destroy()
+
+    return res
+
+def Display_Error_Dialog(e_value):
+    message = wxMessageDialog(None, str(e_value), "Error", wxOK|wxICON_ERROR)
+    message.ShowModal()
+    message.Destroy()
+
+def get_last_traceback(tb):
+    while tb.tb_next:
+        tb = tb.tb_next
+    return tb
+
+
+def format_namespace(d, indent='    '):
+    return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()])
+
+
+ignored_exceptions = [] # a problem with a line in a module is only reported once per session
+
+def wxAddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
+    
+    def handle_exception(e_type, e_value, e_traceback):
+        traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
+        last_tb = get_last_traceback(e_traceback)
+        ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
+        if str(e_value).startswith("!!!"):
+            Display_Error_Dialog(e_value)
+        elif ex not in ignored_exceptions:
+            result = Display_Exception_Dialog(e_type,e_value,e_traceback)
+            if result:
+                ignored_exceptions.append(ex)
+                info = {
+                    'app-title' : wx.GetApp().GetAppName(), # app_title
+                    'app-version' : app_version,
+                    'wx-version' : wx.VERSION_STRING,
+                    'wx-platform' : wx.Platform,
+                    'python-version' : platform.python_version(), #sys.version.split()[0],
+                    'platform' : platform.platform(),
+                    'e-type' : e_type,
+                    'e-value' : e_value,
+                    'date' : time.ctime(),
+                    'cwd' : os.getcwd(),
+                    }
+                if e_traceback:
+                    info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
+                    last_tb = get_last_traceback(e_traceback)
+                    exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
+                    info['locals'] = format_namespace(exception_locals)
+                    if 'self' in exception_locals:
+                        info['self'] = format_namespace(exception_locals['self'].__dict__)
+                
+                output = open(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w')
+                lst = info.keys()
+                lst.sort()
+                for a in lst:
+                    output.write(a+":\n"+str(info[a])+"\n\n")
+
+    #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
+    sys.excepthook = handle_exception
+
+if __name__ == '__main__':
+    app = wxPySimpleApp()
+    wxInitAllImageHandlers()
+    
+    # Install a exception handle for bug reports
+    wxAddExceptHook(os.getcwd(),__version__)
+    
+    frame = PLCOpenEditor(None)
+
+    frame.Show()
+    app.MainLoop()
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SFCViewer.py	Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,1604 @@
+#!/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): 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 Lesser 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
+#Lesser General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser 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 wxPython.wx import *
+from wxPython.grid import *
+import wx
+from types import *
+
+from plcopen.structures import *
+from graphics.GraphicCommons import *
+from graphics.SFC_Objects import *
+from Viewer import *
+
+class SFC_Viewer(Viewer):
+    
+    def __init__(self, parent, window, controler):
+        Viewer.__init__(self, parent, window, controler)
+    
+    def ConnectConnectors(self, start, end):
+        startpoint = [start.GetPosition(False), start.GetDirection()]
+        endpoint = [end.GetPosition(False), end.GetDirection()]
+        wire = Wire(self, startpoint, endpoint)
+        self.Wires.append(wire)
+        self.Elements.append(wire)
+        start.Connect((wire, 0), False)
+        end.Connect((wire, -1), False)
+        wire.ConnectStartPoint(None, start)
+        wire.ConnectEndPoint(None, end)
+        return wire
+    
+    def CreateTransition(self, connector, next = None):
+        previous = connector.GetParentBlock()
+        id = self.GetNewId()
+        transition = SFC_Transition(self, "reference", "", id)
+        pos = connector.GetPosition(False)
+        transition.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
+        transition_connectors = transition.GetConnectors()
+        wire = self.ConnectConnectors(transition_connectors["input"], connector)
+        if isinstance(previous, SFC_Divergence):
+            previous.RefreshConnectedPosition(connector)
+        else:
+            previous.RefreshOutputPosition()
+        wire.SetPoints([wxPoint(pos.x, pos.y + GetWireSize(previous)), wxPoint(pos.x, pos.y)])
+        self.Blocks.append(transition)
+        self.Elements.append(transition)
+        self.Controler.AddCurrentElementEditingTransition(id)
+        self.RefreshTransitionModel(transition)
+        if next:
+            wire = self.ConnectConnectors(next, transition_connectors["output"])
+            pos = transition_connectors["output"].GetPosition(False)
+            next_block = next.GetParentBlock()
+            next_pos = next.GetPosition(False)
+            transition.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
+            wire.SetPoints([wxPoint(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wxPoint(pos.x, pos.y)])
+            if isinstance(next_block, SFC_Divergence):
+                next_block.RefreshPosition()
+            next_block.RefreshModel()
+        return transition
+    
+    def RemoveTransition(self, transition):
+        connectors = transition.GetConnectors()
+        input_wires = connectors["input"].GetWires()
+        if len(input_wires) != 1:
+            return
+        input_wire = input_wires[0][0]
+        previous = input_wire.EndConnected
+        input_wire.Clean()
+        self.Wires.remove(input_wire)
+        self.Elements.remove(input_wire)
+        output_wires = connectors["output"].GetWires()
+        if len(output_wires) != 1:
+            return
+        output_wire = output_wires[0][0]
+        next = output_wire.StartConnected
+        output_wire.Clean()
+        self.Wires.remove(output_wire)
+        self.Elements.remove(output_wire)
+        transition.Clean()
+        self.Blocks.remove(transition)
+        self.Elements.remove(transition)
+        self.Controler.RemoveCurrentElementEditingInstance(transition.GetId())
+        wire = self.ConnectConnectors(next, previous)
+        return wire
+    
+    def CreateStep(self, name, connector, next = None):
+        previous = connector.GetParentBlock()
+        id = self.GetNewId()
+        step = SFC_Step(self, name, False, id)
+        if next:
+            step.AddOutput()
+        min_width, min_height = step.GetMinSize()
+        pos = connector.GetPosition(False)
+        step.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
+        step.SetSize(min_width, min_height)
+        step_connectors = step.GetConnectors()
+        wire = self.ConnectConnectors(step_connectors["input"], connector)
+        if isinstance(previous, SFC_Divergence):
+            previous.RefreshConnectedPosition(connector)
+        else:
+            previous.RefreshOutputPosition()
+        wire.SetPoints([wxPoint(pos.x, pos.y + GetWireSize(previous)), wxPoint(pos.x, pos.y)])
+        self.Blocks.append(step)
+        self.Elements.append(step)
+        self.Controler.AddCurrentElementEditingStep(id)
+        self.RefreshStepModel(step)
+        if next:
+            wire = self.ConnectConnectors(next, step_connectors["output"])
+            pos = step_connectors["output"].GetPosition(False)
+            next_block = next.GetParentBlock()
+            next_pos = next.GetPosition(False)
+            step.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
+            wire.SetPoints([wxPoint(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wxPoint(pos.x, pos.y)])
+            if isinstance(next_block, SFC_Divergence):
+                next_block.RefreshPosition()
+            next_block.RefreshModel()
+        return step
+
+    def RemoveStep(self, step):
+        connectors = step.GetConnectors()
+        if connectors["input"]:
+            input_wires = connectors["input"].GetWires()
+            if len(input_wires) != 1:
+                return
+            input_wire = input_wires[0][0]
+            previous = input_wire.EndConnected
+            input_wire.Clean()
+            self.Wires.remove(input_wire)
+            self.Elements.remove(input_wire)
+        else:
+            previous = None
+        if connectors["output"]:
+            output_wires = connectors["output"].GetWires()
+            if len(output_wires) != 1:
+                return
+            output_wire = output_wires[0][0]
+            next = output_wire.StartConnected
+            output_wire.Clean()
+            self.Wires.remove(output_wire)
+            self.Elements.remove(output_wire)
+        else:
+            next = None
+        action = step.GetActionConnector()
+        if action:
+            self.DeleteActionBlock(action.GetParentBlock())
+        step.Clean()
+        self.Blocks.remove(step)
+        self.Elements.remove(step)
+        self.Controler.RemoveCurrentElementEditingInstance(step.GetId())
+        if next and previous:
+            wire = self.ConnectConnectors(next, previous)
+            return wire
+        else:
+            return None
+
+#-------------------------------------------------------------------------------
+#                          Mouse event functions
+#-------------------------------------------------------------------------------
+
+    def OnViewerLeftDown(self, event):
+        if self.Mode == MODE_SELECTION:
+            pos = event.GetPosition()
+            if event.ControlDown():
+                element = self.FindElement(pos, True)
+                if element and element not in self.Wires:
+                    if isinstance(self.SelectedElement, Graphic_Group):
+                        self.SelectedElement.SelectElement(element)
+                    else:
+                        group = Graphic_Group(self)
+                        self.SelectedElement.SetSelected(False)
+                        group.SelectElement(self.SelectedElement)
+                        group.SelectElement(element)
+                        self.SelectedElement = group
+                    elements = self.SelectedElement.GetElements()
+                    if len(elements) == 0:
+                        self.SelectedElement = element
+                    elif len(elements) == 1:
+                        self.SelectedElement = elements[0]
+            else:
+                element = self.FindElement(pos)
+                if self.SelectedElement and self.SelectedElement != element:
+                    if self.SelectedElement in self.Wires:
+                        self.SelectedElement.SetSelectedSegment(None)
+                    else:
+                        self.SelectedElement.SetSelected(False)
+                    self.SelectedElement = None
+                    self.Refresh()
+                if element:
+                    self.SelectedElement = element
+                    self.SelectedElement.OnLeftDown(event, self.Scaling)
+                    self.Refresh()
+                else:
+                    self.rubberBand.Reset()
+                    self.rubberBand.OnLeftDown(event, self.Scaling)
+        elif self.Mode == MODE_COMMENT:
+            self.rubberBand.Reset()
+            self.rubberBand.OnLeftDown(event, self.Scaling)
+        elif self.Mode == MODE_WIRE:
+            pos = GetScaledEventPosition(event, self.Scaling)
+            wire = Wire(self, [wxPoint(pos.x, pos.y), SOUTH], [wxPoint(pos.x, pos.y), NORTH])
+            wire.oldPos = pos
+            wire.Handle = (HANDLE_POINT, 0)
+            wire.ProcessDragging(0, 0)
+            wire.Handle = (HANDLE_POINT, 1)
+            self.Wires.append(wire)
+            self.Elements.append(wire)
+            if self.SelectedElement:
+                self.SelectedElement.SetSelected(False)
+            self.SelectedElement = wire
+            self.Refresh()
+        event.Skip()
+
+    def OnViewerLeftUp(self, event):
+        if self.rubberBand.IsShown():
+            if self.Mode == MODE_SELECTION:
+                elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                if len(elements) > 0:
+                    self.SelectedElement = Graphic_Group(self)
+                    self.SelectedElement.SetElements(elements)
+                    self.SelectedElement.SetSelected(True)
+                    self.Refresh()
+            elif self.Mode == MODE_COMMENT:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.Scaling)
+                wxCallAfter(self.AddComment, bbox)
+        elif self.Mode == MODE_INITIAL_STEP:
+            wxCallAfter(self.AddInitialStep, GetScaledEventPosition(event, self.Scaling))
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            if self.SelectedElement in self.Wires:
+                self.SelectedElement.SetSelectedSegment(0)
+            else:
+                self.SelectedElement.OnLeftUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            self.SelectedElement.ResetPoints()
+            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.SelectedElement.GeneratePoints()
+            self.SelectedElement.RefreshModel()
+            self.SelectedElement.SetSelected(True)
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerRightUp(self, event):
+        pos = event.GetPosition()
+        element = self.FindElement(pos)
+        if element:
+            if self.SelectedElement and self.SelectedElement != element:
+                self.SelectedElement.SetSelected(False)
+            self.SelectedElement = element
+            if self.SelectedElement in self.Wires:
+                self.SelectedElement.SetSelectedSegment(0)
+            else:
+                self.SelectedElement.SetSelected(True)
+                self.SelectedElement.OnRightUp(event, self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerLeftDClick(self, event):
+        if self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftDClick(event, self.Scaling)
+            self.Refresh()
+        event.Skip()
+    
+    def OnViewerMotion(self, event):
+        if self.rubberBand.IsShown():
+            self.rubberBand.OnMotion(event, self.Scaling)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            if self.SelectedElement not in self.Wires:
+                self.SelectedElement.OnMotion(event, self.Scaling)
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            self.SelectedElement.ResetPoints()
+            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.SelectedElement.GeneratePoints()
+            self.Refresh()
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Keyboard event functions
+#-------------------------------------------------------------------------------
+
+    def OnChar(self, event):
+        keycode = event.GetKeyCode()
+        if self.Scaling:
+            scaling = self.Scaling
+        else:
+            scaling = (8, 8)
+        if keycode == WXK_DELETE and self.SelectedElement:
+            self.SelectedElement.Delete()
+            self.SelectedElement = None
+        elif keycode == WXK_LEFT and self.SelectedElement:
+            self.SelectedElement.Move(-scaling[0], 0)
+        elif keycode == WXK_RIGHT and self.SelectedElement:
+            self.SelectedElement.Move(scaling[0], 0)
+        elif keycode == WXK_UP and self.SelectedElement:
+            self.SelectedElement.Move(0, -scaling[1])
+        elif keycode == WXK_DOWN and self.SelectedElement:
+            self.SelectedElement.Move(0, scaling[1])
+        self.Refresh()
+        event.Skip()
+        
+#-------------------------------------------------------------------------------
+#                          Adding element functions
+#-------------------------------------------------------------------------------
+
+    def AddInitialStep(self, pos):
+        dialog = wxTextEntryDialog(self.Parent, "Add a new initial step", "Please enter step name", "", wxOK|wxCANCEL)
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            name = dialog.GetValue()
+            step = SFC_Step(self, name, True, id)
+            min_width, min_height = step.GetMinSize()
+            step.SetPosition(pos.x, pos.y)
+            width, height = step.GetSize()
+            step.SetSize(max(min_width, width), max(min_height, height))
+            self.Blocks.append(step)
+            self.Elements.append(step)
+            self.Controler.AddCurrentElementEditingStep(id)
+            self.RefreshStepModel(step)
+            self.Parent.RefreshProjectTree()
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddStep(self):
+        if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, SFC_Step):
+            dialog = wxTextEntryDialog(self.Parent, "Add a new step", "Please enter step name", "", wxOK|wxCANCEL)
+            if dialog.ShowModal() == wxID_OK:
+                name = dialog.GetValue()
+                if self.SelectedElement in self.Wires:
+                    self.SelectedElement.SetSelectedSegment(None)
+                    previous = self.SelectedElement.EndConnected
+                    next = self.SelectedElement.StartConnected
+                    self.SelectedElement.Clean()
+                    self.Wires.remove(self.SelectedElement)
+                    self.Elements.remove(self.SelectedElement)
+                else:
+                    connectors = self.SelectedElement.GetConnectors()
+                    if connectors["output"]:
+                        previous = connectors["output"]
+                        wires = previous.GetWires()
+                        if len(wires) != 1:
+                            return
+                        wire = wires[0][0]
+                        next = wire.StartConnected
+                        wire.Clean()
+                        self.Wires.remove(wire)
+                        self.Elements.remove(wire)
+                    else:
+                        self.SelectedElement.AddOutput()
+                        connectors = self.SelectedElement.GetConnectors()
+                        self.RefreshStepModel(self.SelectedElement)
+                        previous = connectors["output"]
+                        next = None
+                previous_block = previous.GetParentBlock()
+                if isinstance(previous_block, SFC_Step) or isinstance(previous_block, SFC_Divergence) and previous_block.GetType() in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
+                    transition = self.CreateTransition(previous)
+                    transition_connectors = transition.GetConnectors()
+                    step = self.CreateStep(name, transition_connectors["output"], next)
+                else:
+                    step = self.CreateStep(name, previous)
+                    step.AddOutput()
+                    step.RefreshModel()
+                    step_connectors = step.GetConnectors()
+                    transition = self.CreateTransition(step_connectors["output"], next)
+                if self.SelectedElement in self.Wires:
+                    self.SelectedElement = wire
+                    self.SelectedElement.SetSelectedSegment(0)
+                else:
+                    self.SelectedElement.SetSelected(False)
+                    self.SelectedElement = step
+                    self.SelectedElement.SetSelected(True)
+                self.Parent.RefreshProjectTree()
+                self.Refresh()
+            dialog.Destroy()
+    
+    def AddStepAction(self):
+        if isinstance(self.SelectedElement, SFC_Step):
+            connectors = self.SelectedElement.GetConnectors()
+            if not connectors["action"]:
+                dialog = ActionBlockDialog(self.Parent)
+                dialog.SetQualifierList(self.Controler.GetQualifierTypes())
+                dialog.SetActionList(self.Controler.GetCurrentElementEditingActions())
+                dialog.SetVariableList(self.Controler.GetCurrentElementEditingInterfaceVars())
+                if dialog.ShowModal() == wxID_OK:
+                    actions = dialog.GetValues()
+                    self.SelectedElement.AddAction()
+                    self.RefreshStepModel(self.SelectedElement)
+                    connectors = self.SelectedElement.GetConnectors()
+                    pos = connectors["action"].GetPosition(False)
+                    id = self.GetNewId()
+                    ac