Current developping version
authorlbessard
Mon, 09 Jul 2007 11:10:14 +0200
changeset 27 dae55dd9ee14
parent 26 36d378bd852e
child 28 fc23e1f415d8
Current developping version
Dialogs.py
FBDViewer.py
Images/coil.png
Images/coil.svg
Images/powerrail.png
Images/powerrail.svg
Images/rung.png
Images/rung.svg
LDViewer.py
PLCControler.py
PLCOpenEditor.py
RessourceEditor.py
SFCViewer.py
TextViewer.py
Viewer.py
examples/example.xml
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
plcopen/TC6_XML_V10_B.xsd
plcopen/plcopen.py
plcopen/structures.py
test.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dialogs.py	Mon Jul 09 11:10:14 2007 +0200
@@ -0,0 +1,1526 @@
+#!/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 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 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 graphics.FBD_Objects import *
+from graphics.LD_Objects import *
+from graphics.SFC_Objects import *
+
+#-------------------------------------------------------------------------------
+#                          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)]
+
+[CATEGORY, BLOCK] = range(2)
+
+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=wxSP_ARROW_KEYS, 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|wxCENTRE)
+        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 FindTreeItem(self, root, name):
+        if root.IsOk():
+            if self.TypeTree.GetItemText(root) == name:
+                return root
+            else:
+                item, root_cookie = self.TypeTree.GetFirstChild(root)
+                while item.IsOk():
+                    result = self.FindTreeItem(item, name)
+                    if result:
+                        return result
+                    item, root_cookie = self.TypeTree.GetNextChild(root, root_cookie)
+        return None
+    
+    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("")
+        self.TypeTree.SetPyData(root, CATEGORY)
+        for category in blocktypes:
+            category_item = self.TypeTree.AppendItem(root, category["name"])
+            self.TypeTree.SetPyData(category_item, CATEGORY)
+            for blocktype in category["list"]:
+                blocktype_item = self.TypeTree.AppendItem(category_item, blocktype["name"])
+                self.TypeTree.SetPyData(blocktype_item, BLOCK)
+
+    def SetMinBlockSize(self, size):
+        self.MinBlockSize = size
+
+    def SetValues(self, values):
+        for name, value in values.items():
+            if name == "type":
+                item = self.FindTreeItem(self.TypeTree.GetRootItem(), value)
+                if item:
+                    self.TypeTree.SelectItem(item)
+            elif name == "name":
+                self.Name.SetValue(value)
+            elif name == "extension":
+                self.Inputs.SetValue(value)
+        self.RefreshPreview()
+
+    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.GetPyData(selected) != CATEGORY:
+            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()
+        item = self.TypeTree.GetSelection()
+        if self.TypeTree.GetPyData(item) == CATEGORY:
+            self.Block = None
+        else:
+            blocktype = self.TypeTree.GetItemText(item)
+            if blocktype:
+                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)
+            else:
+                self.Block = None
+
+    def OnPaint(self, event):
+        if self.Block:
+            self.RefreshPreview()
+
+
+#-------------------------------------------------------------------------------
+#                          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, 78), 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|wxCENTRE)
+        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"]:
+                self.Name.Append(name)
+            elif var_type == "Input" and self.Class.GetStringSelection() == "Input":
+                self.Name.Append(name)
+            elif var_type == "Output" and self.Class.GetStringSelection() == "Output":
+                self.Name.Append(name)
+            elif var_type == "InOut" and self.Class.GetStringSelection() == "InOut":
+                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 SetValues(self, values):
+        for name, value in values.items():
+            if name == "type":
+                if value == INPUT:
+                    self.Class.SetStringSelection("Input")
+                if value == OUTPUT:
+                    self.Class.SetStringSelection("Output")
+                if value == INOUT:
+                    self.Class.SetStringSelection("InOut")
+            elif name == "name":
+                self.Name.SetStringSelection(value)
+        self.RefreshPreview()
+        
+    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|wxCENTRE)
+        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()
+
+
+#-------------------------------------------------------------------------------
+#                        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='Modifier:', 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','Negate','Rising Edge','Falling Edge'])
+            self.Element = LD_Contact(self.Preview, CONTACT_NORMAL, "")
+        elif type == "coil":
+            self._init_ctrls(parent, "Edit Coil Values", ['Normal','Negate','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|wxCENTRE)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+
+        EVT_PAINT(self, self.OnPaint)
+
+    def SetElementSize(self, width, height):
+        min_width, min_height = self.Element.GetMinSize()
+        width, height = max(min_width, width), max(min_height, height)
+        self.Element.SetSize(width, height)
+        self.Element.SetPosition((150 - width) / 2, (150 - height) / 2)
+
+    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()
+        values["width"], values["height"] = self.Element.GetSize()
+        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()
+
+
+#-------------------------------------------------------------------------------
+#                      Edit Ladder Power Rail Properties Dialog
+#-------------------------------------------------------------------------------
+
+
+[wxID_LDPOWERRAILDIALOG, wxID_LDPOWERRAILDIALOGMAINPANEL, 
+ wxID_LDPOWERRAILDIALOGTYPE, wxID_LDPOWERRAILDIALOGRADIOBUTTON1, 
+ wxID_LDPOWERRAILDIALOGRADIOBUTTON2, wxID_LDPOWERRAILDIALOGPREVIEW,
+ wxID_LDPOWERRAILDIALOGSTATICTEXT1, wxID_LDPOWERRAILDIALOGSTATICTEXT2, 
+ wxID_LDPOWERRAILDIALOGSTATICTEXT3, wxID_LDPOWERRAILDIALOGPINNUMBER,
+] = [wx.NewId() for _init_ctrls in range(10)]
+
+class LDPowerRailDialog(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_LDPOWERRAILDIALOG,
+              name='PowerRailDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(350, 260), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Power Rail Properties')
+        self.SetClientSize(wx.Size(350, 260))
+
+        self.MainPanel = wx.Panel(id=wxID_LDPOWERRAILDIALOGMAINPANEL,
+              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_LDPOWERRAILDIALOGSTATICTEXT1,
+              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_LDPOWERRAILDIALOGSTATICTEXT2,
+              label='Pin number:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 100), size=wx.Size(70, 17), style=0)
+
+        self.staticText3 = wx.StaticText(id=wxID_LDPOWERRAILDIALOGSTATICTEXT3,
+              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_LDPOWERRAILDIALOGRADIOBUTTON1,
+              label='Left PowerRail', name='radioButton1', parent=self.MainPanel,
+              pos=wx.Point(24, 48), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDPOWERRAILDIALOGRADIOBUTTON1, self.OnTypeChanged)
+        self.radioButton1.SetValue(True)
+
+        self.radioButton2 = wx.RadioButton(id=wxID_LDPOWERRAILDIALOGRADIOBUTTON2,
+              label='Right PowerRail', name='radioButton2', parent=self.MainPanel, 
+              pos=wx.Point(24, 72), size=wx.Size(128, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_LDPOWERRAILDIALOGRADIOBUTTON2, self.OnTypeChanged)
+
+        self.PinNumber = wx.SpinCtrl(id=wxID_LDPOWERRAILDIALOGPINNUMBER,
+              name='PinNumber', parent=self.MainPanel, pos=wx.Point(24, 124),
+              size=wx.Size(145, 24), style=wxSP_ARROW_KEYS, min=1, max=20)
+        EVT_SPINCTRL(self, wxID_LDPOWERRAILDIALOGPINNUMBER, self.OnPinNumberChanged)
+
+        self.Preview = wx.Panel(id=wxID_LDPOWERRAILDIALOGPREVIEW,
+              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 = LEFTRAIL, number = 1):
+        self._init_ctrls(parent)
+        self.Type = type
+        if type == LEFTRAIL:
+            self.radioButton1.SetValue(True)
+        elif type == RIGHTRAIL:
+            self.radioButton2.SetValue(True)
+        self.PinNumber.SetValue(number)
+        
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL|wxCENTRE)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+
+        self.PowerRailMinSize = (0, 0)
+        self.PowerRail = None
+
+        EVT_PAINT(self, self.OnPaint)
+
+    def SetMinSize(self, size):
+        self.PowerRailMinSize = size
+        self.RefreshPreview()
+
+    def GetValues(self):
+        values = {}
+        values["type"] = self.Type
+        values["number"] = self.PinNumber.GetValue()
+        values["width"], values["height"] = self.PowerRail.GetSize()
+        return values
+
+    def OnTypeChanged(self, event):
+        if self.radioButton1.GetValue():
+            self.Type = LEFTRAIL
+        elif self.radioButton2.GetValue():
+            self.Type = RIGHTRAIL
+        self.RefreshPreview()
+        event.Skip()
+
+    def OnPinNumberChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        self.PowerRail = LD_PowerRail(self.Preview, self.Type, connectors = [True for i in xrange(self.PinNumber.GetValue())])
+        min_width, min_height = self.PowerRail.GetMinSize()
+        width, height = max(min_width, self.PowerRailMinSize[0]), max(min_height, self.PowerRailMinSize[1])
+        self.PowerRail.SetSize(width, height)
+        self.PowerRail.RefreshConnectors()
+        self.PowerRail.SetPosition((150 - width) / 2, (150 - height) / 2)
+        self.PowerRail.Draw(dc)
+
+    def OnPaint(self, event):
+        self.RefreshPreview()
+        event.Skip()
+
+
+#-------------------------------------------------------------------------------
+#                          Edit Transition Content Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_TRANSITIONCONTENTDIALOG, wxID_TRANSITIONCONTENTDIALOGMAINPANEL, 
+ wxID_TRANSITIONCONTENTDIALOGREFERENCE, wxID_TRANSITIONCONTENTDIALOGINLINE, 
+ wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, 
+] = [wx.NewId() for _init_ctrls in range(6)]
+
+class TransitionContentDialog(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_TRANSITIONCONTENTDIALOG,
+              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Edit transition')
+        self.SetClientSize(wx.Size(300, 200))
+
+        self.MainPanel = wx.Panel(id=wxID_TRANSITIONCONTENTDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(300, 200), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.radioButton1 = wx.RadioButton(id=wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1,
+              label='Reference', name='radioButton1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, self.OnTypeChanged)
+        self.radioButton1.SetValue(True)
+
+        self.Reference = wx.Choice(id=wxID_TRANSITIONCONTENTDIALOGREFERENCE,
+              name='Reference', parent=self.MainPanel, pos=wx.Point(48, 48), 
+              size=wx.Size(200, 24), style=0)
+
+        self.radioButton2 = wx.RadioButton(id=wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2,
+              label='Inline', name='radioButton2', parent=self.MainPanel,
+              pos=wx.Point(24, 72), size=wx.Size(114, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, self.OnTypeChanged)
+        self.radioButton2.SetValue(False)
+
+        self.Inline = wx.TextCtrl(id=wxID_TRANSITIONCONTENTDIALOGINLINE,
+              name='Inline', parent=self.MainPanel, pos=wx.Point(48, 96),
+              size=wx.Size(200, 24), style=0)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL|wxCENTRE)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        
+        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
+    
+    def OnOK(self, event):
+        error = []
+        if self.radioButton1.GetValue() and self.Reference.GetStringSelection() == "":
+            error.append("Reference")
+        if self.radioButton2.GetValue() and self.Inline.GetValue() == "":
+            error.append("Inline")
+        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 OnTypeChanged(self, event):
+        if self.radioButton1.GetValue():
+            self.Reference.Enable(True)
+            self.Inline.Enable(False)
+        else:
+            self.Reference.Enable(False)
+            self.Inline.Enable(True)
+        event.Skip()
+
+    def SetTransitions(self, transitions):
+        for transition in transitions:
+            self.Reference.Append(transition)
+
+    def SetValues(self, values):
+        if values["type"] == "reference":
+            self.radioButton1.SetValue(True)
+            self.radioButton2.SetValue(False)
+            self.Reference.Enable(True)
+            self.Inline.Enable(False)
+            self.Reference.SetStringSelection(values["value"])
+        elif values["type"] == "inline":
+            self.radioButton1.SetValue(False)
+            self.radioButton2.SetValue(True)
+            self.Reference.Enable(False)
+            self.Inline.Enable(True)
+            self.Inline.SetValue(values["value"])
+                
+    def GetValues(self):
+        values = {}
+        if self.radioButton1.GetValue():
+            values["type"] = "reference"
+            values["value"] = self.Reference.GetStringSelection()
+        else:
+            values["type"] = "inline"
+            values["value"] = self.Inline.GetValue()
+        return values
+
+#-------------------------------------------------------------------------------
+#                         Create New Divergence Dialog
+#-------------------------------------------------------------------------------
+
+[wxID_DIVERGENCECREATEDIALOG, wxID_DIVERGENCECREATEDIALOGMAINPANEL, 
+ wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2,
+ wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4, 
+ wxID_DIVERGENCECREATEDIALOGSEQUENCES, wxID_DIVERGENCECREATEDIALOGPREVIEW, 
+ wxID_DIVERGENCECREATEDIALOGSTATICTEXT1, wxID_DIVERGENCECREATEDIALOGSTATICTEXT2, 
+ wxID_DIVERGENCECREATEDIALOGSTATICTEXT3,  
+] = [wx.NewId() for _init_ctrls in range(11)]
+
+class DivergenceCreateDialog(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_DIVERGENCECREATEDIALOG,
+              name='DivergencePropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Create a new divergence or convergence')
+        self.SetClientSize(wx.Size(500, 260))
+
+        self.MainPanel = wx.Panel(id=wxID_DIVERGENCECREATEDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(600, 220), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT1,
+              label='Type:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(200, 17), style=0)
+
+        self.radioButton1 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1,
+              label='Selection Divergence', name='radioButton1', parent=self.MainPanel,
+              pos=wx.Point(24, 48), size=wx.Size(200, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1, self.OnTypeChanged)
+        self.radioButton1.SetValue(True)
+
+        self.radioButton2 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2,
+              label='Selection Convergence', name='radioButton2', parent=self.MainPanel, 
+              pos=wx.Point(24, 72), size=wx.Size(200, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2, self.OnTypeChanged)
+        self.radioButton2.SetValue(False)
+
+        self.radioButton3 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3,
+              label='Simultaneous Divergence', name='radioButton3', parent=self.MainPanel,
+              pos=wx.Point(24, 96), size=wx.Size(200, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3, self.OnTypeChanged)
+        self.radioButton3.SetValue(False)
+
+        self.radioButton4 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4,
+              label='Simultaneous Convergence', name='radioButton4', parent=self.MainPanel, 
+              pos=wx.Point(24, 120), size=wx.Size(200, 24), style=0)
+        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4, self.OnTypeChanged)
+        self.radioButton4.SetValue(False)
+
+        self.staticText2 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT2,
+              label='Number of sequences:', name='staticText2', parent=self.MainPanel,
+              pos=wx.Point(24, 150), size=wx.Size(200, 17), style=0)
+
+        self.Sequences = wx.SpinCtrl(id=wxID_DIVERGENCECREATEDIALOGSEQUENCES,
+              name='Sequences', parent=self.MainPanel, pos=wx.Point(24, 174),
+              size=wx.Size(200, 24), style=0, min=2, max=20)
+        EVT_SPINCTRL(self, wxID_DIVERGENCECREATEDIALOGSEQUENCES, self.OnSequencesChanged)
+
+        self.staticText3 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT3,
+              label='Preview:', name='staticText3', parent=self.MainPanel,
+              pos=wx.Point(250, 24), size=wx.Size(100, 17), style=0)
+
+        self.Preview = wx.Panel(id=wxID_DIVERGENCECREATEDIALOGPREVIEW,
+              name='Preview', parent=self.MainPanel, pos=wx.Point(250, 48),
+              size=wx.Size(225, 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|wxCENTRE)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        
+        self.Divergence = None
+        self.MinSize = (0, 0)
+        
+        EVT_PAINT(self, self.OnPaint)
+
+    def GetValues(self):
+        values = {}
+        if self.radioButton1.GetValue():
+            values["type"] = SELECTION_DIVERGENCE
+        elif self.radioButton2.GetValue():
+            values["type"] = SELECTION_CONVERGENCE
+        elif self.radioButton3.GetValue():
+            values["type"] = SIMULTANEOUS_DIVERGENCE
+        else:
+            values["type"] = SIMULTANEOUS_CONVERGENCE
+        values["number"] = self.Sequences.GetValue()
+        return values
+
+    def SetMinSize(self, size):
+        self.MinSize = size
+
+    def OnTypeChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+
+    def OnSequencesChanged(self, event):
+        self.RefreshPreview()
+        event.Skip()
+        
+    def RefreshPreview(self):
+        dc = wxClientDC(self.Preview)
+        dc.Clear()
+        if self.radioButton1.GetValue():
+            self.Divergence = SFC_Divergence(self.Preview, SELECTION_DIVERGENCE, self.Sequences.GetValue())
+        elif self.radioButton2.GetValue():
+            self.Divergence = SFC_Divergence(self.Preview, SELECTION_CONVERGENCE, self.Sequences.GetValue())
+        elif self.radioButton3.GetValue():
+            self.Divergence = SFC_Divergence(self.Preview, SIMULTANEOUS_DIVERGENCE, self.Sequences.GetValue())
+        else:
+            self.Divergence = SFC_Divergence(self.Preview, SIMULTANEOUS_CONVERGENCE, self.Sequences.GetValue())
+        width, height = self.Divergence.GetSize()
+        min_width, min_height = max(width, self.MinSize[0]), max(height, self.MinSize[1])
+        self.Divergence.SetSize(min_width, min_height)
+        clientsize = self.Preview.GetClientSize()
+        x = (clientsize.width - min_width) / 2
+        y = (clientsize.height - min_height) / 2
+        self.Divergence.SetPosition(x, y)
+        self.Divergence.Draw(dc)
+
+    def OnPaint(self, event):
+        self.RefreshPreview()
+
+
+#-------------------------------------------------------------------------------
+#                            Action Block Dialog
+#-------------------------------------------------------------------------------
+
+class ActionTable(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
+                readonly = False
+                colname = self.GetColLabelValue(col)
+                if colname == "Qualifier":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.QualifierList)
+                if colname == "Duration":
+                    editor = wxGridCellTextEditor()
+                    renderer = wxGridCellStringRenderer()
+                    if self.Parent.DurationList[self.data[row]["Qualifier"]]:
+                        readonly = False
+                    else:
+                        readonly = True
+                        self.data[row]["Duration"] = ""
+                elif colname == "Type":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.TypeList)
+                elif colname == "Value":
+                    type = self.data[row]["Type"]
+                    if type == "Action":
+                        editor = wxGridCellChoiceEditor()
+                        editor.SetParameters(self.Parent.ActionList)
+                    elif type == "Variable":
+                        editor = wxGridCellChoiceEditor()
+                        editor.SetParameters(self.Parent.VariableList)
+                    elif type == "Inline":
+                        editor = wxGridCellTextEditor()
+                        renderer = wxGridCellStringRenderer()
+                elif colname == "Indicator":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.VariableList)
+                    
+                grid.SetCellEditor(row, col, editor)
+                grid.SetCellRenderer(row, col, renderer)
+                grid.SetReadOnly(row, col, readonly)
+                
+                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_ACTIONBLOCKDIALOG, wxID_ACTIONBLOCKDIALOGMAINPANEL, 
+ wxID_ACTIONBLOCKDIALOGVARIABLESGRID, wxID_ACTIONBLOCKDIALOGSTATICTEXT1, 
+ wxID_ACTIONBLOCKDIALOGADDBUTTON,wxID_ACTIONBLOCKDIALOGDELETEBUTTON, 
+ wxID_ACTIONBLOCKDIALOGUPBUTTON, wxID_ACTIONBLOCKDIALOGDOWNBUTTON, 
+] = [wx.NewId() for _init_ctrls in range(8)]
+
+class ActionBlockDialog(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_ACTIONBLOCKDIALOG,
+              name='ActionBlockDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE,
+              title='Edit action block properties')
+        self.SetClientSize(wx.Size(500, 300))
+
+        self.MainPanel = wx.Panel(id=wxID_ACTIONBLOCKDIALOGMAINPANEL,
+              name='MainPanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
+        self.MainPanel.SetAutoLayout(True)
+
+        self.staticText1 = wx.StaticText(id=wxID_ACTIONBLOCKDIALOGSTATICTEXT1,
+              label='Actions:', name='staticText1', parent=self.MainPanel,
+              pos=wx.Point(24, 24), size=wx.Size(95, 17), style=0)
+
+        self.ActionsGrid = wx.grid.Grid(id=wxID_ACTIONBLOCKDIALOGVARIABLESGRID,
+              name='ActionsGrid', parent=self.MainPanel, pos=wx.Point(24, 44), 
+              size=wx.Size(450, 150), style=wxVSCROLL)
+        self.ActionsGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+              'Sans'))
+        self.ActionsGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+              False, 'Sans'))
+        self.ActionsGrid.DisableDragGridSize()
+        self.ActionsGrid.EnableScrolling(False, True)
+        EVT_GRID_CELL_CHANGE(self.ActionsGrid, self.OnActionsGridCellChange)
+
+        self.AddButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGADDBUTTON, label='Add',
+              name='AddButton', parent=self.MainPanel, pos=wx.Point(245, 204),
+              size=wx.Size(72, 32), style=0)
+        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGADDBUTTON, self.OnAddButton)
+
+        self.DeleteButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGDELETEBUTTON, label='Delete',
+              name='DeleteButton', parent=self.MainPanel, pos=wx.Point(325, 204),
+              size=wx.Size(72, 32), style=0)
+        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGDELETEBUTTON, self.OnDeleteButton)
+
+        self.UpButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGUPBUTTON, label='^',
+              name='UpButton', parent=self.MainPanel, pos=wx.Point(405, 204),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGUPBUTTON, self.OnUpButton)
+
+        self.DownButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGDOWNBUTTON, label='v',
+              name='DownButton', parent=self.MainPanel, pos=wx.Point(445, 204),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGDOWNBUTTON, self.OnDownButton)
+
+        self._init_sizers()
+
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL|wxCENTRE)
+        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
+        
+        self.DefaultValue = {"Qualifier" : "N", "Duration" : "", "Type" : "Action", "Value" : "", "Indicator" : ""}
+        self.Table = ActionTable(self, [], ["Qualifier","Duration","Type","Value","Indicator"])
+        self.TypeList = "Action,Variable,Inline"
+        self.ColSizes = [60, 90, 80, 110, 80]
+        self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT]
+        
+        self.ActionsGrid.SetTable(self.Table)
+        self.ActionsGrid.SetRowLabelSize(0)
+        
+        self.Table.ResetView(self.ActionsGrid)
+
+    def OnAddButton(self, event):
+        self.Table.AppendRow(self.DefaultValue.copy())
+        self.Table.ResetView(self.ActionsGrid)
+        event.Skip()
+
+    def OnDeleteButton(self, event):
+        row = self.ActionsGrid.GetGridCursorRow()
+        self.Table.RemoveRow(row)
+        self.Table.ResetView(self.ActionsGrid)
+        event.Skip()
+
+    def OnUpButton(self, event):
+        row = self.ActionsGrid.GetGridCursorRow()
+        self.Table.MoveRow(row, -1, self.ActionsGrid)
+        self.Table.ResetView(self.ActionsGrid)
+        event.Skip()
+
+    def OnDownButton(self, event):
+        row = self.ActionsGrid.GetGridCursorRow()
+        self.Table.MoveRow(row, 1, self.ActionsGrid)
+        self.Table.ResetView(self.ActionsGrid)
+        event.Skip()
+
+    def OnActionsGridCellChange(self, event):
+        self.Table.ResetView(self.ActionsGrid)
+        event.Skip()
+
+    def SetQualifierList(self, list):
+        self.QualifierList = ""
+        sep = ""
+        for qualifier in list.keys():
+            self.QualifierList += "%s%s"%(sep, qualifier)
+            sep = ","
+        self.DurationList = list
+
+    def SetVariableList(self, list):
+        self.VariableList = ""
+        sep = ""
+        for variable in list:
+            self.VariableList += "%s%s"%(sep, variable["Name"])
+            sep = ","
+
+    def SetActionList(self, list):
+        self.ActionList = ""
+        sep = ""
+        for action in list:
+            self.ActionList += "%s%s"%(sep, action)
+            sep = ","
+
+    def SetValues(self, actions):
+        for action in actions:
+            row = {"Qualifier" : action["qualifier"], "Value" : action["value"]}
+            if action["type"] == "reference":
+                if action["value"] in self.ActionList:
+                    row["Type"] = "Action"
+                elif action["value"] in self.VariableList:
+                    row["Type"] = "Variable"
+                else:
+                    row["Type"] = "Inline"
+            else:
+                row["Type"] = "Inline"
+            if "duration" in action:
+                row["Duration"] = action["duration"]
+            else:
+                row["Duration"] = ""
+            if "indicator" in action:
+                row["Indicator"] = action["indicator"]
+            else:
+                row["Indicator"] = ""
+            self.Table.AppendRow(row)
+        self.Table.ResetView(self.ActionsGrid)
+    
+    def GetValues(self):
+        values = []
+        for data in self.Table.GetData():
+            print data
+            action = {"qualifier" : data["Qualifier"], "value" : data["Value"]}
+            if data["Type"] in ["Action", "Variable"]:
+                action["type"] = "reference"
+            else:
+                action["type"] = "inline"
+            if data["Duration"] != "":
+                action["duration"] = data["Duration"]
+            if data["Indicator"] != "":
+                action["indicator"] = data["Indicator"]
+            values.append(action)
+        return values
+
+
+#-------------------------------------------------------------------------------
+#                          Edit Step Name Dialog
+#-------------------------------------------------------------------------------
+
+class StepNameDialog(wxTextEntryDialog):
+
+    def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", 
+                       style = wxOK|wxCANCEL|wxCENTRE, pos = wxDefaultPosition):
+        wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
+        
+        self.PouNames = []
+        self.Variables = []
+        self.StepNames = []
+        
+        EVT_BUTTON(self, self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId(), self.OnOK)
+        
+    def OnOK(self, event):
+        step_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
+        if step_name == "":
+            message = wxMessageDialog(self, "You must type a name!", "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif not TestIdentifier(step_name):
+            message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%step_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif step_name.upper() in IEC_KEYWORDS:
+            message = wxMessageDialog(self, "\"%s\" is a keyword. It can't be used!"%step_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif step_name.upper() in self.PouNames:
+            message = wxMessageDialog(self, "A pou with \"%s\" as name exists!"%step_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif step_name.upper() in self.Variables:
+            message = wxMessageDialog(self, "A variable with \"%s\" as name exists!"%step_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        elif step_name.upper() in self.StepNames:
+            message = wxMessageDialog(self, "\"%s\" step already exists!"%step_name, "Error", wxOK|wxICON_ERROR)
+            message.ShowModal()
+            message.Destroy()
+        else:
+            self.EndModal(wxID_OK)
+
+    def SetPouNames(self, pou_names):
+        self.PouNames = [pou_name.upper() for pou_name in pou_names]
+
+    def SetVariables(self, variables):
+        self.Variables = [var["Name"].upper() for var in variables]
+
+    def SetStepNames(self, step_names):
+        self.StepNames = [step_name.upper() for step_name in step_names]
+
--- a/FBDViewer.py	Sat Jul 07 11:35:17 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,905 +0,0 @@
-#!/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 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 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)
-            connector = self.FindBlockConnector(pos)
-            if connector:
-                if (connector.GetDirection() == EAST):
-                    wire = Wire(self, [wxPoint(pos.x, pos.y), EAST], [wxPoint(pos.x, pos.y), WEST])
-                else:
-                    wire = Wire(self, [wxPoint(pos.x, pos.y), WEST], [wxPoint(pos.x, pos.y), EAST])
-                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
-            elif self.SelectedElement:
-                self.SelectedElement.SetSelected(False)
-                self.SelectedElement = None
-            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:
-            pos = GetScaledEventPosition(event, self.Scaling)
-            connector = self.FindBlockConnector(pos, False)
-            if connector and connector != self.SelectedElement.StartConnected:
-                self.SelectedElement.ResetPoints()
-                self.SelectedElement.OnMotion(event, self.Scaling)
-                self.SelectedElement.GeneratePoints()
-                self.SelectedElement.RefreshModel()
-                self.SelectedElement.SetSelected(True)
-            else:
-                self.SelectedElement.Delete()
-                self.SelectedElement = None
-            self.Refresh()
-        if not self.SavedMode:
-            wxCallAfter(self.Parent.ResetCurrentMode)
-        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:
-            pos = GetScaledEventPosition(event, self.Scaling)
-            connector = self.FindBlockConnector(pos, False)
-            if not connector or self.SelectedElement.EndConnected == None:
-                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.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.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.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()
-
-    def DeleteVariable(self, variable):
-        wires = []
-        if variable.GetType() == INPUT:
-            connector = variable.GetConnector()
-            wires.extend([wire[0] for wire in connector.GetWires()])
-        variable.Clean()
-        self.Blocks.remove(variable)
-        self.Elements.remove(variable)
-        self.Controler.RemoveCurrentElementEditingInstance(variable.GetId())
-        for wire in wires:
-            wire.RefreshModel()
-
-    def DeleteConnection(self, connection):
-        wires = []
-        if connection.GetType() == CONTINUATION:
-            connector = connection.GetConnector()
-            wires.extend([wire[0] for wire in connector.GetWires()])
-        connection.Clean()
-        self.Blocks.remove(connection)
-        self.Elements.remove(connection)
-        self.Controler.RemoveCurrentElementEditingInstance(connection.GetId())
-        for wire in wires:
-            wire.RefreshModel()
-
-    def DeleteComment(self, comment):
-        self.Elements.remove(comment)
-        self.Controler.RemoveCurrentElementEditingInstance(comment.GetId())
-
-    def DeleteWire(self, wire):
-        connected = wire.GetConnected()
-        wire.Clean()
-        self.Wires.remove(wire)
-        self.Elements.remove(wire)
-        for connector in connected:
-            connector.RefreshParentBlock()
-
-#-------------------------------------------------------------------------------
-#                          Edit element content functions
-#-------------------------------------------------------------------------------
-
-    def EditBlockContent(self, block):
-        dialog = BlockPropertiesDialog(self.Parent)
-        dialog.SetBlockList(self.Controler.GetBlockTypes())
-        dialog.SetMinBlockSize(block.GetSize())
-        values = {"name" : block.GetName(), "type" : block.GetType()}
-        values["extension"] = block.GetExtension()
-        dialog.SetValues(values)
-        if dialog.ShowModal() == wxID_OK:
-            values = dialog.GetValues()
-            if "name" in values:
-                block.SetName(values["name"])
-            block.SetExtension(values["extension"])
-            block.SetSize(values["width"], values["height"])
-            block.SetType(values["type"])
-            self.RefreshBlockModel(block)
-            self.Refresh()
-        dialog.Destroy()
-
-    def EditVariableContent(self, variable):
-        dialog = VariablePropertiesDialog(self.Parent)
-        dialog.SetMinVariableSize(variable.GetSize())
-        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)
-        values = {"name" : variable.GetName(), "type" : variable.GetType()}
-        dialog.SetValues(values)
-        if dialog.ShowModal() == wxID_OK:
-            old_type = variable.GetType()
-            values = dialog.GetValues()
-            variable.SetName(values["name"])
-            variable.SetType(values["type"], values["value_type"])
-            variable.SetSize(values["width"], values["height"])
-            if old_type != values["type"]:
-                id = variable.GetId()
-                self.Controler.RemoveCurrentElementEditingInstance(id)
-                self.Controler.AddCurrentElementEditingVariable(id, values["type"])
-            self.RefreshVariableModel(variable)
-            self.Refresh()
-        dialog.Destroy()
-
-#-------------------------------------------------------------------------------
-#                          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)]
-
-[CATEGORY, BLOCK] = range(2)
-
-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|wxCENTRE)
-        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 FindTreeItem(self, root, name):
-        if root.IsOk():
-            if self.TypeTree.GetItemText(root) == name:
-                return root
-            else:
-                item, root_cookie = self.TypeTree.GetFirstChild(root)
-                while item.IsOk():
-                    result = self.FindTreeItem(item, name)
-                    if result:
-                        return result
-                    item, root_cookie = self.TypeTree.GetNextChild(root, root_cookie)
-        return None
-    
-    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("")
-        self.TypeTree.SetPyData(root, CATEGORY)
-        for category in blocktypes:
-            category_item = self.TypeTree.AppendItem(root, category["name"])
-            self.TypeTree.SetPyData(category_item, CATEGORY)
-            for blocktype in category["list"]:
-                blocktype_item = self.TypeTree.AppendItem(category_item, blocktype["name"])
-                self.TypeTree.SetPyData(blocktype_item, BLOCK)
-
-    def SetMinBlockSize(self, size):
-        self.MinBlockSize = size
-
-    def SetValues(self, values):
-        for name, value in values.items():
-            if name == "type":
-                item = self.FindTreeItem(self.TypeTree.GetRootItem(), value)
-                if item:
-                    self.TypeTree.SelectItem(item)
-            elif name == "name":
-                self.Name.SetValue(value)
-            elif name == "extension":
-                self.Inputs.SetValue(value)
-        self.RefreshPreview()
-
-    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.GetPyData(selected) != CATEGORY:
-            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()
-        item = self.TypeTree.GetSelection()
-        if self.TypeTree.GetPyData(item) == CATEGORY:
-            self.Block = None
-        else:
-            blocktype = self.TypeTree.GetItemText(item)
-            if blocktype:
-                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)
-            else:
-                self.Block = None
-
-    def OnPaint(self, event):
-        if self.Block:
-            self.RefreshPreview()
-
-
-#-------------------------------------------------------------------------------
-#                          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, 78), 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|wxCENTRE)
-        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 SetValues(self, values):
-        for name, value in values.items():
-            if name == "type":
-                if value == INPUT:
-                    self.Class.SetStringSelection("Input")
-                if value == OUTPUT:
-                    self.Class.SetStringSelection("Output")
-                if value == INOUT:
-                    self.Class.SetStringSelection("InOut")
-            elif name == "name":
-                self.Name.SetStringSelection(value)
-        self.RefreshPreview()
-        
-    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|wxCENTRE)
-        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()
-
Binary file Images/coil.png has changed
--- a/Images/coil.svg	Sat Jul 07 11:35:17 2007 +0200
+++ b/Images/coil.svg	Mon Jul 09 11:10:14 2007 +0200
@@ -12,13 +12,14 @@
    height="25"
    id="svg2"
    sodipodi:version="0.32"
-   inkscape:version="0.44"
+   inkscape:version="0.45.1"
    version="1.0"
-   inkscape:export-filename="/mnt/nfs/Pim/workspace_laurent/PLCOpenEditor/Images/coil.png"
+   inkscape:export-filename="/taf/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">
+   sodipodi:docbase="/taf/Pim/workspace_laurent/plcopeneditor/Images"
+   sodipodi:docname="coil.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs4" />
   <sodipodi:namedview
@@ -28,7 +29,7 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="2.8284271"
+     inkscape:zoom="5.6568542"
      inkscape:cx="11.347815"
      inkscape:cy="11.723796"
      inkscape:document-units="px"
@@ -38,7 +39,7 @@
      showgrid="true"
      inkscape:grid-points="true"
      inkscape:window-width="1272"
-     inkscape:window-height="960"
+     inkscape:window-height="937"
      inkscape:window-x="0"
      inkscape:window-y="0" />
   <metadata
@@ -58,9 +59,9 @@
      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 "
+       d="M 0,15 L 0,16 L 6,16 L 6,15 L 0,15 z "
        id="rect4559"
-       sodipodi:nodetypes="ccccccccc"
+       sodipodi:nodetypes="ccccc"
        inkscape:export-xdpi="90"
        inkscape:export-ydpi="90" />
     <text
@@ -76,9 +77,9 @@
          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 "
+       d="M 25,15 L 25,16 L 19,16 L 19,15 L 25,15 z "
        id="path1964"
-       sodipodi:nodetypes="ccccccccc"
+       sodipodi:nodetypes="ccccc"
        inkscape:export-xdpi="90"
        inkscape:export-ydpi="90" />
     <path
Binary file Images/powerrail.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/powerrail.svg	Mon Jul 09 11:10:14 2007 +0200
@@ -0,0 +1,104 @@
+<?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.45.1"
+   version="1.0"
+   inkscape:export-filename="/taf/Pim/workspace_laurent/PLCOpenEditor/Images/powerrail.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:docbase="/taf/Pim/workspace_laurent/plcopeneditor/Images"
+   sodipodi:docname="powerrail.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="22.627418"
+     inkscape:cx="5.4294731"
+     inkscape:cy="13.670153"
+     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="937"
+     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:#000000;fill:#000000;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 5,1.8041124e-16 L 5,25 L 7,25 L 7,19 L 11,19 L 11,18 L 7,18 L 7,7 L 11,7 L 11,6 L 7,6 L 7,1.8041124e-16 L 5,1.8041124e-16 z "
+       id="rect4559"
+       sodipodi:nodetypes="ccccccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:#000000;fill:#999999;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,4 L 18,9 L 17,9 L 17,7 L 15,7 L 15,6 L 17,6 L 17,4 L 18,4 z "
+       id="path1964"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:#000000;fill:#999999;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,16 L 18,21 L 17,21 L 17,19 L 15,19 L 15,18 L 17,18 L 17,16 L 18,16 z "
+       id="path2391"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:#000000;fill:#999999;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 22,4 L 22,9 L 23,9 L 23,7 L 25,7 L 25,6 L 23,6 L 23,4 L 22,4 z "
+       id="path2397"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="opacity:1;color:#000000;fill:#999999;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 22,16 L 22,21 L 23,21 L 23,19 L 25,19 L 25,18 L 23,18 L 23,16 L 22,16 z "
+       id="path2403"
+       sodipodi:nodetypes="ccccccccc"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90" />
+    <path
+       style="color:#000000;fill:#999999;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 12,6 L 14,6 L 14,7 L 12,7 L 12,6 z "
+       id="path4252" />
+    <path
+       style="color:#000000;fill:#999999;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 12,18 L 14,18 L 14,19 L 12,19 L 12,18 z "
+       id="path2410" />
+  </g>
+</svg>
Binary file Images/rung.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Images/rung.svg	Mon Jul 09 11:10:14 2007 +0200
@@ -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>
--- a/LDViewer.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/LDViewer.py	Mon Jul 09 11:10:14 2007 +0200
@@ -30,6 +30,7 @@
 from graphics.GraphicCommons import *
 from graphics.FBD_Objects import *
 from Viewer import *
+from Dialogs import *
 
 def ExtractNextBlocks(block, block_list):
     current_list = [block]
@@ -53,10 +54,11 @@
                         next_list.append(next)
         current_list = next_list
     
-def CalcBranchSize(elements, stop):
+def CalcBranchSize(elements, stops):
     branch_size = 0
-    stop_list = [stop]
-    ExtractNextBlocks(stop, stop_list)
+    stop_list = stops
+    for stop in stops:
+        ExtractNextBlocks(stop, stop_list)
     element_tree = {}
     for element in elements:
         if element not in element_tree:
@@ -64,13 +66,34 @@
             GenerateTree(element, element_tree, stop_list)
         elif element_tree[element]:
             element_tree[element]["parents"].append("start")
+    remove_stops = {"start":[], "stop":[]}
     for element, values in element_tree.items():
-        if values and values["children"] == ["stop"]:
+        if "stop" in values["children"]:
+            removed = []
+            for child in values["children"]:
+                if child != "stop":
+##                    if child in elements:
+##                        RemoveElement(child, element_tree)
+##                        removed.append(child)
+                    if "start" in element_tree[child]["parents"]:
+                        if element not in remove_stops["stop"]:
+                            remove_stops["stop"].append(element)
+                        if child not in remove_stops["start"]:
+                            remove_stops["start"].append(child)
+            for child in removed:
+                values["children"].remove(child)
+    for element in remove_stops["start"]:
+        element_tree[element]["parents"].remove("start")
+    for element in remove_stops["stop"]:
+        element_tree[element]["children"].remove("stop")
+    for element, values in element_tree.items():
+        if values and "stop" in values["children"]:
             CalcWeight(element, element_tree)
             if values["weight"]:
                 branch_size += values["weight"]
             else:
                 return 1
+    #print branch_size
     return branch_size
 
 def RemoveElement(remove, element_tree):
@@ -78,7 +101,8 @@
         for child in element_tree[remove]["children"]:
             if child != "stop":
                 RemoveElement(child, element_tree)
-        element_tree[remove] = None
+        element_tree.pop(remove)
+##        element_tree[remove] = None
 
 def GenerateTree(element, element_tree, stop_list):
     if element in element_tree:
@@ -95,11 +119,12 @@
             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
+##                    for remove in element_tree[element]["children"]:
+##                        RemoveElement(remove, element_tree)
+##                    element_tree[element]["children"] = ["stop"]
+                    element_tree[element]["children"].append("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:
@@ -227,6 +252,9 @@
         return None
 
     def FindElement(self, pos):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            return Viewer.FindElement(self, pos)
+        
         elements = []
         for element in self.Elements:
             if element.HitTest(pos) or element.TestHandle(pos) != (0, 0):
@@ -243,6 +271,9 @@
         return None
 
     def SearchElements(self, bbox):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            return Viewer.SearchElements(self, bbox)
+        
         elements = []
         for element in self.Blocks:
             element_bbox = element.GetBoundingBox()
@@ -255,8 +286,11 @@
 #-------------------------------------------------------------------------------
 
     def OnViewerLeftDown(self, event):
-        if self.Mode == MODE_SELECTION:
-            pos = event.GetPosition()
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftDown(self, event)
+        elif self.Mode == MODE_SELECTION:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
             element = self.FindElement(pos)
             if self.SelectedElement:
                 if self.SelectedElement in self.Elements:
@@ -283,94 +317,106 @@
                 self.Refresh()
             if element:
                 self.SelectedElement = element
-                self.SelectedElement.OnLeftDown(event, self.Scaling)
+                self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
                 self.Refresh()
             else:
                 self.rubberBand.Reset()
-                self.rubberBand.OnLeftDown(event, self.Scaling)
+                self.rubberBand.OnLeftDown(event, dc, self.Scaling)
         event.Skip()
 
     def OnViewerLeftUp(self, event):
-        if self.rubberBand.IsShown():
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftUp(self, event)
+        elif self.rubberBand.IsShown():
             if self.Mode == MODE_SELECTION:
                 elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
-                self.rubberBand.OnLeftUp(event, self.Scaling)
+                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), 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:
+            dc = self.GetLogicalDC() 
             if self.SelectedElement in self.Elements:
                 if self.SelectedElement in self.Wires:
-                    result = self.SelectedElement.TestSegment(event.GetPosition(), True)
+                    result = self.SelectedElement.TestSegment(event.GetLogicalPosition(dc), True)
                     if result and result[1] in [EAST, WEST]:
                         self.SelectedElement.SetSelectedSegment(result[0])
                 else:
-                    self.SelectedElement.OnLeftUp(event, self.Scaling)
+                    self.SelectedElement.OnLeftUp(event, dc, self.Scaling)
             else:
                 for element in self.SelectedElement.GetElements():
                     if element in self.Wires:
-                        result = element.TestSegment(event.GetPosition(), True)
+                        result = element.TestSegment(event.GetLogicalPosition(dc), True)
                         if result and result[1] in [EAST, WEST]:
                             element.SetSelectedSegment(result[0])
                     else:
-                        element.OnLeftUp(event, self.Scaling)
+                        element.OnLeftUp(event, dc, 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()
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerRightUp(self, event)
+        else:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
+            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, dc, self.Scaling)
+                wxCallAfter(self.SetCursor, wxNullCursor)
+                self.ReleaseMouse()
+                self.Refresh()
+        event.Skip()
+
+    def OnViewerLeftDClick(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftDClick(self, event)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
             self.Refresh()
         event.Skip()
 
-    def OnViewerLeftDClick(self, event):
-        if self.Mode == MODE_SELECTION and self.SelectedElement:
-            self.SelectedElement.OnLeftDClick(event, self.Scaling)
+    def OnViewerMotion(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerMotion(self, event)
+        event.Skip()
+
+#-------------------------------------------------------------------------------
+#                          Keyboard event functions
+#-------------------------------------------------------------------------------
+
+    def OnChar(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnChar(self, event)
+        else:
+            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()
 
-    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
 #-------------------------------------------------------------------------------
@@ -669,6 +715,7 @@
                 for element in right_elements:
                     right_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail)
                 if not left_powerrail or not right_powerrail:
+                    wires = []
                     if left_powerrail:
                         powerrail = left_elements[0].GetParentBlock()
                         index = 0
@@ -679,15 +726,14 @@
                         powerrail.InsertConnector(index + 1)
                         powerrail.RefreshModel()
                         connectors = powerrail.GetConnectors()
+                        right_elements.reverse()
                         for i, right_element in enumerate(right_elements):
                             new_wire = Wire(self)
+                            wires.append(new_wire)
                             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:
                         dialog = LDElementDialog(self.Parent, "coil")
@@ -731,23 +777,20 @@
                             wire.ConnectEndPoint(None, coil_connectors["output"])
                             self.Wires.append(wire)
                             self.Elements.append(wire)
-                            rung.SelectElement(wire)                                
+                            rung.SelectElement(wire)
+                            left_elements.reverse()
                             for i, left_element in enumerate(left_elements):
                                 # Create Wire between LeftPowerRail and Coil
                                 new_wire = Wire(self)
+                                wires.append(new_wire)
                                 coil_connectors["input"].Connect((new_wire, 0), False)
                                 left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False)
                                 new_wire.ConnectStartPoint(None, coil_connectors["input"])
                                 new_wire.ConnectEndPoint(None, left_element)
-                                self.Wires.append(new_wire)
-                                self.Elements.append(new_wire)
-                                rung.SelectElement(new_wire)
-                            left_elements.reverse()
                             self.RefreshPosition(coil)
                     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
@@ -760,12 +803,12 @@
                                     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()
+                    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:
@@ -784,7 +827,6 @@
             message.ShowModal()
             message.Destroy()
 
-
     def AddBlock(self):
         message = wxMessageDialog(self, "This option isn't available yet!", "Warning", wxOK|wxICON_EXCLAMATION)
         message.ShowModal()
@@ -795,69 +837,72 @@
 #-------------------------------------------------------------------------------
 
     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:
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.DeleteContact(self, contact)
+        else:
+            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:
-                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
+                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 RecursiveDeletion(self, element, rung):
         connectors = element.GetConnectors()
@@ -881,109 +926,115 @@
                 self.RefreshPosition(block)
 
     def DeleteCoil(self, coil):
-        rungindex = self.FindRung(coil)
-        rung = self.Rungs[rungindex]
-        old_bbox = rung.GetBoundingBox()
-        nbcoils = 0
-        for element in rung.GetElements():
-            if isinstance(element, LD_Coil):
-                nbcoils += 1
-        if nbcoils > 1:
-            connectors = coil.GetConnectors()
-            output_wires = [wire for wire, handle in connectors["output"].GetWires()]
-            right_elements = [wire.StartConnected for wire in output_wires]
-            for wire in output_wires:
-                wire.Clean()
-                self.Wires.remove(wire)
-                self.Elements.remove(wire)
-                rung.SelectElement(wire)
-            for right_element in right_elements:
-                right_block = right_element.GetParentBlock()
-                if isinstance(right_block, LD_PowerRail):
-                    if len(right_element.GetWires()) == 0:
-                        index = right_block.GetConnectorIndex(right_element)
-                        right_block.DeleteConnector(index)
-                        powerrail_connectors = right_block.GetConnectors()
-                        for connector in powerrail_connectors:
-                            for wire, handle in connector.GetWires():
-                                block = wire.EndConnected.GetParentBlock()
-                                endpoint = wire.EndConnected.GetPosition(False)
-                                startpoint = connector.GetPosition(False)
-                                block.Move(0, startpoint.y - endpoint.y)
-                                self.RefreshPosition(block)
-            self.RecursiveDeletion(coil, rung)
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.DeleteContact(self, coil)
         else:
-            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(old_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])
+            rungindex = self.FindRung(coil)
             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):
+            nbcoils = 0
+            for element in rung.GetElements():
+                if isinstance(element, LD_Coil):
+                    nbcoils += 1
+            if nbcoils > 1:
+                connectors = coil.GetConnectors()
+                output_wires = [wire for wire, handle in connectors["output"].GetWires()]
+                right_elements = [wire.StartConnected for wire in output_wires]
+                for wire in output_wires:
                     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)
+                for right_element in right_elements:
+                    right_block = right_element.GetParentBlock()
+                    if isinstance(right_block, LD_PowerRail):
+                        if len(right_element.GetWires()) == 0:
+                            index = right_block.GetConnectorIndex(right_element)
+                            right_block.DeleteConnector(index)
+                            powerrail_connectors = right_block.GetConnectors()
+                            for connector in powerrail_connectors:
+                                for wire, handle in connector.GetWires():
+                                    block = wire.EndConnected.GetParentBlock()
+                                    endpoint = wire.EndConnected.GetPosition(False)
+                                    startpoint = connector.GetPosition(False)
+                                    block.Move(0, startpoint.y - endpoint.y)
+                                    self.RefreshPosition(block)
+                self.RecursiveDeletion(coil, rung)
+            else:
+                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(old_bbox.y - next_bbox.y, rungindex)
             self.SelectedElement = None
 
+    def DeleteWire(self, wire):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.DeleteWire(self, wire)
+        else:
+            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
 #-------------------------------------------------------------------------------
@@ -1030,6 +1081,10 @@
         movex = minx + interval - position[0]
         element.Move(movex, 0)
         position = element.GetPosition()
+        blocks = []
+        for i, connector in enumerate(input_connectors):
+            for j, (wire, handle) in enumerate(connector.GetWires()):
+                blocks.append(wire.EndConnected.GetParentBlock())
         for i, connector in enumerate(input_connectors):
             startpoint = connector.GetPosition(False)
             previous_blocks = []
@@ -1050,7 +1105,7 @@
                         start_offset = endpoint.y - startpoint.y
                     offset = start_offset
                 else:
-                    offset = start_offset + LD_LINE_SIZE * CalcBranchSize(previous_blocks, block)
+                    offset = start_offset + LD_LINE_SIZE * CalcBranchSize(previous_blocks, blocks)
                 if block in block_list:
                     wires = wire.EndConnected.GetWires()
                     endmiddlepoint = wires[0][0].StartConnected.GetPosition(False)[0] - LD_WIRE_SIZE
@@ -1087,6 +1142,7 @@
                         points = [startpoint, endpoint]
                 wire.SetPoints(points)
                 previous_blocks.append(block)
+                blocks.remove(block)
                 ExtractNextBlocks(block, block_list)
         element.RefreshModel(False)
         if recursive:
@@ -1147,175 +1203,3 @@
             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='Modifier:', 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','Negate','Rising Edge','Falling Edge'])
-            self.Element = LD_Contact(self.Preview, CONTACT_NORMAL, "")
-        elif type == "coil":
-            self._init_ctrls(parent, "Edit Coil Values", ['Normal','Negate','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|wxCENTRE)
-        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()
--- a/PLCControler.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/PLCControler.py	Mon Jul 09 11:10:14 2007 +0200
@@ -23,6 +23,7 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from minixsv import pyxsval
+from xml.dom import minidom
 import cPickle
 import os,sys,re
 from datetime import *
@@ -158,6 +159,7 @@
     
     # Reset PLCControler internal variables
     def Reset(self):
+        self.VerifyXML = False
         self.Project = None
         self.ProjectBuffer = None
         self.FilePath = ""
@@ -185,7 +187,7 @@
         self.Project = plcopen.project()
         self.Project.setName(name)
         # Initialize the project buffer
-        self.ProjectBuffer = UndoBuffer(self.Copy(self.Project))
+        #self.ProjectBuffer = UndoBuffer(self.Copy(self.Project))
     
     # Change project name
     def SetProjectName(self, name):
@@ -1054,7 +1056,7 @@
                     connections = variable.connectionPointIn.getConnections()
                     if connections:
                         for link in connections:
-                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                             connector["links"].append(dic)
                     infos["connectors"]["inputs"].append(connector)
                 for variable in instance.outputVariables.getVariable():
@@ -1083,7 +1085,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connector"]["links"].append(dic)
             elif isinstance(instance, plcopen.inOutVariable):
                 infos["name"] = instance.getExpression()
@@ -1100,7 +1102,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connectors"]["input"]["links"].append(dic)
             elif isinstance(instance, plcopen.continuation):
                 infos["name"] = instance.getName()
@@ -1118,7 +1120,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connector"]["links"].append(dic)
             elif isinstance(instance, plcopen.comment):
                 infos["type"] = "comment"
@@ -1138,7 +1140,7 @@
                     connector["position"] = connection.getRelPosition()
                     connector["links"] = []
                     for link in connection.getConnections():
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         connector["links"].append(dic)
                     infos["connectors"].append(connector)
             elif isinstance(instance, plcopen.contact):
@@ -1152,7 +1154,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connectors"]["input"]["links"].append(dic)
                 infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
             elif isinstance(instance, plcopen.coil):
@@ -1166,7 +1168,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connectors"]["input"]["links"].append(dic)
                 infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
             elif isinstance(instance, plcopen.step):
@@ -1181,7 +1183,7 @@
                     connections = instance.connectionPointIn.getConnections()
                     if connections:
                         for link in connections:
-                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                             infos["connectors"]["input"]["links"].append(dic)
                 if instance.connectionPointOut:
                     infos["connectors"]["output"] = {"position" : instance.connectionPointOut.getRelPosition()}
@@ -1198,7 +1200,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connectors"]["input"]["links"].append(dic)
                 infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
             elif isinstance(instance, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)):
@@ -1213,7 +1215,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         connector["links"].append(dic)
                 infos["connectors"]["inputs"].append(connector)
                 for sequence in instance.getConnectionPointOut():
@@ -1233,7 +1235,7 @@
                     connections = sequence.getConnections()
                     if connections:
                         for link in connections:
-                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                             connector["links"].append(dic)
                     infos["connectors"]["inputs"].append(connector)
                 connector = {}
@@ -1248,7 +1250,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connector"]["links"].append(dic)
             elif isinstance(instance, plcopen.actionBlock):
                 infos["type"] = "actionBlock"
@@ -1259,7 +1261,7 @@
                 connections = instance.connectionPointIn.getConnections()
                 if connections:
                     for link in connections:
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
+                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
                         infos["connector"]["links"].append(dic)
             return infos
         return False
@@ -1278,13 +1280,18 @@
         for wire, handle in wires:
             points = wire.GetPoints(handle != 0)
             if handle == 0:
-                refLocalId = wire.GetConnectedId(-1)
+                result = wire.GetConnectedInfos(-1)
             else:
-                refLocalId = wire.GetConnectedId(0)
-            if refLocalId != None:
+                result = wire.GetConnectedInfos(0)
+            if result != None:
+                refLocalId, formalParameter = result
                 connection.addConnection()
                 connection.setConnectionId(idx, refLocalId)
                 connection.setConnectionPoints(idx, points)
+                if formalParameter != "":
+                    connection.setConnectionParameter(idx, formalParameter)
+                else:
+                    connection.setConnectionParameter(idx, None)
                 idx += 1
     
     def AddCurrentElementEditingBlock(self, id):
@@ -1847,14 +1854,20 @@
         return tasks_data, instances_data
 
     def OpenXMLFile(self, filepath):
-        if sys:
-            sys.stdout = HolePseudoFile()
-        tree = pyxsval.parseAndValidate(filepath, os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"))
-        if sys:
-            sys.stdout = sys.__stdout__
+        if self.VerifyXML:
+            if sys:
+                sys.stdout = HolePseudoFile()
+            result = pyxsval.parseAndValidate(filepath, os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"))
+            if sys:
+                sys.stdout = sys.__stdout__
+            tree = result.getTree()
+        else:
+            xmlfile = open(filepath, 'r')
+            tree = minidom.parse(xmlfile)
+            xmlfile.close()
         
         self.Project = plcopen.project()
-        self.Project.loadXMLTree(tree.getTree().childNodes[0])
+        self.Project.loadXMLTree(tree.childNodes[0])
         self.UndoBuffer = UndoBuffer(self.Copy(self.Project), True)
         self.SetFilePath(filepath)
         self.ElementsOpened = []
@@ -1873,11 +1886,12 @@
                       "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 = HolePseudoFile()
-            pyxsval.parseAndValidateString(text, open(os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"),"r").read())
-            if sys:
-                sys.stdout = sys.__stdout__
+            if self.VerifyXML:
+                if sys:
+                    sys.stdout = HolePseudoFile()
+                pyxsval.parseAndValidateString(text, open(os.path.join(sys.path[0], "plcopen/TC6_XML_V10_B.xsd"),"r").read())
+                if sys:
+                    sys.stdout = sys.__stdout__
             
             if filepath:
                 xmlfile = open(filepath,"w")
@@ -1885,7 +1899,7 @@
                 xmlfile = open(self.FilePath,"w")
             xmlfile.write(text)
             xmlfile.close()
-            self.UndoBuffer.CurrentSaved()
+            #self.ProjectBuffer.CurrentSaved()
             if filepath:
                 self.SetFilePath(filepath)
             return True
@@ -1901,20 +1915,20 @@
         return cPickle.loads(cPickle.dumps(model))
 
     def BufferProject(self):
-        self.UndoBuffer.Buffering(self.Copy(self))
+        self.ProjectBuffer.Buffering(self.Copy(self))
 
     def ProjectIsSaved(self):
-        return self.UndoBuffer.IsCurrentSaved()
+        return self.ProjectBuffer.IsCurrentSaved()
 
     def LoadPrevious(self):
-        self.Project = self.Copy(self.UndoBuffer.Previous())
+        self.Project = self.Copy(self.ProjectBuffer.Previous())
         self.RefreshElementsOpened()
     
     def LoadNext(self):
-        self.Project = self.Copy(self.UndoBuffer.Next())
+        self.Project = self.Copy(self.ProjectBuffer.Next())
         self.RefreshElementsOpened()
     
     def GetBufferState(self):
-        first = self.UndoBuffer.IsFirst()
-        last = self.UndoBuffer.IsLast()
+        first = self.ProjectBuffer.IsFirst()
+        last = self.ProjectBuffer.IsLast()
         return not first, not last
--- a/PLCOpenEditor.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/PLCOpenEditor.py	Mon Jul 09 11:10:14 2007 +0200
@@ -29,9 +29,10 @@
 import wx
 
 from SFCViewer import *
-from FBDViewer import *
 from LDViewer import *
 from Viewer import *
+from TextViewer import *
+from RessourceEditor import *
 from PLCControler import *
 from plcopen import OpenPDFDoc
 from plcopen.structures import *
@@ -74,25 +75,6 @@
  wxID_PLCOPENEDITORFBDTOOLBAR, wxID_PLCOPENEDITORLDTOOLBAR,
 ] = [wx.NewId() for _init_ctrls in range(10)]
 
-[wxID_PLCOPENEDITORTOOLBARITEMS0, 
-] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(1)]
-
-SFC_ITEMS = [wxID_PLCOPENEDITORSFCTOOLBARITEMS1, 
- wxID_PLCOPENEDITORSFCTOOLBARITEMS2, wxID_PLCOPENEDITORSFCTOOLBARITEMS3, 
- wxID_PLCOPENEDITORSFCTOOLBARITEMS4, wxID_PLCOPENEDITORSFCTOOLBARITEMS5,
- wxID_PLCOPENEDITORSFCTOOLBARITEMS6,
-] = [wx.NewId() for _init_coll_SFCToolBar_Items in range(6)]
-
-FBD_ITEMS = [wxID_PLCOPENEDITORFBDTOOLBARITEMS1, 
- wxID_PLCOPENEDITORFBDTOOLBARITEMS2, wxID_PLCOPENEDITORFBDTOOLBARITEMS3, 
- wxID_PLCOPENEDITORFBDTOOLBARITEMS4, wxID_PLCOPENEDITORFBDTOOLBARITEMS5,
-] = [wx.NewId() for _init_coll_FBDToolBar_Items in range(5)]
-
-LD_ITEMS = [wxID_PLCOPENEDITORLDTOOLBARITEMS1, 
- wxID_PLCOPENEDITORLDTOOLBARITEMS2, wxID_PLCOPENEDITORLDTOOLBARITEMS3, 
- wxID_PLCOPENEDITORLDTOOLBARITEMS4,
-] = [wx.NewId() for _init_coll_LDToolBar_Items in range(4)]
-
 [wxID_PLCOPENEDITORFILEMENUITEMS0, wxID_PLCOPENEDITORFILEMENUITEMS1, 
  wxID_PLCOPENEDITORFILEMENUITEMS2, wxID_PLCOPENEDITORFILEMENUITEMS3, 
  wxID_PLCOPENEDITORFILEMENUITEMS5, wxID_PLCOPENEDITORFILEMENUITEMS6, 
@@ -125,6 +107,56 @@
 [wxID_PLCOPENEDITORCONFIGMENUITEMS0, wxID_PLCOPENEDITORCONFIGMENUITEMS1, 
 ] = [wx.NewId() for _init_coll_ConfigMenu_Items in range(2)]
 
+
+#-------------------------------------------------------------------------------
+#                            ToolBars definitions
+#-------------------------------------------------------------------------------
+
+
+[wxID_PLCOPENEDITORTOOLBARSELECTION, wxID_PLCOPENEDITORTOOLBARCOMMENT,
+ wxID_PLCOPENEDITORTOOLBARVARIABLE, wxID_PLCOPENEDITORTOOLBARBLOCK,
+ wxID_PLCOPENEDITORTOOLBARCONNECTION, wxID_PLCOPENEDITORTOOLBARWIRE,
+ wxID_PLCOPENEDITORTOOLBARPOWERRAIL, wxID_PLCOPENEDITORTOOLBARRUNG,
+ wxID_PLCOPENEDITORTOOLBARCOIL, wxID_PLCOPENEDITORTOOLBARCONTACT,
+ wxID_PLCOPENEDITORTOOLBARBRANCH, wxID_PLCOPENEDITORTOOLBARINITIALSTEP,
+ wxID_PLCOPENEDITORTOOLBARSTEP, wxID_PLCOPENEDITORTOOLBARTRANSITION,
+ wxID_PLCOPENEDITORTOOLBARACTIONBLOCK, wxID_PLCOPENEDITORTOOLBARDIVERGENCE,
+ wxID_PLCOPENEDITORTOOLBARJUMP,
+] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(17)]
+
+ToolBarItems = {
+    "FBD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", "Images/comment.png", "Create a new comment"),
+             (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", "Images/variable.png", "Create a new variable"),
+             (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", "Images/block.png", "Create a new block"),
+             (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", "Images/connection.png", "Create a new connection"),
+             (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARWIRE, "OnWireTool", "Images/wire.png", "Create a new wire")],
+    "LD" :  [(True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", "Images/comment.png", "Create a new comment"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool", "Images/powerrail.png", "Create a new power rail"),
+             (False, DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARRUNG, "OnRungTool", "Images/rung.png", "Create a new rung"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCOIL, "OnCoilTool", "Images/coil.png", "Create a new coil"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool", "Images/contact.png", "Create a new contact"),
+             (False, DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARBRANCH, "OnBranchTool", "Images/branch.png", "Create a new branch"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", "Images/variable.png", "Create a new variable"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", "Images/block.png", "Create a new block"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", "Images/connection.png", "Create a new connection"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARWIRE, "OnWireTool", "Images/wire.png", "Create a new wire")],
+    "SFC" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool", "Images/comment.png", "Create a new comment"),
+             (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARINITIALSTEP, "OnInitialStepTool", "Images/initial_step.png", "Create a new initial step"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARSTEP, "OnStepTool", "Images/step.png", "Create a new step"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARTRANSITION, "OnTransitionTool", "Images/transition.png", "Create a new transition"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARACTIONBLOCK, "OnActionBlockTool", "Images/action.png", "Create a new action block"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARDIVERGENCE, "OnDivergenceTool", "Images/divergence.png", "Create a new divergence"),
+             (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARJUMP, "OnJumpTool", "Images/jump.png", "Create a new jump"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool", "Images/variable.png", "Create a new variable"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool", "Images/block.png", "Create a new block"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool", "Images/connection.png", "Create a new connection"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool", "Images/powerrail.png", "Create a new power rail"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool", "Images/contact.png", "Create a new contact"),
+             (True, FREEDRAWING_MODE, wxID_PLCOPENEDITORTOOLBARWIRE, "OnWireTool", "Images/wire.png", "Create a new wire")],
+    "ST" : [],
+    "IL" : []
+}
+
 class PLCOpenEditor(wx.Frame):
     _custom_classes = {'wx.SashWindow' : ['Viewer']}
     
@@ -242,6 +274,8 @@
               id=wxID_PLCOPENEDITORFILEMENUITEMS6)
         self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu,
               id=wxID_PLCOPENEDITORFILEMENUITEMS7)
+        self.Bind(wx.EVT_MENU, self.OnPropertiesMenu,
+              id=wxID_PLCOPENEDITORFILEMENUITEMS9)
         self.Bind(wx.EVT_MENU, self.OnQuitMenu,
               id=wxID_PLCOPENEDITORFILEMENUITEMS11)
 
@@ -351,16 +385,16 @@
         self.ToolBar = wxToolBar(id=wxID_PLCOPENEDITORTOOLBAR, name='ToolBar',
               parent=self.EditorPanel, pos=wx.Point(0, 0), size=wx.Size(0, 40),
               style=wxTB_HORIZONTAL | wxNO_BORDER)
-        self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORTOOLBARITEMS0, 
+        self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORTOOLBARSELECTION, 
               wxBitmap(os.path.join(CWD, 'Images/select.png')), wxNullBitmap, "Select an object")
         self.Bind(wx.EVT_TOOL, self.OnSelectionTool, 
-              id=wxID_PLCOPENEDITORTOOLBARITEMS0)
+              id=wxID_PLCOPENEDITORTOOLBARSELECTION)
         
         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.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
+        self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
         self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag,
               id=wxID_PLCOPENEDITORPROJECTTREE)
         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
@@ -391,11 +425,16 @@
             self.RefreshProjectTree()
         
         self.CurrentToolBar = []
+        self.CurrentLanguage = ""
+        self.DrawingMode = DRIVENDRAWING_MODE
         
         self.RefreshFileMenu()
         self.RefreshEditMenu()
         self.RefreshToolBar()
 
+    def GetDrawingMode(self):
+        return self.DrawingMode
+
     def RefreshFileMenu(self):
         if self.FileMenu:
             if self.Controler.HasOpenedProject():
@@ -441,6 +480,20 @@
                 self.EditMenu.FindItemByPosition(5).Enable(False)
             self.EditMenu.FindItemByPosition(6).Enable(False)
 
+    def ShowProperties(self):
+        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()
+
     def OnNewProjectMenu(self, event):
         dialog = ProjectDialog(self)
         if dialog.ShowModal() == wxID_OK:
@@ -529,7 +582,7 @@
         if filepath != "":
             directory, filename = os.path.split(filepath)
         else:
-            directory, filename = os.getcwd(), "%s.od"%self.Controler.GetProjectName()
+            directory, filename = os.getcwd(), "%s.xml"%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()
@@ -545,6 +598,10 @@
                 message.Destroy()
         dialog.Destroy()
 
+    def OnPropertiesMenu(self, event):
+        self.ShowProperties()
+        event.Skip()
+
     def OnQuitMenu(self, event):
         self.ToolBar.Reparent(self)
         self.Controler.Reset()
@@ -557,7 +614,7 @@
             window = self.TabsOpened.GetPage(selected)
             if not isinstance(window, TextViewer):
                 window.SetMode(MODE_SELECTION)
-        self.ToolBar.ToggleTool(wxID_PLCOPENEDITORTOOLBARITEMS0, True)
+        self.ToolBar.ToggleTool(wxID_PLCOPENEDITORTOOLBARSELECTION, True)
 
     def ResetToolToggle(self, id):
         tool = self.ToolBar.FindById(id)
@@ -569,101 +626,134 @@
             self.TabsOpened.GetPage(selected).SetMode(MODE_SELECTION)
         event.Skip()
     
-    def OnSFCCommentTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORSFCTOOLBARITEMS1)
+    def OnCommentTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARCOMMENT)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT)
         event.Skip()
     
-    def OnSFCInitialStepTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORSFCTOOLBARITEMS2)
-        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 OnFBDCommentTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORFBDTOOLBARITEMS1)
-        selected = self.TabsOpened.GetSelection()
-        if selected != -1:
-            self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT)
-        event.Skip()
-    
-    def OnFBDVariableTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORFBDTOOLBARITEMS2)
+    def OnVariableTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARVARIABLE)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).SetMode(MODE_VARIABLE)
         event.Skip()
     
-    def OnFBDBlockTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORFBDTOOLBARITEMS3)
+    def OnBlockTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARBLOCK)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).SetMode(MODE_BLOCK)
         event.Skip()
         
-    def OnFBDConnectionTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORFBDTOOLBARITEMS4)
+    def OnConnectionTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARCONNECTION)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).SetMode(MODE_CONNECTION)
         event.Skip()
 
-    def OnFBDWireTool(self, event):
-        self.ResetToolToggle(wxID_PLCOPENEDITORFBDTOOLBARITEMS5)
+    def OnWireTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARWIRE)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).SetMode(MODE_WIRE)
         event.Skip()
 
-    def OnLDCoilTool(self, event):
+    def OnPowerRailTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARPOWERRAIL)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_POWERRAIL)
+        event.Skip()
+
+    def OnRungTool(self, event):
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).AddRung()
         event.Skip()
     
-    def OnLDContactTool(self, event):
+    def OnCoilTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARCOIL)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
-            self.TabsOpened.GetPage(selected).AddContact()
-        event.Skip()
-    
-    def OnLDBlockTool(self, event):
+            self.TabsOpened.GetPage(selected).SetMode(MODE_COIL)
+        event.Skip()
+    
+    def OnContactTool(self, event):
+        if self.DrawingMode == FREEDRAWING_MODE:
+            self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARCONTACT)
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
-            self.TabsOpened.GetPage(selected).AddBlock()
-        event.Skip()
-    
-    def OnLDBranchTool(self, event): 
+            if self.DrawingMode == FREEDRAWING_MODE:
+                self.TabsOpened.GetPage(selected).SetMode(MODE_CONTACT)
+            else:
+                self.TabsOpened.GetPage(selected).AddContact()
+        event.Skip()
+    
+    def OnBranchTool(self, event): 
         selected = self.TabsOpened.GetSelection()
         if selected != -1:
             self.TabsOpened.GetPage(selected).AddBranch()
+        event.Skip()    
+    
+    def OnInitialStepTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARINITIALSTEP)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_INITIALSTEP)
+        event.Skip()
+    
+    def OnStepTool(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARSTEP)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            if self.GetDrawingMode() == FREEDRAWING_MODE:
+                self.TabsOpened.GetPage(selected).SetMode(MODE_STEP)
+            else:
+                self.TabsOpened.GetPage(selected).AddStep()
+        event.Skip()
+
+    def OnActionBlockTool(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARACTIONBLOCK)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            if self.GetDrawingMode() == FREEDRAWING_MODE:
+                self.TabsOpened.GetPage(selected).SetMode(MODE_ACTION)
+            else:
+                self.TabsOpened.GetPage(selected).AddStepAction()
+        event.Skip()
+
+    def OnTransitionTool(self, event):
+        self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARTRANSITION)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            self.TabsOpened.GetPage(selected).SetMode(MODE_TRANSITION)
+        event.Skip()
+
+    def OnDivergenceTool(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARDIVERGENCE)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            if self.GetDrawingMode() == FREEDRAWING_MODE:
+                self.TabsOpened.GetPage(selected).SetMode(MODE_DIVERGENCE)
+            else:
+                self.TabsOpened.GetPage(selected).AddDivergence()
+        event.Skip()
+    
+    def OnJumpTool(self, event):
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            self.ResetToolToggle(wxID_PLCOPENEDITORTOOLBARJUMP)
+        selected = self.TabsOpened.GetSelection()
+        if selected != -1:
+            if self.GetDrawingMode() == FREEDRAWING_MODE:
+                self.TabsOpened.GetPage(selected).SetMode(MODE_JUMP)
+            else:
+                self.TabsOpened.GetPage(selected).AddJump()
         event.Skip()
         
     def OnPouSelectedChanged(self, event):
@@ -785,18 +875,7 @@
         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()
+            self.ShowProperties()
         elif data == ITEM_CLASS:
             item = self.ProjectTree.GetItemParent(selected)
             item_type = self.ProjectTree.GetPyData(item)
@@ -889,7 +968,7 @@
                         varlist.append(var["Name"])
             if idx != None:
                 if language == "FBD":
-                    new_window = FBD_Viewer(self.TabsOpened, self, self.Controler)
+                    new_window = Viewer(self.TabsOpened, self, self.Controler)
                 elif language == "LD":
                     new_window = LD_Viewer(self.TabsOpened, self, self.Controler)
                 elif language == "SFC":
@@ -1017,92 +1096,29 @@
                 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)
+            item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
         for item in to_delete:
             self.ProjectTree.Delete(item)
-
+    
     def ResetToolBar(self):
         for item in self.CurrentToolBar:
+            self.Unbind(wx.EVT_MENU, id=item)
             self.ToolBar.DeleteTool(item)
 
     def RefreshToolBar(self):
         language = self.Controler.GetCurrentElementEditingBodyType()
-        if language == "SFC":
-            if self.CurrentToolBar != SFC_ITEMS:
-                self.ResetToolBar()
-                self.CurrentToolBar = SFC_ITEMS
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS1, 
-                      wxBitmap(os.path.join(CWD, 'Images/comment.png')), wxNullBitmap, "Create a new comment")
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS2, 
-                      wxBitmap(os.path.join(CWD, 'Images/initial_step.png')), wxNullBitmap, "Create a new initial step")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS3, 
-                      wxBitmap(os.path.join(CWD, 'Images/step.png')), "Create a new step")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS4, 
-                      wxBitmap(os.path.join(CWD, 'Images/action.png')), "Add action block to step")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS5, 
-                      wxBitmap(os.path.join(CWD, 'Images/divergence.png')), "Create a new divergence")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS6, 
-                      wxBitmap(os.path.join(CWD, 'Images/jump.png')), "Create a new jump")
-                self.Bind(wx.EVT_TOOL, self.OnSFCCommentTool, 
-                      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)
-        elif language == "FBD":
-            if self.CurrentToolBar != FBD_ITEMS:
-                self.ResetToolBar()
-                self.CurrentToolBar = FBD_ITEMS
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS1, 
-                      wxBitmap(os.path.join(CWD, 'Images/comment.png')), wxNullBitmap, "Create a new comment")
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS2, 
-                      wxBitmap(os.path.join(CWD, 'Images/variable.png')), wxNullBitmap, "Create a new variable")
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS3, 
-                      wxBitmap(os.path.join(CWD, 'Images/block.png')), wxNullBitmap, "Create a new block")
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS4, 
-                      wxBitmap(os.path.join(CWD, 'Images/connection.png')), wxNullBitmap, "Create a new connection")
-                self.ToolBar.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS5, 
-                      wxBitmap(os.path.join(CWD, 'Images/wire.png')), wxNullBitmap, "Create a new wire")
-                self.Bind(wx.EVT_TOOL, self.OnFBDCommentTool, 
-                      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.OnFBDWireTool, 
-                      id=wxID_PLCOPENEDITORFBDTOOLBARITEMS5)
-        elif language == "LD":
-            if self.CurrentToolBar != LD_ITEMS:
-                self.ResetToolBar()
-                self.CurrentToolBar = LD_ITEMS
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS1, 
-                      wxBitmap(os.path.join(CWD, 'Images/coil.png')), "Create a new rung")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS2, 
-                      wxBitmap(os.path.join(CWD, 'Images/contact.png')), "Create a new contact")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS3, 
-                      wxBitmap(os.path.join(CWD, 'Images/block.png')), "Create a new block")
-                self.ToolBar.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS4, 
-                      wxBitmap(os.path.join(CWD, 'Images/branch.png')), "Create a new branch")
-                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)
-        else:
-            if len(self.CurrentToolBar) > 0:
-                self.ResetToolBar()
-                self.CurrentToolBar = []
+        if language and language != self.CurrentLanguage:
+            self.ResetToolBar()
+            self.CurrentLanguage = language
+            self.CurrentToolBar = []
+            for radio, modes, id, method, picture, help in ToolBarItems[language]:
+                if modes & self.DrawingMode:
+                    if radio or self.DrawingMode == FREEDRAWING_MODE:
+                        self.ToolBar.AddRadioTool(id, wxBitmap(os.path.join(CWD, picture)), wxNullBitmap, help)
+                    else:
+                        self.ToolBar.AddSimpleTool(id, wxBitmap(os.path.join(CWD, picture)), help)
+                    self.Bind(wx.EVT_TOOL, getattr(self, method), id=id)
+                    self.CurrentToolBar.append(id)
         self.ResetCurrentMode()
 
     def RefreshTabsOpenedTitles(self):
@@ -2063,7 +2079,7 @@
 
         self.OptionList = "Yes,No"
         self.TypeList = ""
-        for value in TypeHierarchy.keys():
+        for value, parent in TypeHierarchy_list:
             if not value.startswith("ANY"):
                 self.TypeList += "%s,"%value
         self.TypeList = self.TypeList[:-1]
@@ -2208,6 +2224,7 @@
         self.RefreshValues()
     
     def RefreshValues(self):
+        self.VariablesGrid.SetGridCursor(0, 0)
         data = []
         for variable in self.Values:
             if variable["Class"] in self.ClassList:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RessourceEditor.py	Mon Jul 09 11:10:14 2007 +0200
@@ -0,0 +1,509 @@
+#!/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 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 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
+
+#-------------------------------------------------------------------------------
+#                            Resource Editor class
+#-------------------------------------------------------------------------------
+
+class ResourceTable(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
+        
+        self.ColAlignements = []
+        self.ColSizes = []
+        # 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 GetColAlignements(self):
+        return self.ColAlignements
+    
+    def SetColAlignements(self, list):
+        self.ColAlignements = list
+
+    def GetColSizes(self):
+        return self.ColSizes
+    
+    def SetColSizes(self, list):
+        self.ColSizes = list
+
+    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 SetValueByName(self, row, colname, value):
+        if colname in self.colnames:
+            self.data[row][colname] = 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.ColAlignements[col], wxALIGN_CENTRE)
+            grid.SetColAttr(col, attr)
+            grid.SetColSize(col, self.ColSizes[col])
+        
+        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","Interval"]:
+                    editor = wxGridCellTextEditor()
+                    renderer = wxGridCellStringRenderer()
+                    if colname == "Interval" and self.GetValueByName(row, "Single") != "":
+                        grid.SetReadOnly(row, col, True)
+                elif colname == "Single":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.VariableList)
+                    if self.GetValueByName(row, "Interval") != "":
+                        grid.SetReadOnly(row, col, True)
+                elif colname == "Type":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.TypeList)
+                elif colname == "Priority":
+                    editor = wxGridCellNumberEditor()
+                    editor.SetParameters("0,65535")
+                elif colname == "Task":
+                    editor = wxGridCellChoiceEditor()
+                    editor.SetParameters(self.Parent.TaskList)
+                    
+                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_RESOURCEEDITOR, wxID_RESOURCEEDITORSTATICTEXT1,
+ wxID_RESOURCEEDITORSTATICTEXT2, wxID_RESOURCEEDITORINSTANCESGRID,
+ wxID_RESOURCEEDITORTASKSGRID, wxID_RESOURCEEDITORADDINSTANCEBUTTON,
+ wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, wxID_RESOURCEEDITORUPINSTANCEBUTTON,
+ wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, wxID_RESOURCEEDITORADDTASKBUTTON,
+ wxID_RESOURCEEDITORDELETETASKBUTTON, wxID_RESOURCEEDITORUPTASKBUTTON,
+ wxID_RESOURCEEDITORDOWNTASKBUTTON,
+] = [wx.NewId() for _init_ctrls in range(13)]
+
+class ResourceEditor(wx.Panel):
+    
+    def _init_coll_InstancesSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(1)
+
+    def _init_coll_InstancesSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddSizer(self.InstancesButtonsSizer, 0, border=0, flag=wxGROW)
+        parent.AddWindow(self.InstancesGrid, 0, border=0, flag=wxGROW)
+
+    def _init_coll_InstancesButtonsSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(0)
+
+    def _init_coll_InstancesButtonsSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.staticText2, 0, border=0, flag=wxALIGN_BOTTOM)
+        parent.AddWindow(self.AddInstanceButton, 0, border=0, flag=0)
+        parent.AddWindow(self.DeleteInstanceButton, 0, border=0, flag=0)
+        parent.AddWindow(self.UpInstanceButton, 0, border=0, flag=0)
+        parent.AddWindow(self.DownInstanceButton, 0, border=0, flag=0)
+
+    def _init_coll_TasksSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(1)
+
+    def _init_coll_TasksSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddSizer(self.TasksButtonsSizer, 0, border=0, flag=wxGROW)
+        parent.AddWindow(self.TasksGrid, 0, border=0, flag=wxGROW)
+
+    def _init_coll_TasksButtonsSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(0)
+
+    def _init_coll_TasksButtonsSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddWindow(self.staticText1, 0, border=0, flag=wxALIGN_BOTTOM)
+        parent.AddWindow(self.AddTaskButton, 0, border=0, flag=0)
+        parent.AddWindow(self.DeleteTaskButton, 0, border=0, flag=0)
+        parent.AddWindow(self.UpTaskButton, 0, border=0, flag=0)
+        parent.AddWindow(self.DownTaskButton, 0, border=0, flag=0)
+
+    def _init_coll_MainGridSizer_Items(self, parent):
+        # generated method, don't edit
+
+        parent.AddSizer(self.TasksSizer, 0, border=0, flag=wxGROW)
+        parent.AddSizer(self.InstancesSizer, 0, border=0, flag=wxGROW)
+
+    def _init_coll_MainGridSizer_Growables(self, parent):
+        # generated method, don't edit
+
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(0)
+        parent.AddGrowableRow(1)
+
+    def _init_sizers(self):
+        # generated method, don't edit
+        self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+
+        self.InstancesSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+
+        self.InstancesButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
+
+        self.TasksSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+
+        self.TasksButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
+
+        self._init_coll_MainGridSizer_Growables(self.MainGridSizer)
+        self._init_coll_MainGridSizer_Items(self.MainGridSizer)
+        self._init_coll_InstancesSizer_Growables(self.InstancesSizer)
+        self._init_coll_InstancesSizer_Items(self.InstancesSizer)
+        self._init_coll_InstancesButtonsSizer_Growables(self.InstancesButtonsSizer)
+        self._init_coll_InstancesButtonsSizer_Items(self.InstancesButtonsSizer)
+        self._init_coll_TasksSizer_Growables(self.TasksSizer)
+        self._init_coll_TasksSizer_Items(self.TasksSizer)
+        self._init_coll_TasksButtonsSizer_Growables(self.TasksButtonsSizer)
+        self._init_coll_TasksButtonsSizer_Items(self.TasksButtonsSizer)
+
+        self.SetSizer(self.MainGridSizer)
+
+    def _init_ctrls(self, prnt):
+        # generated method, don't edit
+        wx.Panel.__init__(self, id=wxID_RESOURCEEDITOR, name='', parent=prnt,
+              pos=wx.Point(0, 0), size=wx.Size(-1, -1),
+              style=wx.SUNKEN_BORDER)
+        
+        self.staticText1 = wx.StaticText(id=wxID_RESOURCEEDITORSTATICTEXT1,
+              label=u'Tasks:', name='staticText2', parent=self, pos=wx.Point(0,
+              0), size=wx.Size(60, 17), style=wxALIGN_CENTER)
+
+        self.TasksGrid = wx.grid.Grid(id=wxID_RESOURCEEDITORTASKSGRID,
+              name='TasksGrid', parent=self, pos=wx.Point(0, 0), 
+              size=wx.Size(-1, -1), style=wxVSCROLL)
+        self.TasksGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+              'Sans'))
+        self.TasksGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+              False, 'Sans'))
+        EVT_GRID_CELL_CHANGE(self.TasksGrid, self.OnTasksGridCellChange)
+
+        self.AddTaskButton = wx.Button(id=wxID_RESOURCEEDITORADDTASKBUTTON, label='Add Task',
+              name='AddTaskButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(102, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORADDTASKBUTTON, self.OnAddTaskButton)
+
+        self.DeleteTaskButton = wx.Button(id=wxID_RESOURCEEDITORDELETETASKBUTTON, label='Delete Task',
+              name='DeleteTaskButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(102, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORDELETETASKBUTTON, self.OnDeleteTaskButton)
+
+        self.UpTaskButton = wx.Button(id=wxID_RESOURCEEDITORUPTASKBUTTON, label='^',
+              name='UpTaskButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORUPTASKBUTTON, self.OnUpTaskButton)
+
+        self.DownTaskButton = wx.Button(id=wxID_RESOURCEEDITORDOWNTASKBUTTON, label='v',
+              name='DownTaskButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORDOWNTASKBUTTON, self.OnDownTaskButton)
+
+        self.staticText2 = wx.StaticText(id=wxID_RESOURCEEDITORSTATICTEXT2,
+              label=u'Instances:', name='staticText1', parent=self,
+              pos=wx.Point(0, 0), size=wx.Size(85, 17), style=wxALIGN_CENTER)
+
+        self.InstancesGrid = wx.grid.Grid(id=wxID_RESOURCEEDITORINSTANCESGRID,
+              name='InstancesGrid', parent=self, pos=wx.Point(0, 0), 
+              size=wx.Size(-1, -1), style=wxVSCROLL)
+        self.InstancesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+              'Sans'))
+        self.InstancesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+              False, 'Sans'))
+        EVT_GRID_CELL_CHANGE(self.InstancesGrid, self.OnInstancesGridCellChange)
+
+        self.AddInstanceButton = wx.Button(id=wxID_RESOURCEEDITORADDINSTANCEBUTTON, label='Add Instance',
+              name='AddInstanceButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(122, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORADDINSTANCEBUTTON, self.OnAddInstanceButton)
+
+        self.DeleteInstanceButton = wx.Button(id=wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, label='Delete Instance',
+              name='DeleteInstanceButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(122, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, self.OnDeleteInstanceButton)
+
+        self.UpInstanceButton = wx.Button(id=wxID_RESOURCEEDITORUPINSTANCEBUTTON, label='^',
+              name='UpInstanceButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORUPINSTANCEBUTTON, self.OnUpInstanceButton)
+
+        self.DownInstanceButton = wx.Button(id=wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, label='v',
+              name='DownInstanceButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        EVT_BUTTON(self, wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, self.OnDownInstanceButton)
+
+        self._init_sizers()
+
+    def __init__(self, parent, window, controler):
+        self._init_ctrls(parent)
+        
+        self.Parent = window
+        self.Controler = controler
+        
+        self.TasksDefaultValue = {"Name" : "", "Single" : "", "Interval" : "", "Priority" : 0}
+        self.TasksTable = ResourceTable(self, [], ["Name", "Single", "Interval", "Priority"])
+        self.TasksTable.SetColAlignements([wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_RIGHT, wxALIGN_RIGHT])
+        self.TasksTable.SetColSizes([200, 100, 100, 100])
+        self.TasksGrid.SetTable(self.TasksTable)
+        self.TasksGrid.SetRowLabelSize(0)
+        self.TasksTable.ResetView(self.TasksGrid)
+
+        self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""}
+        self.InstancesTable = ResourceTable(self, [], ["Name", "Type", "Task"])
+        self.InstancesTable.SetColAlignements([wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT])
+        self.InstancesTable.SetColSizes([200, 150, 150])
+        self.InstancesGrid.SetTable(self.InstancesTable)
+        self.InstancesGrid.SetRowLabelSize(0)
+        self.InstancesTable.ResetView(self.InstancesGrid)
+
+    def SetMode(self, mode):
+        pass
+
+    def RefreshTypeList(self):
+        self.TypeList = ""
+        blocktypes = self.Controler.GetBlockResource()
+        for blocktype in blocktypes:
+            self.TypeList += ",%s"%blocktype
+
+    def RefreshTaskList(self):
+        self.TaskList = ""
+        for row in xrange(self.TasksTable.GetNumberRows()):
+            self.TaskList += ",%s"%self.TasksTable.GetValueByName(row, "Name")
+
+    def RefreshVariableList(self):
+        self.VariableList = ""
+        for variable in self.Controler.GetCurrentResourceEditingVariables():
+            self.VariableList += ",%s"%variable
+        
+    def RefreshModel(self):
+        self.Controler.SetCurrentResourceEditingInfos(self.TasksTable.GetData(), self.InstancesTable.GetData())
+
+    def RefreshView(self):
+        tasks, instances = self.Controler.GetCurrentResourceEditingInfos()
+        self.TasksTable.SetData(tasks)
+        self.InstancesTable.SetData(instances)
+        self.RefreshTypeList()
+        self.RefreshTaskList()
+        self.RefreshVariableList()
+        self.InstancesTable.ResetView(self.InstancesGrid)
+        self.TasksTable.ResetView(self.TasksGrid)
+
+    def OnAddTaskButton(self, event):
+        self.TasksTable.AppendRow(self.TasksDefaultValue.copy())
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnDeleteTaskButton(self, event):
+        row = self.TasksGrid.GetGridCursorRow()
+        self.TasksTable.RemoveRow(row)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnUpTaskButton(self, event):
+        row = self.TasksGrid.GetGridCursorRow()
+        self.TasksTable.MoveRow(row, -1, self.TasksGrid)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnDownTaskButton(self, event):
+        row = self.TasksGrid.GetGridCursorRow()
+        self.TasksTable.MoveRow(row, 1, self.TasksGrid)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnAddInstanceButton(self, event):
+        self.InstancesTable.AppendRow(self.InstancesDefaultValue.copy())
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnDeleteInstanceButton(self, event):
+        row = self.InstancesGrid.GetGridCursorRow()
+        self.InstancesTable.RemoveRow(row)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnUpInstanceButton(self, event):
+        row = self.InstancesGrid.GetGridCursorRow()
+        self.InstancesTable.MoveRow(row, -1, self.InstancesGrid)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnDownInstanceButton(self, event):
+        row = self.InstancesGrid.GetGridCursorRow()
+        self.InstancesTable.MoveRow(row, 1, self.InstancesGrid)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnTasksGridCellChange(self, event):
+        row, col = event.GetRow(), event.GetCol()
+        if self.TasksTable.GetColLabelValue(event.GetCol()) == "Name":
+            tasklist = self.TaskList.split(",")
+            for i in xrange(self.TasksTable.GetNumberRows()):
+                task = self.TasksTable.GetValueByName(i, "Name")
+                if task in tasklist:
+                    tasklist.remove(task)
+            tasklist.remove("")
+            if len(tasklist) > 0:
+                old_name = tasklist[0]
+                new_name = self.TasksTable.GetValue(row, col)
+                for i in xrange(self.InstancesTable.GetNumberRows()):
+                    if self.InstancesTable.GetValueByName(i, "Task") == old_name:
+                        self.InstancesTable.SetValueByName(i, "Task", new_name)
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
+
+    def OnInstancesGridCellChange(self, event):
+        self.RefreshModel()
+        self.RefreshView()
+        event.Skip()
--- a/SFCViewer.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/SFCViewer.py	Mon Jul 09 11:10:14 2007 +0200
@@ -23,7 +23,6 @@
 #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 *
 
@@ -31,6 +30,7 @@
 from graphics.GraphicCommons import *
 from graphics.SFC_Objects import *
 from Viewer import *
+from Dialogs import *
 
 class SFC_Viewer(Viewer):
     
@@ -178,8 +178,11 @@
 #-------------------------------------------------------------------------------
 
     def OnViewerLeftDown(self, event):
-        if self.Mode == MODE_SELECTION:
-            pos = event.GetPosition()
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftDown(self, event)
+        elif self.Mode == MODE_SELECTION:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
             if event.ControlDown():
                 element = self.FindElement(pos, True)
                 if element and element not in self.Wires:
@@ -207,16 +210,16 @@
                     self.Refresh()
                 if element:
                     self.SelectedElement = element
-                    self.SelectedElement.OnLeftDown(event, self.Scaling)
+                    self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
                     self.Refresh()
                 else:
                     self.rubberBand.Reset()
-                    self.rubberBand.OnLeftDown(event, self.Scaling)
+                    self.rubberBand.OnLeftDown(event, dc, self.Scaling)
         elif self.Mode == MODE_COMMENT:
             self.rubberBand.Reset()
-            self.rubberBand.OnLeftDown(event, self.Scaling)
+            self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
         elif self.Mode == MODE_WIRE:
-            pos = GetScaledEventPosition(event, self.Scaling)
+            pos = GetScaledEventPosition(event, self.GetLogicalDC(), 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)
@@ -231,10 +234,12 @@
         event.Skip()
 
     def OnViewerLeftUp(self, event):
-        if self.rubberBand.IsShown():
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftUp(self, event)
+        elif self.rubberBand.IsShown():
             if self.Mode == MODE_SELECTION:
                 elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
-                self.rubberBand.OnLeftUp(event, self.Scaling)
+                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
                 if len(elements) > 0:
                     self.SelectedElement = Graphic_Group(self)
                     self.SelectedElement.SetElements(elements)
@@ -242,21 +247,21 @@
                     self.Refresh()
             elif self.Mode == MODE_COMMENT:
                 bbox = self.rubberBand.GetCurrentExtent()
-                self.rubberBand.OnLeftUp(event, self.Scaling)
+                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
                 wxCallAfter(self.AddComment, bbox)
-        elif self.Mode == MODE_INITIAL_STEP:
-            wxCallAfter(self.AddInitialStep, GetScaledEventPosition(event, self.Scaling))
+        elif self.Mode == MODE_INITIALSTEP:
+            wxCallAfter(self.AddInitialStep, GetScaledEventPosition(event, self.GetLogicalDC(), 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)
+                self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), 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.OnMotion(event, self.GetLogicalDC(), self.Scaling)
             self.SelectedElement.GeneratePoints()
             self.SelectedElement.RefreshModel()
             self.SelectedElement.SetSelected(True)
@@ -264,40 +269,49 @@
         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()
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerRightUp(self, event)
+        else:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
+            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, dc, 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)
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerLeftDClick(self, event)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
             self.Refresh()
         event.Skip()
     
     def OnViewerMotion(self, event):
-        if self.rubberBand.IsShown():
-            self.rubberBand.OnMotion(event, self.Scaling)
+        if self.GetDrawingMode() == FREEDRAWING_MODE:
+            Viewer.OnViewerMotion(self, event)
+        elif self.rubberBand.IsShown():
+            self.rubberBand.OnMotion(event, self.GetLogicalDC(), self.Scaling)
         elif self.Mode == MODE_SELECTION and self.SelectedElement:
             if self.SelectedElement not in self.Wires:
-                self.SelectedElement.OnMotion(event, self.Scaling)
+                self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
             self.Refresh()
         elif self.Mode == MODE_WIRE and self.SelectedElement:
             self.SelectedElement.ResetPoints()
-            self.SelectedElement.OnMotion(event, self.Scaling)
+            self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
             self.SelectedElement.GeneratePoints()
             self.Refresh()
+        Viewer.OnViewerMotion(self, event)
         event.Skip()
 
 #-------------------------------------------------------------------------------
@@ -1017,659 +1031,3 @@
     def DeleteWire(self, wire):
         pass
 
-
-#-------------------------------------------------------------------------------
-#                          Edit Transition Content Dialog
-#-------------------------------------------------------------------------------
-
-[wxID_TRANSITIONCONTENTDIALOG, wxID_TRANSITIONCONTENTDIALOGMAINPANEL, 
- wxID_TRANSITIONCONTENTDIALOGREFERENCE, wxID_TRANSITIONCONTENTDIALOGINLINE, 
- wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, 
-] = [wx.NewId() for _init_ctrls in range(6)]
-
-class TransitionContentDialog(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_TRANSITIONCONTENTDIALOG,
-              name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
-              size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE,
-              title='Edit transition')
-        self.SetClientSize(wx.Size(300, 200))
-
-        self.MainPanel = wx.Panel(id=wxID_TRANSITIONCONTENTDIALOGMAINPANEL,
-              name='MainPanel', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(300, 200), style=wx.TAB_TRAVERSAL)
-        self.MainPanel.SetAutoLayout(True)
-
-        self.radioButton1 = wx.RadioButton(id=wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1,
-              label='Reference', name='radioButton1', parent=self.MainPanel,
-              pos=wx.Point(24, 24), size=wx.Size(114, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON1, self.OnTypeChanged)
-        self.radioButton1.SetValue(True)
-
-        self.Reference = wx.Choice(id=wxID_TRANSITIONCONTENTDIALOGREFERENCE,
-              name='Reference', parent=self.MainPanel, pos=wx.Point(48, 48), 
-              size=wx.Size(200, 24), style=0)
-
-        self.radioButton2 = wx.RadioButton(id=wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2,
-              label='Inline', name='radioButton2', parent=self.MainPanel,
-              pos=wx.Point(24, 72), size=wx.Size(114, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_TRANSITIONCONTENTDIALOGRADIOBUTTON2, self.OnTypeChanged)
-        self.radioButton2.SetValue(False)
-
-        self.Inline = wx.TextCtrl(id=wxID_TRANSITIONCONTENTDIALOGINLINE,
-              name='Inline', parent=self.MainPanel, pos=wx.Point(48, 96),
-              size=wx.Size(200, 24), style=0)
-
-        self._init_sizers()
-
-    def __init__(self, parent):
-        self._init_ctrls(parent)
-        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL|wxCENTRE)
-        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
-        
-        EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK)
-    
-    def OnOK(self, event):
-        error = []
-        if self.radioButton1.GetValue() and self.Reference.GetStringSelection() == "":
-            error.append("Reference")
-        if self.radioButton2.GetValue() and self.Inline.GetValue() == "":
-            error.append("Inline")
-        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 OnTypeChanged(self, event):
-        if self.radioButton1.GetValue():
-            self.Reference.Enable(True)
-            self.Inline.Enable(False)
-        else:
-            self.Reference.Enable(False)
-            self.Inline.Enable(True)
-        event.Skip()
-
-    def SetTransitions(self, transitions):
-        for transition in transitions:
-            self.Reference.Append(transition)
-
-    def SetValues(self, values):
-        if values["type"] == "reference":
-            self.radioButton1.SetValue(True)
-            self.radioButton2.SetValue(False)
-            self.Reference.Enable(True)
-            self.Inline.Enable(False)
-            self.Reference.SetStringSelection(values["value"])
-        elif values["type"] == "inline":
-            self.radioButton1.SetValue(False)
-            self.radioButton2.SetValue(True)
-            self.Reference.Enable(False)
-            self.Inline.Enable(True)
-            self.Inline.SetValue(values["value"])
-                
-    def GetValues(self):
-        values = {}
-        if self.radioButton1.GetValue():
-            values["type"] = "reference"
-            values["value"] = self.Reference.GetStringSelection()
-        else:
-            values["type"] = "inline"
-            values["value"] = self.Inline.GetValue()
-        return values
-
-#-------------------------------------------------------------------------------
-#                         Create New Divergence Dialog
-#-------------------------------------------------------------------------------
-
-[wxID_DIVERGENCECREATEDIALOG, wxID_DIVERGENCECREATEDIALOGMAINPANEL, 
- wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2,
- wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4, 
- wxID_DIVERGENCECREATEDIALOGSEQUENCES, wxID_DIVERGENCECREATEDIALOGPREVIEW, 
- wxID_DIVERGENCECREATEDIALOGSTATICTEXT1, wxID_DIVERGENCECREATEDIALOGSTATICTEXT2, 
- wxID_DIVERGENCECREATEDIALOGSTATICTEXT3,  
-] = [wx.NewId() for _init_ctrls in range(11)]
-
-class DivergenceCreateDialog(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_DIVERGENCECREATEDIALOG,
-              name='DivergencePropertiesDialog', parent=prnt, pos=wx.Point(376, 223),
-              size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE,
-              title='Create a new divergence or convergence')
-        self.SetClientSize(wx.Size(500, 260))
-
-        self.MainPanel = wx.Panel(id=wxID_DIVERGENCECREATEDIALOGMAINPANEL,
-              name='MainPanel', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(600, 220), style=wx.TAB_TRAVERSAL)
-        self.MainPanel.SetAutoLayout(True)
-
-        self.staticText1 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT1,
-              label='Type:', name='staticText1', parent=self.MainPanel,
-              pos=wx.Point(24, 24), size=wx.Size(200, 17), style=0)
-
-        self.radioButton1 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1,
-              label='Selection Divergence', name='radioButton1', parent=self.MainPanel,
-              pos=wx.Point(24, 48), size=wx.Size(200, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON1, self.OnTypeChanged)
-        self.radioButton1.SetValue(True)
-
-        self.radioButton2 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2,
-              label='Selection Convergence', name='radioButton2', parent=self.MainPanel, 
-              pos=wx.Point(24, 72), size=wx.Size(200, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON2, self.OnTypeChanged)
-        self.radioButton2.SetValue(False)
-
-        self.radioButton3 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3,
-              label='Simultaneous Divergence', name='radioButton3', parent=self.MainPanel,
-              pos=wx.Point(24, 96), size=wx.Size(200, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON3, self.OnTypeChanged)
-        self.radioButton3.SetValue(False)
-
-        self.radioButton4 = wx.RadioButton(id=wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4,
-              label='Simultaneous Convergence', name='radioButton4', parent=self.MainPanel, 
-              pos=wx.Point(24, 120), size=wx.Size(200, 24), style=0)
-        EVT_RADIOBUTTON(self, wxID_DIVERGENCECREATEDIALOGRADIOBUTTON4, self.OnTypeChanged)
-        self.radioButton4.SetValue(False)
-
-        self.staticText2 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT2,
-              label='Number of sequences:', name='staticText2', parent=self.MainPanel,
-              pos=wx.Point(24, 150), size=wx.Size(200, 17), style=0)
-
-        self.Sequences = wx.SpinCtrl(id=wxID_DIVERGENCECREATEDIALOGSEQUENCES,
-              name='Sequences', parent=self.MainPanel, pos=wx.Point(24, 174),
-              size=wx.Size(200, 24), style=0, min=2, max=20)
-        EVT_SPINCTRL(self, wxID_DIVERGENCECREATEDIALOGSEQUENCES, self.OnSequencesChanged)
-
-        self.staticText3 = wx.StaticText(id=wxID_DIVERGENCECREATEDIALOGSTATICTEXT3,
-              label='Preview:', name='staticText3', parent=self.MainPanel,
-              pos=wx.Point(250, 24), size=wx.Size(100, 17), style=0)
-
-        self.Preview = wx.Panel(id=wxID_DIVERGENCECREATEDIALOGPREVIEW,
-              name='Preview', parent=self.MainPanel, pos=wx.Point(250, 48),
-              size=wx.Size(225, 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|wxCENTRE)
-        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
-        
-        self.Divergence = None
-        
-        EVT_PAINT(self, self.OnPaint)
-
-    def GetValues(self):
-        values = {}
-        if self.radioButton1.GetValue():
-            values["type"] = SELECTION_DIVERGENCE
-        elif self.radioButton2.GetValue():
-            values["type"] = SELECTION_CONVERGENCE
-        elif self.radioButton3.GetValue():
-            values["type"] = SIMULTANEOUS_DIVERGENCE
-        else:
-            values["type"] = SIMULTANEOUS_CONVERGENCE
-        values["number"] = self.Sequences.GetValue()
-        return values
-
-    def OnTypeChanged(self, event):
-        self.RefreshPreview()
-        event.Skip()
-
-    def OnSequencesChanged(self, event):
-        self.RefreshPreview()
-        event.Skip()
-        
-    def RefreshPreview(self):
-        dc = wxClientDC(self.Preview)
-        dc.Clear()
-        if self.radioButton1.GetValue():
-            self.Divergence = SFC_Divergence(self.Preview, SELECTION_DIVERGENCE, self.Sequences.GetValue())
-        elif self.radioButton2.GetValue():
-            self.Divergence = SFC_Divergence(self.Preview, SELECTION_CONVERGENCE, self.Sequences.GetValue())
-        elif self.radioButton3.GetValue():
-            self.Divergence = SFC_Divergence(self.Preview, SIMULTANEOUS_DIVERGENCE, self.Sequences.GetValue())
-        else:
-            self.Divergence = SFC_Divergence(self.Preview, SIMULTANEOUS_CONVERGENCE, self.Sequences.GetValue())
-        width, height = self.Divergence.GetSize()
-        clientsize = self.Preview.GetClientSize()
-        x = (clientsize.width - width) / 2
-        y = (clientsize.height - height) / 2
-        self.Divergence.SetPosition(x, y)
-        self.Divergence.Draw(dc)
-
-    def OnPaint(self, event):
-        self.RefreshPreview()
-
-
-#-------------------------------------------------------------------------------
-#                            Action Block Dialog
-#-------------------------------------------------------------------------------
-
-class ActionTable(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
-                readonly = False
-                colname = self.GetColLabelValue(col)
-                if colname == "Qualifier":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.QualifierList)
-                if colname == "Duration":
-                    editor = wxGridCellTextEditor()
-                    renderer = wxGridCellStringRenderer()
-                    if self.Parent.DurationList[self.data[row]["Qualifier"]]:
-                        readonly = False
-                    else:
-                        readonly = True
-                        self.data[row]["Duration"] = ""
-                elif colname == "Type":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.TypeList)
-                elif colname == "Value":
-                    type = self.data[row]["Type"]
-                    if type == "Action":
-                        editor = wxGridCellChoiceEditor()
-                        editor.SetParameters(self.Parent.ActionList)
-                    elif type == "Variable":
-                        editor = wxGridCellChoiceEditor()
-                        editor.SetParameters(self.Parent.VariableList)
-                    elif type == "Inline":
-                        editor = wxGridCellTextEditor()
-                        renderer = wxGridCellStringRenderer()
-                elif colname == "Indicator":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.VariableList)
-                    
-                grid.SetCellEditor(row, col, editor)
-                grid.SetCellRenderer(row, col, renderer)
-                grid.SetReadOnly(row, col, readonly)
-                
-                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_ACTIONBLOCKDIALOG, wxID_ACTIONBLOCKDIALOGMAINPANEL, 
- wxID_ACTIONBLOCKDIALOGVARIABLESGRID, wxID_ACTIONBLOCKDIALOGSTATICTEXT1, 
- wxID_ACTIONBLOCKDIALOGADDBUTTON,wxID_ACTIONBLOCKDIALOGDELETEBUTTON, 
- wxID_ACTIONBLOCKDIALOGUPBUTTON, wxID_ACTIONBLOCKDIALOGDOWNBUTTON, 
-] = [wx.NewId() for _init_ctrls in range(8)]
-
-class ActionBlockDialog(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_ACTIONBLOCKDIALOG,
-              name='ActionBlockDialog', parent=prnt, pos=wx.Point(376, 223),
-              size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE,
-              title='Edit action block properties')
-        self.SetClientSize(wx.Size(500, 300))
-
-        self.MainPanel = wx.Panel(id=wxID_ACTIONBLOCKDIALOGMAINPANEL,
-              name='MainPanel', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
-        self.MainPanel.SetAutoLayout(True)
-
-        self.staticText1 = wx.StaticText(id=wxID_ACTIONBLOCKDIALOGSTATICTEXT1,
-              label='Actions:', name='staticText1', parent=self.MainPanel,
-              pos=wx.Point(24, 24), size=wx.Size(95, 17), style=0)
-
-        self.ActionsGrid = wx.grid.Grid(id=wxID_ACTIONBLOCKDIALOGVARIABLESGRID,
-              name='ActionsGrid', parent=self.MainPanel, pos=wx.Point(24, 44), 
-              size=wx.Size(450, 150), style=wxVSCROLL)
-        self.ActionsGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
-              'Sans'))
-        self.ActionsGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
-              False, 'Sans'))
-        self.ActionsGrid.DisableDragGridSize()
-        self.ActionsGrid.EnableScrolling(False, True)
-        EVT_GRID_CELL_CHANGE(self.ActionsGrid, self.OnActionsGridCellChange)
-
-        self.AddButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGADDBUTTON, label='Add',
-              name='AddButton', parent=self.MainPanel, pos=wx.Point(245, 204),
-              size=wx.Size(72, 32), style=0)
-        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGADDBUTTON, self.OnAddButton)
-
-        self.DeleteButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGDELETEBUTTON, label='Delete',
-              name='DeleteButton', parent=self.MainPanel, pos=wx.Point(325, 204),
-              size=wx.Size(72, 32), style=0)
-        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGDELETEBUTTON, self.OnDeleteButton)
-
-        self.UpButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGUPBUTTON, label='^',
-              name='UpButton', parent=self.MainPanel, pos=wx.Point(405, 204),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGUPBUTTON, self.OnUpButton)
-
-        self.DownButton = wx.Button(id=wxID_ACTIONBLOCKDIALOGDOWNBUTTON, label='v',
-              name='DownButton', parent=self.MainPanel, pos=wx.Point(445, 204),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_ACTIONBLOCKDIALOGDOWNBUTTON, self.OnDownButton)
-
-        self._init_sizers()
-
-    def __init__(self, parent):
-        self._init_ctrls(parent)
-        self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL|wxCENTRE)
-        self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT)
-        
-        self.DefaultValue = {"Qualifier" : "N", "Duration" : "", "Type" : "Action", "Value" : "", "Indicator" : ""}
-        self.Table = ActionTable(self, [], ["Qualifier","Duration","Type","Value","Indicator"])
-        self.TypeList = "Action,Variable,Inline"
-        self.ColSizes = [60, 90, 80, 110, 80]
-        self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT]
-        
-        self.ActionsGrid.SetTable(self.Table)
-        self.ActionsGrid.SetRowLabelSize(0)
-        
-        self.Table.ResetView(self.ActionsGrid)
-
-    def OnAddButton(self, event):
-        self.Table.AppendRow(self.DefaultValue.copy())
-        self.Table.ResetView(self.ActionsGrid)
-        event.Skip()
-
-    def OnDeleteButton(self, event):
-        row = self.ActionsGrid.GetGridCursorRow()
-        self.Table.RemoveRow(row)
-        self.Table.ResetView(self.ActionsGrid)
-        event.Skip()
-
-    def OnUpButton(self, event):
-        row = self.ActionsGrid.GetGridCursorRow()
-        self.Table.MoveRow(row, -1, self.ActionsGrid)
-        self.Table.ResetView(self.ActionsGrid)
-        event.Skip()
-
-    def OnDownButton(self, event):
-        row = self.ActionsGrid.GetGridCursorRow()
-        self.Table.MoveRow(row, 1, self.ActionsGrid)
-        self.Table.ResetView(self.ActionsGrid)
-        event.Skip()
-
-    def OnActionsGridCellChange(self, event):
-        self.Table.ResetView(self.ActionsGrid)
-        event.Skip()
-
-    def SetQualifierList(self, list):
-        self.QualifierList = ""
-        sep = ""
-        for qualifier in list.keys():
-            self.QualifierList += "%s%s"%(sep, qualifier)
-            sep = ","
-        self.DurationList = list
-
-    def SetVariableList(self, list):
-        self.VariableList = ""
-        sep = ""
-        for variable in list:
-            self.VariableList += "%s%s"%(sep, variable["Name"])
-            sep = ","
-
-    def SetActionList(self, list):
-        self.ActionList = ""
-        sep = ""
-        for action in list:
-            self.ActionList += "%s%s"%(sep, action)
-            sep = ","
-
-    def SetValues(self, actions):
-        for action in actions:
-            row = {"Qualifier" : action["qualifier"], "Value" : action["value"]}
-            if action["type"] == "reference":
-                if action["value"] in self.ActionList:
-                    row["Type"] = "Action"
-                elif action["value"] in self.VariableList:
-                    row["Type"] = "Variable"
-                else:
-                    row["Type"] = "Inline"
-            else:
-                row["Type"] = "Inline"
-            if "duration" in action:
-                row["Duration"] = action["duration"]
-            else:
-                row["Duration"] = ""
-            if "indicator" in action:
-                row["Indicator"] = action["indicator"]
-            else:
-                row["Indicator"] = ""
-            self.Table.AppendRow(row)
-        self.Table.ResetView(self.ActionsGrid)
-    
-    def GetValues(self):
-        values = []
-        for data in self.Table.GetData():
-            print data
-            action = {"qualifier" : data["Qualifier"], "value" : data["Value"]}
-            if data["Type"] in ["Action", "Variable"]:
-                action["type"] = "reference"
-            else:
-                action["type"] = "inline"
-            if data["Duration"] != "":
-                action["duration"] = data["Duration"]
-            if data["Indicator"] != "":
-                action["indicator"] = data["Indicator"]
-            values.append(action)
-        return values
-
-
-#-------------------------------------------------------------------------------
-#                          Edit Step Name Dialog
-#-------------------------------------------------------------------------------
-
-class StepNameDialog(wxTextEntryDialog):
-
-    def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", 
-                       style = wxOK|wxCANCEL|wxCENTRE, pos = wxDefaultPosition):
-        wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
-        
-        self.PouNames = []
-        self.Variables = []
-        self.StepNames = []
-        
-        EVT_BUTTON(self, self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId(), self.OnOK)
-        
-    def OnOK(self, event):
-        step_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
-        if step_name == "":
-            message = wxMessageDialog(self, "You must type a name!", "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        elif not TestIdentifier(step_name):
-            message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%step_name, "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        elif step_name.upper() in IEC_KEYWORDS:
-            message = wxMessageDialog(self, "\"%s\" is a keyword. It can't be used!"%step_name, "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        elif step_name.upper() in self.PouNames:
-            message = wxMessageDialog(self, "A pou with \"%s\" as name exists!"%step_name, "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        elif step_name.upper() in self.Variables:
-            message = wxMessageDialog(self, "A variable with \"%s\" as name exists!"%step_name, "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        elif step_name.upper() in self.StepNames:
-            message = wxMessageDialog(self, "\"%s\" step already exists!"%step_name, "Error", wxOK|wxICON_ERROR)
-            message.ShowModal()
-            message.Destroy()
-        else:
-            self.EndModal(wxID_OK)
-
-    def SetPouNames(self, pou_names):
-        self.PouNames = [pou_name.upper() for pou_name in pou_names]
-
-    def SetVariables(self, variables):
-        self.Variables = [var["Name"].upper() for var in variables]
-
-    def SetStepNames(self, step_names):
-        self.StepNames = [step_name.upper() for step_name in step_names]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextViewer.py	Mon Jul 09 11:10:14 2007 +0200
@@ -0,0 +1,321 @@
+#!/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 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 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.stc import * 
+import wx
+
+import re
+
+#-------------------------------------------------------------------------------
+#                         Textual programs Viewer class
+#-------------------------------------------------------------------------------
+
+
+NEWLINE = "\n"
+NUMBERS = [str(i) for i in xrange(10)]
+LETTERS = ['_']
+for i in xrange(26):
+    LETTERS.append(chr(ord('a') + i))
+    LETTERS.append(chr(ord('A') + i))
+
+[wxSTC_PLC_WORD, wxSTC_PLC_COMMENT, wxSTC_PLC_NUMBER, wxSTC_PLC_VARIABLE, 
+ wxSTC_PLC_FUNCTION, wxSTC_PLC_JUMP] = range(6)
+[SPACE, WORD, NUMBER, COMMENT] = range(4)
+
+[wxID_TEXTVIEWER,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+if wx.Platform == '__WXMSW__':
+    faces = { 'times': 'Times New Roman',
+              'mono' : 'Courier New',
+              'helv' : 'Arial',
+              'other': 'Comic Sans MS',
+              'size' : 10,
+             }
+else:
+    faces = { 'times': 'Times',
+              'mono' : 'Courier',
+              'helv' : 'Helvetica',
+              'other': 'new century schoolbook',
+              'size' : 12,
+             }
+re_texts = {}
+re_texts["letter"] = "[A-Za-z]"
+re_texts["digit"] = "[0-9]"
+re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts
+IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
+LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts)
+
+class TextViewer(wxStyledTextCtrl):
+    
+    def __init__(self, parent, window, controler):
+        wxStyledTextCtrl.__init__(self, parent, wxID_TEXTVIEWER, style=0)
+        
+        self.CmdKeyAssign(ord('+'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMIN)
+        self.CmdKeyAssign(ord('-'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMOUT)
+        
+        self.SetViewWhiteSpace(False)
+        
+        self.SetLexer(wxSTC_LEX_CONTAINER)
+        
+        # Global default styles for all languages
+        self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+        self.StyleClearAll()  # Reset all to be like the default
+        
+        self.StyleSetSpec(wxSTC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
+        self.SetSelBackground(1, "#E0E0E0")
+        
+        # Highlighting styles
+        self.StyleSetSpec(wxSTC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
+        self.StyleSetSpec(wxSTC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
+        self.StyleSetSpec(wxSTC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
+        self.StyleSetSpec(wxSTC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
+        self.StyleSetSpec(wxSTC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
+        self.StyleSetSpec(wxSTC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
+        
+        # Indicators styles
+        self.IndicatorSetStyle(0, wxSTC_INDIC_SQUIGGLE)
+        self.IndicatorSetForeground(0, wxRED)
+        
+        # Line numbers in the margin
+        self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
+        self.SetMarginWidth(1, 50)
+        
+        # Indentation size
+        self.SetTabWidth(2)
+        self.SetUseTabs(0)
+        
+        self.Keywords = []
+        self.Variables = []
+        self.Functions = []
+        self.Jumps = []
+        self.TextChanged = False
+        self.TextSyntax = "ST"
+        
+        self.Controler = controler
+
+        EVT_KEY_DOWN(self, self.OnKeyDown)
+        EVT_STC_STYLENEEDED(self, wxID_TEXTVIEWER, self.OnStyleNeeded)
+        EVT_KILL_FOCUS(self, self.OnKillFocus)
+    
+    def SetTextSyntax(self, syntax):
+        self.TextSyntax = syntax
+    
+    def SetKeywords(self, keywords):
+        self.Keywords = [keyword.upper() for keyword in keywords]
+        self.Colourise(0, -1)
+    
+    def SetVariables(self, variables):
+        self.Variables = [variable.upper() for variable in variables]
+        self.Colourise(0, -1)
+    
+    def SetFunctions(self, blocktypes):
+        self.Functions = []
+        for category in blocktypes:
+            for blocktype in category["list"]:
+                if blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables:
+                    self.Functions.append(blocktype["name"].upper())
+        self.Colourise(0, -1)
+    
+    def RefreshJumpList(self):
+        self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]
+        self.Colourise(0, -1)
+    
+    def RefreshView(self):
+        self.SetText(self.Controler.GetCurrentElementEditingText())
+        self.RefreshJumpList()
+    
+    def OnStyleNeeded(self, event):
+        self.TextChanged = True
+        line = self.LineFromPosition(self.GetEndStyled())
+        if line == 0:
+            start_pos = 0
+        else:
+            start_pos = self.GetLineEndPosition(line - 1) + 1
+        end_pos = event.GetPosition()
+        self.StartStyling(start_pos, 0xff)
+        
+        i = start_pos
+        state = SPACE
+        line = ""
+        word = ""
+        while i < end_pos:
+            char = chr(self.GetCharAt(i)).upper()
+            line += char
+            if char == NEWLINE:
+                if state == COMMENT:
+                    self.SetStyling(i - start_pos + 1, wxSTC_PLC_COMMENT)
+                elif state == NUMBER:
+                    self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
+                elif state == WORD:
+                    if word in self.Keywords:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
+                    elif word in self.Variables:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
+                    elif word in self.Functions:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
+                    elif word in self.Jumps:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
+                    else:
+                        self.SetStyling(i - start_pos, 31)
+                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
+                            self.StartStyling(start_pos, wxSTC_INDICS_MASK)
+                            self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
+                            self.StartStyling(i, 0xff)    
+                else:
+                    self.SetStyling(i - start_pos, 31)
+                start_pos = i
+                state = SPACE
+                line = ""
+            elif line.endswith("(*") and state != COMMENT:
+                self.SetStyling(i - start_pos - 1, 31)
+                start_pos = i
+                state = COMMENT
+            elif state == COMMENT:
+                if line.endswith("*)"):
+                    self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
+                    start_pos = i + 1
+                    state = SPACE
+            elif char in LETTERS:
+                if state == NUMBER:
+                    word = "#"
+                    state = WORD
+                elif state == SPACE:
+                    self.SetStyling(i - start_pos, 31)
+                    word = char
+                    start_pos = i
+                    state = WORD
+                else:
+                    word += char
+            elif char in NUMBERS or char == '.' and state != WORD:
+                if state == SPACE:
+                    self.SetStyling(i - start_pos, 31)
+                    start_pos = i
+                    state = NUMBER
+                if state == WORD and char != '.':
+                    word += char
+            else:
+                if state == WORD:
+                    if word in self.Keywords:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
+                    elif word in self.Variables:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
+                    elif word in self.Functions:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
+                    elif word in self.Jumps:
+                        self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
+                    else:
+                        self.SetStyling(i - start_pos, 31)
+                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
+                            self.StartStyling(start_pos, wxSTC_INDICS_MASK)
+                            self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
+                            self.StartStyling(i, 0xff)
+                    word = ""
+                    start_pos = i
+                    state = SPACE
+                elif state == NUMBER:
+                    self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
+                    start_pos = i
+                    state = SPACE
+            i += 1
+        if state == COMMENT:
+            self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
+        elif state == NUMBER:
+            self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
+        elif state == WORD:
+            if word in self.Keywords:
+                self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
+            elif word in self.Variables:
+                self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
+            elif word in self.Functions:
+                self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
+            elif word in self.Jumps:
+                self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
+            else:
+                self.SetStyling(i - start_pos, 31)
+        else:
+            self.SetStyling(i - start_pos, 31)
+        event.Skip()
+    
+    def Cut(self):
+        self.CmdKeyExecute(wxSTC_CMD_CUT)
+        
+    def Copy(self):
+        self.CmdKeyExecute(wxSTC_CMD_COPY)
+    
+    def Paste(self):
+        self.CmdKeyExecute(wxSTC_CMD_PASTE)
+    
+    def RefreshModel(self):
+        if self.TextChanged:
+            self.RefreshJumpList()
+            self.Controler.SetCurrentElementEditingText(self.GetText())
+    
+    def OnKeyDown(self, event):
+        if self.CallTipActive():
+            self.CallTipCancel()
+        key = event.KeyCode()
+
+        # Code completion
+        if key == WXK_SPACE and event.ControlDown():
+            
+            line = self.GetCurrentLine()
+            if line == 0:
+                start_pos = 0
+            else:
+                start_pos = self.GetLineEndPosition(line - 1) + 1
+            end_pos = self.GetCurrentPos()
+
+            lineText = self.GetTextRange(start_pos, end_pos).replace("\t", " ")
+            words = lineText.split(" ")
+            words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1]
+                        
+            kw = []
+            
+            if self.TextSyntax == "IL":
+                if len(words) == 1:
+                    kw = self.Keywords
+                elif len(words) == 2:
+                    if words[0].upper() in ["CAL", "CALC", "CALNC"]:
+                        kw = self.Functions
+                    elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]:
+                        kw = self.Jumps
+                    else:
+                        kw = self.Variables
+            else:
+                kw = self.Keywords + self.Variables + self.Functions
+            if len(kw) > 0:
+                kw.sort()
+                self.AutoCompSetIgnoreCase(True)
+                self.AutoCompShow(len(words[-1]), " ".join(kw))
+        else:
+            self.TextChanged = False
+            wxCallAfter(self.RefreshModel)
+            event.Skip()
+
+    def OnKillFocus(self, event):
+        self.AutoCompCancel()
+        event.Skip()
+
--- a/Viewer.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/Viewer.py	Mon Jul 09 11:10:14 2007 +0200
@@ -23,17 +23,19 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from wxPython.wx import *
-from wxPython.stc import * 
-from wxPython.grid import *
 import wx
 
 from plcopen.structures import *
 from graphics.GraphicCommons import *
-from graphics.SFC_Objects import *
 from graphics.FBD_Objects import *
 from graphics.LD_Objects import *
-
-import re
+from graphics.SFC_Objects import *
+
+from Dialogs import *
+
+SCROLLBAR_UNIT = 10
+WINDOW_BORDER = 10
+SCROLL_ZONE = 10
 
 #-------------------------------------------------------------------------------
 #                       Graphic elements Viewer base class
@@ -107,7 +109,7 @@
     
     # Create a new Viewer
     def __init__(self, parent, window, controler):
-        wx.ScrolledWindow.__init__(self, parent, style=wx.SUNKEN_BORDER)
+        wx.ScrolledWindow.__init__(self, parent, style=wx.SUNKEN_BORDER | wx.HSCROLL | wx.VSCROLL)
         self._init_menus()
         # Adding a rubberband to Viewer
         self.rubberBand = RubberBand(drawingSurface=self)
@@ -133,6 +135,8 @@
         EVT_RIGHT_UP(self, self.OnViewerRightUp)
         EVT_MOTION(self, self.OnViewerMotion)
         EVT_CHAR(self, self.OnChar)
+        EVT_SCROLLWIN(self, self.OnMoveWindow)
+        EVT_SIZE(self, self.OnMoveWindow)
     
     # Returns a new id
     def GetNewId(self):
@@ -143,6 +147,11 @@
     def __del__(self):
         self.ResetView()
 
+    def GetLogicalDC(self):
+        dc = wxClientDC(self)
+        self.DoPrepareDC(dc)
+        return dc
+
 #-------------------------------------------------------------------------------
 #                              Reset functions
 #-------------------------------------------------------------------------------
@@ -167,6 +176,10 @@
             self.SelectedElement = None
             self.Refresh()
 
+    # Return current drawing mode
+    def GetDrawingMode(self):
+        return self.Parent.GetDrawingMode()
+
 #-------------------------------------------------------------------------------
 #                          Refresh functions
 #-------------------------------------------------------------------------------
@@ -184,8 +197,27 @@
             instance = self.Controler.GetCurrentElementEditingInstanceInfos(exclude=ids)
             if instance:
                 self.loadInstance(instance, ids)
+        self.RefreshScrollBar()
         self.Refresh()
     
+    def RefreshScrollBar(self):
+        xstart, ystart = self.GetViewStart()
+        window_size = self.GetClientSize()
+        maxx = maxy = 0
+        for element in self.Elements:
+            posx, posy = element.GetPosition()
+            width, height = element.GetSize()
+            maxx = max(maxx, posx + width)
+            maxy = max(maxy, posy + height)
+        maxx = max(maxx + WINDOW_BORDER, xstart * SCROLLBAR_UNIT + window_size[0])
+        maxy = max(maxy + WINDOW_BORDER, ystart * SCROLLBAR_UNIT + window_size[1])
+        if self.rubberBand.IsShown():
+            extent = self.rubberBand.GetCurrentExtent()
+            maxx = max(maxx, extent.x + extent.width)
+            maxy = max(maxy, extent.y + extent.height)
+        self.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+            maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, xstart, ystart)
+    
     # Load instance from given informations
     def loadInstance(self, instance, ids):
         ids.append(instance["id"])
@@ -432,7 +464,7 @@
                 connected = self.FindElementById(refLocalId)
                 if connected:
                     points = link["points"]
-                    end_connector = connected.GetConnector(wxPoint(points[-1][0], points[-1][1]))
+                    end_connector = connected.GetConnector(wxPoint(points[-1][0], points[-1][1]), link["formalParameter"])
                     if end_connector:
                         wire = Wire(self)
                         wire.SetPoints(points)
@@ -629,18 +661,180 @@
 #-------------------------------------------------------------------------------
 
     def OnViewerLeftDown(self, event):
+        if self.Mode == MODE_SELECTION:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
+            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, dc, self.Scaling)
+                    self.Refresh()
+                else:
+                    self.rubberBand.Reset()
+                    self.rubberBand.OnLeftDown(event, dc, self.Scaling)
+        elif self.Mode in [MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, 
+                           MODE_CONTACT, MODE_COIL, MODE_POWERRAIL, MODE_INITIALSTEP, 
+                           MODE_STEP, MODE_TRANSITION, MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION]:
+            self.rubberBand.Reset()
+            self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
+        elif self.Mode == MODE_WIRE:
+            pos = GetScaledEventPosition(event, self.GetLogicalDC(), self.Scaling)
+            connector = self.FindBlockConnector(pos)
+            if connector:
+                if (connector.GetDirection() == EAST):
+                    wire = Wire(self, [wxPoint(pos.x, pos.y), EAST], [wxPoint(pos.x, pos.y), WEST])
+                else:
+                    wire = Wire(self, [wxPoint(pos.x, pos.y), WEST], [wxPoint(pos.x, pos.y), EAST])
+                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
+            elif self.SelectedElement:
+                self.SelectedElement.SetSelected(False)
+                self.SelectedElement = None
+            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.GetLogicalDC(), self.Scaling)
+                if len(elements) > 0:
+                    self.SelectedElement = Graphic_Group(self)
+                    self.SelectedElement.SetElements(elements)
+                    self.SelectedElement.SetSelected(True)
+                    self.Refresh()
+            else:
+                bbox = self.rubberBand.GetCurrentExtent()
+                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)                
+                if self.Mode == MODE_BLOCK:
+                    wxCallAfter(self.AddNewBlock, bbox)
+                elif self.Mode == MODE_VARIABLE:
+                    wxCallAfter(self.AddNewVariable, bbox)
+                elif self.Mode == MODE_CONNECTION:
+                    wxCallAfter(self.AddNewConnection, bbox)
+                elif self.Mode == MODE_COMMENT:
+                    wxCallAfter(self.AddNewComment, bbox)
+                elif self.Mode == MODE_CONTACT:
+                    wxCallAfter(self.AddNewContact, bbox)
+                elif self.Mode == MODE_COIL:
+                    wxCallAfter(self.AddNewContact, bbox)
+                elif self.Mode == MODE_POWERRAIL:
+                    wxCallAfter(self.AddNewPowerRail, bbox)
+                elif self.Mode == MODE_INITIALSTEP:
+                    wxCallAfter(self.AddNewInitialStep, bbox)
+                elif self.Mode == MODE_STEP:
+                    wxCallAfter(self.AddNewStep, bbox)
+                elif self.Mode == MODE_TRANSITION:
+                    wxCallAfter(self.AddNewTransition, bbox)
+                elif self.Mode == MODE_DIVERGENCE:
+                    wxCallAfter(self.AddNewDivergence, bbox)
+                elif self.Mode == MODE_JUMP:
+                    wxCallAfter(self.AddNewJump, bbox)
+                elif self.Mode == MODE_ACTION:
+                    wxCallAfter(self.AddNewActionBlock, bbox)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
+            wxCallAfter(self.SetCursor, wxNullCursor)
+            self.ReleaseMouse()
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            dc = self.GetLogicalDC()
+            pos = GetScaledEventPosition(event, dc, self.Scaling)
+            connector = self.FindBlockConnector(pos, False)
+            if connector and connector != self.SelectedElement.StartConnected:
+                self.SelectedElement.ResetPoints()
+                self.SelectedElement.OnMotion(event, dc, self.Scaling)
+                self.SelectedElement.GeneratePoints()
+                self.SelectedElement.RefreshModel()
+                self.SelectedElement.SetSelected(True)
+            else:
+                self.SelectedElement.Delete()
+                self.SelectedElement = None
+            self.Refresh()
+        if not self.SavedMode:
+            wxCallAfter(self.Parent.ResetCurrentMode)
         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.GetLogicalDC(), 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.GetLogicalDC(), self.Scaling)
+            self.Refresh()
         event.Skip()
     
     def OnViewerMotion(self, event):
+        if self.rubberBand.IsShown():
+            self.rubberBand.OnMotion(event, self.GetLogicalDC(), self.Scaling)
+        elif self.Mode == MODE_SELECTION and self.SelectedElement:
+            self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
+            self.Refresh()
+        elif self.Mode == MODE_WIRE and self.SelectedElement:
+            dc = self.GetLogicalDC()
+            pos = GetScaledEventPosition(event, dc, self.Scaling)
+            connector = self.FindBlockConnector(pos, False)
+            if not connector or self.SelectedElement.EndConnected == None:
+                self.SelectedElement.ResetPoints()
+                self.SelectedElement.OnMotion(event, dc, self.Scaling)
+                self.SelectedElement.GeneratePoints()
+                self.Refresh()
+        if (event.Dragging() and self.SelectedElement) or self.rubberBand.IsShown():
+            position = event.GetPosition()
+            move_window = wxPoint()
+            window_size = self.GetClientSize()
+            xstart, ystart = self.GetViewStart()
+            if position.x < SCROLL_ZONE and xstart > 0:
+                move_window.x = -1
+            elif position.x > window_size[0] - SCROLL_ZONE:
+                move_window.x = 1
+            if position.y < SCROLL_ZONE and ystart > 0:
+                move_window.y = -1
+            elif position.y > window_size[1] - SCROLL_ZONE:
+                move_window.y = 1
+            if move_window.x != 0 or move_window.y != 0:
+                self.Scroll(xstart + move_window.x, ystart + move_window.y)
+            self.RefreshScrollBar()
         event.Skip()
 
 #-------------------------------------------------------------------------------
@@ -648,7 +842,206 @@
 #-------------------------------------------------------------------------------
 
     def OnChar(self, event):
-        event.Skip()
+        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()
+
+#-------------------------------------------------------------------------------
+#                          Model adding 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.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.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_Connector(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.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()
+
+    def AddNewContact(self, bbox):
+        dialog = LDElementDialog(self.Parent, "contact")
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                if var["Class"] != "Output" and var["Type"] == "BOOL":
+                    varlist.append(var["Name"])
+        dialog.SetVariables(varlist)
+        dialog.SetValues({"name":"","type":CONTACT_NORMAL})
+        dialog.SetElementSize(bbox.width, bbox.height)
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            contact = LD_Contact(self, values["type"], values["name"], id)
+            contact.SetPosition(bbox.x, bbox.y)
+            contact.SetSize(values["width"], values["height"])
+            self.Blocks.append(contact)
+            self.Elements.append(contact)
+            self.Controler.AddCurrentElementEditingContact(id)
+            self.RefreshContactModel(contact)
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewCoil(self, bbox):
+        dialog = LDElementDialog(self.Parent, "coil")
+        varlist = []
+        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
+        if vars:
+            for var in vars:
+                if var["Class"] != "Input" and var["Type"] == "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})
+        dialog.SetElementSize(bbox.width, bbox.height)
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            coil = LD_Coil(self, values["type"], values["name"], id)
+            coil.SetPosition(bbox.x, bbox.y)
+            coil.SetSize(values["width"], values["height"])
+            self.Blocks.append(coil)
+            self.Elements.append(coil)
+            self.Controler.AddCurrentElementEditingCoil(id)
+            self.RefreshCoilModel(contact)
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewPowerRail(self, bbox):
+        dialog = LDPowerRailDialog(self.Parent)
+        dialog.SetMinSize((bbox.width, bbox.height))
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            powerrail = LD_PowerRail(self, values["type"], id, [True for i in xrange(values["number"])])
+            powerrail.SetPosition(bbox.x, bbox.y)
+            powerrail.SetSize(values["width"], values["height"])
+            self.Blocks.append(powerrail)
+            self.Elements.append(powerrail)
+            self.Controler.AddCurrentElementEditingPowerRail(id, values["type"])
+            self.RefreshPowerRailModel(powerrail)
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewTransition(self, bbox):
+        dialog = TransitionContentDialog(self.Parent)
+        dialog.SetTransitions(self.Controler.GetCurrentElementEditingTransitions())
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            transition = SFC_Transition(self, values["type"], values["value"], id)
+            transition.SetPosition(bbox.x, bbox.y)
+            min_width, min_height = transition.GetMinSize()
+            transition.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            self.Blocks.append(transition)
+            self.Elements.append(transition)
+            self.Controler.AddCurrentElementEditingTransition(id)
+            self.RefreshTransitionModel(transition)
+            self.Refresh()
+        dialog.Destroy()
+
+    def AddNewDivergence(self, bbox):
+        dialog = DivergenceCreateDialog(self.Parent)
+        dialog.SetMinSize((bbox.width, bbox.height))
+        if dialog.ShowModal() == wxID_OK:
+            id = self.GetNewId()
+            values = dialog.GetValues()
+            divergence = SFC_Divergence(self, values["type"], values["number"], id)
+            divergence.SetPosition(bbox.x, bbox.y)
+            min_width, min_height = divergence.GetMinSize()
+            divergence.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            self.Blocks.append(divergence)
+            self.Elements.append(divergence)
+            self.Controler.AddCurrentElementEditingDivergence(id, values["type"])
+            self.RefreshDivergenceModel(divergence)
+            self.Refresh()
+        dialog.Destroy()
 
 #-------------------------------------------------------------------------------
 #                          Model update functions
@@ -764,6 +1157,146 @@
         infos["connector"] = actionblock.GetConnector()
         self.Controler.SetCurrentElementEditingActionBlockInfos(actionblockid, infos)
 
+
+#-------------------------------------------------------------------------------
+#                          Model delete functions
+#-------------------------------------------------------------------------------
+
+
+    def DeleteBlock(self, block):
+        elements = []
+        for output in block.GetConnectors()["outputs"]:
+            for element in output.GetConnectedBlocks():
+                if element not in elements:
+                    elements.append(element)
+        block.Clean()
+        self.Blocks.remove(block)
+        self.Elements.remove(block)
+        self.Controler.RemoveCurrentElementEditingInstance(block.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+    def DeleteVariable(self, variable):
+        connectors = variable.GetConnectors()
+        if connectors["output"]:
+            elements = connectors["output"].GetConnectedBlocks()
+        else:
+            elements = []
+        variable.Clean()
+        self.Blocks.remove(variable)
+        self.Elements.remove(variable)
+        self.Controler.RemoveCurrentElementEditingInstance(variable.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+    def DeleteConnection(self, connection):
+        if connection.GetType() == CONTINUATION:
+            elements = connection.GetConnector().GetConnectedBlocks()
+        else:
+            elements = []
+        connection.Clean()
+        self.Blocks.remove(connection)
+        self.Elements.remove(connection)
+        self.Controler.RemoveCurrentElementEditingInstance(connection.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+    def DeleteComment(self, comment):
+        self.Elements.remove(comment)
+        self.Controler.RemoveCurrentElementEditingInstance(comment.GetId())
+
+    def DeleteWire(self, wire):
+        connected = wire.GetConnected()
+        wire.Clean()
+        self.Wires.remove(wire)
+        self.Elements.remove(wire)
+        for connector in connected:
+            connector.RefreshParentBlock()
+
+    def DeleteContact(self, contact):
+        connectors = contact.GetConnectors()
+        elements = connectors["output"].GetConnectedBlocks()
+        contact.Clean()
+        self.Blocks.remove(contact)
+        self.Elements.remove(contact)
+        self.Controler.RemoveCurrentElementEditingInstance(contact.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+    def DeleteCoil(self, coil):
+        connectors = coil.GetConnectors()
+        elements = connectors["output"].GetConnectedBlocks()
+        coil.Clean()
+        self.Blocks.remove(coil)
+        self.Elements.remove(coil)
+        self.Controler.RemoveCurrentElementEditingInstance(coil.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+    def DeletePowerRail(self, powerrail):
+        elements = []
+        if powerrail.GetType() == LEFTRAIL:
+            for connector in powerrail.GetConnectors():
+                for element in connector.GetConnectedBlocks():
+                    if element not in elements:
+                        elements.append(element)
+        powerrrail.Clean()
+        self.Blocks.remove(powerrrail)
+        self.Elements.remove(powerrrail)
+        self.Controler.RemoveCurrentElementEditingInstance(powerrrail.GetId())
+        for element in elements:
+            element.RefreshModel()
+
+#-------------------------------------------------------------------------------
+#                          Edit element content functions
+#-------------------------------------------------------------------------------
+
+    def EditBlockContent(self, block):
+        dialog = BlockPropertiesDialog(self.Parent)
+        dialog.SetBlockList(self.Controler.GetBlockTypes())
+        dialog.SetMinBlockSize(block.GetSize())
+        values = {"name" : block.GetName(), "type" : block.GetType()}
+        values["extension"] = block.GetExtension()
+        dialog.SetValues(values)
+        if dialog.ShowModal() == wxID_OK:
+            values = dialog.GetValues()
+            if "name" in values:
+                block.SetName(values["name"])
+            block.SetSize(values["width"], values["height"])
+            block.SetType(values["type"], values["extension"])
+            self.RefreshBlockModel(block)
+            self.Refresh()
+        dialog.Destroy()
+
+    def EditVariableContent(self, variable):
+        dialog = VariablePropertiesDialog(self.Parent)
+        dialog.SetMinVariableSize(variable.GetSize())
+        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)
+        values = {"name" : variable.GetName(), "type" : variable.GetType()}
+        dialog.SetValues(values)
+        if dialog.ShowModal() == wxID_OK:
+            old_type = variable.GetType()
+            values = dialog.GetValues()
+            variable.SetName(values["name"])
+            variable.SetType(values["type"], values["value_type"])
+            variable.SetSize(values["width"], values["height"])
+            if old_type != values["type"]:
+                id = variable.GetId()
+                self.Controler.RemoveCurrentElementEditingInstance(id)
+                self.Controler.AddCurrentElementEditingVariable(id, values["type"])
+            self.RefreshVariableModel(variable)
+            self.Refresh()
+        dialog.Destroy()
+
+
 #-------------------------------------------------------------------------------
 #                            Editing functions
 #-------------------------------------------------------------------------------
@@ -781,8 +1314,12 @@
 #                            Drawing functions
 #-------------------------------------------------------------------------------
 
+    def OnMoveWindow(self, event):
+        self.RefreshScrollBar()
+        event.Skip()
+
     def OnPaint(self, event):
-        dc = wxClientDC(self)
+        dc = self.GetLogicalDC()
         dc.Clear()
         dc.SetPen(wxPen(wxColour(230, 230, 230)))
         if self.Scaling and self.DrawGrid:
@@ -799,778 +1336,8 @@
                 element.Draw(dc)
         if self.SelectedElement:
             self.SelectedElement.Draw(dc)
-        event.Skip()
-
-
-#-------------------------------------------------------------------------------
-#                         Textual programs Viewer class
-#-------------------------------------------------------------------------------
-
-
-NEWLINE = "\n"
-NUMBERS = [str(i) for i in xrange(10)]
-LETTERS = ['_']
-for i in xrange(26):
-    LETTERS.append(chr(ord('a') + i))
-    LETTERS.append(chr(ord('A') + i))
-
-[wxSTC_PLC_WORD, wxSTC_PLC_COMMENT, wxSTC_PLC_NUMBER, wxSTC_PLC_VARIABLE, 
- wxSTC_PLC_FUNCTION, wxSTC_PLC_JUMP] = range(6)
-[SPACE, WORD, NUMBER, COMMENT] = range(4)
-
-[wxID_TEXTVIEWER,
-] = [wx.NewId() for _init_ctrls in range(1)]
-
-if wx.Platform == '__WXMSW__':
-    faces = { 'times': 'Times New Roman',
-              'mono' : 'Courier New',
-              'helv' : 'Arial',
-              'other': 'Comic Sans MS',
-              'size' : 10,
-             }
-else:
-    faces = { 'times': 'Times',
-              'mono' : 'Courier',
-              'helv' : 'Helvetica',
-              'other': 'new century schoolbook',
-              'size' : 12,
-             }
-re_texts = {}
-re_texts["letter"] = "[A-Za-z]"
-re_texts["digit"] = "[0-9]"
-re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts
-IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
-LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts)
-
-class TextViewer(wxStyledTextCtrl):
-    
-    def __init__(self, parent, window, controler):
-        wxStyledTextCtrl.__init__(self, parent, wxID_TEXTVIEWER, style=0)
-        
-        self.CmdKeyAssign(ord('+'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMIN)
-        self.CmdKeyAssign(ord('-'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMOUT)
-        
-        self.SetViewWhiteSpace(False)
-        
-        self.SetLexer(wxSTC_LEX_CONTAINER)
-        
-        # Global default styles for all languages
-        self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
-        self.StyleClearAll()  # Reset all to be like the default
-        
-        self.StyleSetSpec(wxSTC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
-        self.SetSelBackground(1, "#E0E0E0")
-        
-        # Highlighting styles
-        self.StyleSetSpec(wxSTC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
-        self.StyleSetSpec(wxSTC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
-        self.StyleSetSpec(wxSTC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
-        self.StyleSetSpec(wxSTC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
-        self.StyleSetSpec(wxSTC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
-        self.StyleSetSpec(wxSTC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
-        
-        # Indicators styles
-        self.IndicatorSetStyle(0, wxSTC_INDIC_SQUIGGLE)
-        self.IndicatorSetForeground(0, wxRED)
-        
-        # Line numbers in the margin
-        self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
-        self.SetMarginWidth(1, 50)
-        
-        # Indentation size
-        self.SetTabWidth(2)
-        self.SetUseTabs(0)
-        
-        self.Keywords = []
-        self.Variables = []
-        self.Functions = []
-        self.Jumps = []
-        self.TextChanged = False
-        self.TextSyntax = "ST"
-        
-        self.Controler = controler
-
-        EVT_KEY_DOWN(self, self.OnKeyDown)
-        EVT_STC_STYLENEEDED(self, wxID_TEXTVIEWER, self.OnStyleNeeded)
-        EVT_KILL_FOCUS(self, self.OnKillFocus)
-    
-    def SetTextSyntax(self, syntax):
-        self.TextSyntax = syntax
-    
-    def SetKeywords(self, keywords):
-        self.Keywords = [keyword.upper() for keyword in keywords]
-        self.Colourise(0, -1)
-    
-    def SetVariables(self, variables):
-        self.Variables = [variable.upper() for variable in variables]
-        self.Colourise(0, -1)
-    
-    def SetFunctions(self, blocktypes):
-        self.Functions = []
-        for category in blocktypes:
-            for blocktype in category["list"]:
-                if blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables:
-                    self.Functions.append(blocktype["name"].upper())
-        self.Colourise(0, -1)
-    
-    def RefreshJumpList(self):
-        self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]
-        self.Colourise(0, -1)
-    
-    def RefreshView(self):
-        self.SetText(self.Controler.GetCurrentElementEditingText())
-        self.RefreshJumpList()
-    
-    def OnStyleNeeded(self, event):
-        self.TextChanged = True
-        line = self.LineFromPosition(self.GetEndStyled())
-        if line == 0:
-            start_pos = 0
-        else:
-            start_pos = self.GetLineEndPosition(line - 1) + 1
-        end_pos = event.GetPosition()
-        self.StartStyling(start_pos, 0xff)
-        
-        i = start_pos
-        state = SPACE
-        line = ""
-        word = ""
-        while i < end_pos:
-            char = chr(self.GetCharAt(i)).upper()
-            line += char
-            if char == NEWLINE:
-                if state == COMMENT:
-                    self.SetStyling(i - start_pos + 1, wxSTC_PLC_COMMENT)
-                elif state == NUMBER:
-                    self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
-                elif state == WORD:
-                    if word in self.Keywords:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
-                    elif word in self.Variables:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
-                    elif word in self.Functions:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
-                    elif word in self.Jumps:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
-                    else:
-                        self.SetStyling(i - start_pos, 31)
-                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
-                            self.StartStyling(start_pos, wxSTC_INDICS_MASK)
-                            self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
-                            self.StartStyling(i, 0xff)    
-                else:
-                    self.SetStyling(i - start_pos, 31)
-                start_pos = i
-                state = SPACE
-                line = ""
-            elif line.endswith("(*") and state != COMMENT:
-                self.SetStyling(i - start_pos - 1, 31)
-                start_pos = i
-                state = COMMENT
-            elif state == COMMENT:
-                if line.endswith("*)"):
-                    self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
-                    start_pos = i + 1
-                    state = SPACE
-            elif char in LETTERS:
-                if state == NUMBER:
-                    word = "#"
-                    state = WORD
-                elif state == SPACE:
-                    self.SetStyling(i - start_pos, 31)
-                    word = char
-                    start_pos = i
-                    state = WORD
-                else:
-                    word += char
-            elif char in NUMBERS or char == '.' and state != WORD:
-                if state == SPACE:
-                    self.SetStyling(i - start_pos, 31)
-                    start_pos = i
-                    state = NUMBER
-                if state == WORD and char != '.':
-                    word += char
-            else:
-                if state == WORD:
-                    if word in self.Keywords:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
-                    elif word in self.Variables:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
-                    elif word in self.Functions:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
-                    elif word in self.Jumps:
-                        self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
-                    else:
-                        self.SetStyling(i - start_pos, 31)
-                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
-                            self.StartStyling(start_pos, wxSTC_INDICS_MASK)
-                            self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
-                            self.StartStyling(i, 0xff)
-                    word = ""
-                    start_pos = i
-                    state = SPACE
-                elif state == NUMBER:
-                    self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
-                    start_pos = i
-                    state = SPACE
-            i += 1
-        if state == COMMENT:
-            self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
-        elif state == NUMBER:
-            self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
-        elif state == WORD:
-            if word in self.Keywords:
-                self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
-            elif word in self.Variables:
-                self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
-            elif word in self.Functions:
-                self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
-            elif word in self.Jumps:
-                self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
-            else:
-                self.SetStyling(i - start_pos, 31)
-        else:
-            self.SetStyling(i - start_pos, 31)
-        event.Skip()
-    
-    def Cut(self):
-        self.CmdKeyExecute(wxSTC_CMD_CUT)
-        
-    def Copy(self):
-        self.CmdKeyExecute(wxSTC_CMD_COPY)
-    
-    def Paste(self):
-        self.CmdKeyExecute(wxSTC_CMD_PASTE)
-    
-    def RefreshModel(self):
-        if self.TextChanged:
-            self.RefreshJumpList()
-            self.Controler.SetCurrentElementEditingText(self.GetText())
-    
-    def OnKeyDown(self, event):
-        if self.CallTipActive():
-            self.CallTipCancel()
-        key = event.KeyCode()
-
-        # Code completion
-        if key == WXK_SPACE and event.ControlDown():
-            
-            line = self.GetCurrentLine()
-            if line == 0:
-                start_pos = 0
-            else:
-                start_pos = self.GetLineEndPosition(line - 1) + 1
-            end_pos = self.GetCurrentPos()
-
-            lineText = self.GetTextRange(start_pos, end_pos).replace("\t", " ")
-            words = lineText.split(" ")
-            words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1]
-                        
-            kw = []
-            
-            if self.TextSyntax == "IL":
-                if len(words) == 1:
-                    kw = self.Keywords
-                elif len(words) == 2:
-                    if words[0].upper() in ["CAL", "CALC", "CALNC"]:
-                        kw = self.Functions
-                    elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]:
-                        kw = self.Jumps
-                    else:
-                        kw = self.Variables
-            else:
-                kw = self.Keywords + self.Variables + self.Functions
-            if len(kw) > 0:
-                kw.sort()
-                self.AutoCompSetIgnoreCase(True)
-                self.AutoCompShow(len(words[-1]), " ".join(kw))
-        else:
-            self.TextChanged = False
-            wxCallAfter(self.RefreshModel)
-            event.Skip()
-
-    def OnKillFocus(self, event):
-        self.AutoCompCancel()
-        event.Skip()
-
-
-#-------------------------------------------------------------------------------
-#                            Resource Editor class
-#-------------------------------------------------------------------------------
-
-class ResourceTable(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
-        
-        self.ColAlignements = []
-        self.ColSizes = []
-        # 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 GetColAlignements(self):
-        return self.ColAlignements
-    
-    def SetColAlignements(self, list):
-        self.ColAlignements = list
-
-    def GetColSizes(self):
-        return self.ColSizes
-    
-    def SetColSizes(self, list):
-        self.ColSizes = list
-
-    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 SetValueByName(self, row, colname, value):
-        if colname in self.colnames:
-            self.data[row][colname] = 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.ColAlignements[col], wxALIGN_CENTRE)
-            grid.SetColAttr(col, attr)
-            grid.SetColSize(col, self.ColSizes[col])
-        
-        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","Interval"]:
-                    editor = wxGridCellTextEditor()
-                    renderer = wxGridCellStringRenderer()
-                    if colname == "Interval" and self.GetValueByName(row, "Single") != "":
-                        grid.SetReadOnly(row, col, True)
-                elif colname == "Single":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.VariableList)
-                    if self.GetValueByName(row, "Interval") != "":
-                        grid.SetReadOnly(row, col, True)
-                elif colname == "Type":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.TypeList)
-                elif colname == "Priority":
-                    editor = wxGridCellNumberEditor()
-                    editor.SetParameters("0,65535")
-                elif colname == "Task":
-                    editor = wxGridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.TaskList)
-                    
-                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_RESOURCEEDITOR, wxID_RESOURCEEDITORSTATICTEXT1,
- wxID_RESOURCEEDITORSTATICTEXT2, wxID_RESOURCEEDITORINSTANCESGRID,
- wxID_RESOURCEEDITORTASKSGRID, wxID_RESOURCEEDITORADDINSTANCEBUTTON,
- wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, wxID_RESOURCEEDITORUPINSTANCEBUTTON,
- wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, wxID_RESOURCEEDITORADDTASKBUTTON,
- wxID_RESOURCEEDITORDELETETASKBUTTON, wxID_RESOURCEEDITORUPTASKBUTTON,
- wxID_RESOURCEEDITORDOWNTASKBUTTON,
-] = [wx.NewId() for _init_ctrls in range(13)]
-
-class ResourceEditor(wx.Panel):
-    
-    def _init_coll_InstancesSizer_Growables(self, parent):
-        # generated method, don't edit
-
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(1)
-
-    def _init_coll_InstancesSizer_Items(self, parent):
-        # generated method, don't edit
-
-        parent.AddSizer(self.InstancesButtonsSizer, 0, border=0, flag=wxGROW)
-        parent.AddWindow(self.InstancesGrid, 0, border=0, flag=wxGROW)
-
-    def _init_coll_InstancesButtonsSizer_Growables(self, parent):
-        # generated method, don't edit
-
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(0)
-
-    def _init_coll_InstancesButtonsSizer_Items(self, parent):
-        # generated method, don't edit
-
-        parent.AddWindow(self.staticText2, 0, border=0, flag=wxALIGN_BOTTOM)
-        parent.AddWindow(self.AddInstanceButton, 0, border=0, flag=0)
-        parent.AddWindow(self.DeleteInstanceButton, 0, border=0, flag=0)
-        parent.AddWindow(self.UpInstanceButton, 0, border=0, flag=0)
-        parent.AddWindow(self.DownInstanceButton, 0, border=0, flag=0)
-
-    def _init_coll_TasksSizer_Growables(self, parent):
-        # generated method, don't edit
-
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(1)
-
-    def _init_coll_TasksSizer_Items(self, parent):
-        # generated method, don't edit
-
-        parent.AddSizer(self.TasksButtonsSizer, 0, border=0, flag=wxGROW)
-        parent.AddWindow(self.TasksGrid, 0, border=0, flag=wxGROW)
-
-    def _init_coll_TasksButtonsSizer_Growables(self, parent):
-        # generated method, don't edit
-
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(0)
-
-    def _init_coll_TasksButtonsSizer_Items(self, parent):
-        # generated method, don't edit
-
-        parent.AddWindow(self.staticText1, 0, border=0, flag=wxALIGN_BOTTOM)
-        parent.AddWindow(self.AddTaskButton, 0, border=0, flag=0)
-        parent.AddWindow(self.DeleteTaskButton, 0, border=0, flag=0)
-        parent.AddWindow(self.UpTaskButton, 0, border=0, flag=0)
-        parent.AddWindow(self.DownTaskButton, 0, border=0, flag=0)
-
-    def _init_coll_MainGridSizer_Items(self, parent):
-        # generated method, don't edit
-
-        parent.AddSizer(self.TasksSizer, 0, border=0, flag=wxGROW)
-        parent.AddSizer(self.InstancesSizer, 0, border=0, flag=wxGROW)
-
-    def _init_coll_MainGridSizer_Growables(self, parent):
-        # generated method, don't edit
-
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(0)
-        parent.AddGrowableRow(1)
-
-    def _init_sizers(self):
-        # generated method, don't edit
-        self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
-
-        self.InstancesSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
-
-        self.InstancesButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
-
-        self.TasksSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
-
-        self.TasksButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
-
-        self._init_coll_MainGridSizer_Growables(self.MainGridSizer)
-        self._init_coll_MainGridSizer_Items(self.MainGridSizer)
-        self._init_coll_InstancesSizer_Growables(self.InstancesSizer)
-        self._init_coll_InstancesSizer_Items(self.InstancesSizer)
-        self._init_coll_InstancesButtonsSizer_Growables(self.InstancesButtonsSizer)
-        self._init_coll_InstancesButtonsSizer_Items(self.InstancesButtonsSizer)
-        self._init_coll_TasksSizer_Growables(self.TasksSizer)
-        self._init_coll_TasksSizer_Items(self.TasksSizer)
-        self._init_coll_TasksButtonsSizer_Growables(self.TasksButtonsSizer)
-        self._init_coll_TasksButtonsSizer_Items(self.TasksButtonsSizer)
-
-        self.SetSizer(self.MainGridSizer)
-
-    def _init_ctrls(self, prnt):
-        # generated method, don't edit
-        wx.Panel.__init__(self, id=wxID_RESOURCEEDITOR, name='', parent=prnt,
-              pos=wx.Point(0, 0), size=wx.Size(-1, -1),
-              style=wx.SUNKEN_BORDER)
-        
-        self.staticText1 = wx.StaticText(id=wxID_RESOURCEEDITORSTATICTEXT1,
-              label=u'Tasks:', name='staticText2', parent=self, pos=wx.Point(0,
-              0), size=wx.Size(60, 17), style=wxALIGN_CENTER)
-
-        self.TasksGrid = wx.grid.Grid(id=wxID_RESOURCEEDITORTASKSGRID,
-              name='TasksGrid', parent=self, pos=wx.Point(0, 0), 
-              size=wx.Size(-1, -1), style=wxVSCROLL)
-        self.TasksGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
-              'Sans'))
-        self.TasksGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
-              False, 'Sans'))
-        EVT_GRID_CELL_CHANGE(self.TasksGrid, self.OnTasksGridCellChange)
-
-        self.AddTaskButton = wx.Button(id=wxID_RESOURCEEDITORADDTASKBUTTON, label='Add Task',
-              name='AddTaskButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(102, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORADDTASKBUTTON, self.OnAddTaskButton)
-
-        self.DeleteTaskButton = wx.Button(id=wxID_RESOURCEEDITORDELETETASKBUTTON, label='Delete Task',
-              name='DeleteTaskButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(102, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORDELETETASKBUTTON, self.OnDeleteTaskButton)
-
-        self.UpTaskButton = wx.Button(id=wxID_RESOURCEEDITORUPTASKBUTTON, label='^',
-              name='UpTaskButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORUPTASKBUTTON, self.OnUpTaskButton)
-
-        self.DownTaskButton = wx.Button(id=wxID_RESOURCEEDITORDOWNTASKBUTTON, label='v',
-              name='DownTaskButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORDOWNTASKBUTTON, self.OnDownTaskButton)
-
-        self.staticText2 = wx.StaticText(id=wxID_RESOURCEEDITORSTATICTEXT2,
-              label=u'Instances:', name='staticText1', parent=self,
-              pos=wx.Point(0, 0), size=wx.Size(85, 17), style=wxALIGN_CENTER)
-
-        self.InstancesGrid = wx.grid.Grid(id=wxID_RESOURCEEDITORINSTANCESGRID,
-              name='InstancesGrid', parent=self, pos=wx.Point(0, 0), 
-              size=wx.Size(-1, -1), style=wxVSCROLL)
-        self.InstancesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
-              'Sans'))
-        self.InstancesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
-              False, 'Sans'))
-        EVT_GRID_CELL_CHANGE(self.InstancesGrid, self.OnInstancesGridCellChange)
-
-        self.AddInstanceButton = wx.Button(id=wxID_RESOURCEEDITORADDINSTANCEBUTTON, label='Add Instance',
-              name='AddInstanceButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(122, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORADDINSTANCEBUTTON, self.OnAddInstanceButton)
-
-        self.DeleteInstanceButton = wx.Button(id=wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, label='Delete Instance',
-              name='DeleteInstanceButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(122, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORDELETEINSTANCEBUTTON, self.OnDeleteInstanceButton)
-
-        self.UpInstanceButton = wx.Button(id=wxID_RESOURCEEDITORUPINSTANCEBUTTON, label='^',
-              name='UpInstanceButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORUPINSTANCEBUTTON, self.OnUpInstanceButton)
-
-        self.DownInstanceButton = wx.Button(id=wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, label='v',
-              name='DownInstanceButton', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(32, 32), style=0)
-        EVT_BUTTON(self, wxID_RESOURCEEDITORDOWNINSTANCEBUTTON, self.OnDownInstanceButton)
-
-        self._init_sizers()
-
-    def __init__(self, parent, window, controler):
-        self._init_ctrls(parent)
-        
-        self.Parent = window
-        self.Controler = controler
-        
-        self.TasksDefaultValue = {"Name" : "", "Single" : "", "Interval" : "", "Priority" : 0}
-        self.TasksTable = ResourceTable(self, [], ["Name", "Single", "Interval", "Priority"])
-        self.TasksTable.SetColAlignements([wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_RIGHT, wxALIGN_RIGHT])
-        self.TasksTable.SetColSizes([200, 100, 100, 100])
-        self.TasksGrid.SetTable(self.TasksTable)
-        self.TasksGrid.SetRowLabelSize(0)
-        self.TasksTable.ResetView(self.TasksGrid)
-
-        self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""}
-        self.InstancesTable = ResourceTable(self, [], ["Name", "Type", "Task"])
-        self.InstancesTable.SetColAlignements([wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT])
-        self.InstancesTable.SetColSizes([200, 150, 150])
-        self.InstancesGrid.SetTable(self.InstancesTable)
-        self.InstancesGrid.SetRowLabelSize(0)
-        self.InstancesTable.ResetView(self.InstancesGrid)
-
-    def SetMode(self, mode):
-        pass
-
-    def RefreshTypeList(self):
-        self.TypeList = ""
-        blocktypes = self.Controler.GetBlockResource()
-        for blocktype in blocktypes:
-            self.TypeList += ",%s"%blocktype
-
-    def RefreshTaskList(self):
-        self.TaskList = ""
-        for row in xrange(self.TasksTable.GetNumberRows()):
-            self.TaskList += ",%s"%self.TasksTable.GetValueByName(row, "Name")
-
-    def RefreshVariableList(self):
-        self.VariableList = ""
-        for variable in self.Controler.GetCurrentResourceEditingVariables():
-            self.VariableList += ",%s"%variable
-        
-    def RefreshModel(self):
-        self.Controler.SetCurrentResourceEditingInfos(self.TasksTable.GetData(), self.InstancesTable.GetData())
-
-    def RefreshView(self):
-        tasks, instances = self.Controler.GetCurrentResourceEditingInfos()
-        self.TasksTable.SetData(tasks)
-        self.InstancesTable.SetData(instances)
-        self.RefreshTypeList()
-        self.RefreshTaskList()
-        self.RefreshVariableList()
-        self.InstancesTable.ResetView(self.InstancesGrid)
-        self.TasksTable.ResetView(self.TasksGrid)
-
-    def OnAddTaskButton(self, event):
-        self.TasksTable.AppendRow(self.TasksDefaultValue.copy())
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnDeleteTaskButton(self, event):
-        row = self.TasksGrid.GetGridCursorRow()
-        self.TasksTable.RemoveRow(row)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnUpTaskButton(self, event):
-        row = self.TasksGrid.GetGridCursorRow()
-        self.TasksTable.MoveRow(row, -1, self.TasksGrid)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnDownTaskButton(self, event):
-        row = self.TasksGrid.GetGridCursorRow()
-        self.TasksTable.MoveRow(row, 1, self.TasksGrid)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnAddInstanceButton(self, event):
-        self.InstancesTable.AppendRow(self.InstancesDefaultValue.copy())
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnDeleteInstanceButton(self, event):
-        row = self.InstancesGrid.GetGridCursorRow()
-        self.InstancesTable.RemoveRow(row)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnUpInstanceButton(self, event):
-        row = self.InstancesGrid.GetGridCursorRow()
-        self.InstancesTable.MoveRow(row, -1, self.InstancesGrid)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnDownInstanceButton(self, event):
-        row = self.InstancesGrid.GetGridCursorRow()
-        self.InstancesTable.MoveRow(row, 1, self.InstancesGrid)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnTasksGridCellChange(self, event):
-        row, col = event.GetRow(), event.GetCol()
-        if self.TasksTable.GetColLabelValue(event.GetCol()) == "Name":
-            tasklist = self.TaskList.split(",")
-            for i in xrange(self.TasksTable.GetNumberRows()):
-                task = self.TasksTable.GetValueByName(i, "Name")
-                if task in tasklist:
-                    tasklist.remove(task)
-            tasklist.remove("")
-            if len(tasklist) > 0:
-                old_name = tasklist[0]
-                new_name = self.TasksTable.GetValue(row, col)
-                for i in xrange(self.InstancesTable.GetNumberRows()):
-                    if self.InstancesTable.GetValueByName(i, "Task") == old_name:
-                        self.InstancesTable.SetValueByName(i, "Task", new_name)
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
-
-    def OnInstancesGridCellChange(self, event):
-        self.RefreshModel()
-        self.RefreshView()
-        event.Skip()
+        if self.rubberBand.IsShown():
+            self.rubberBand.Draw()
+        event.Skip()
+
+
--- a/examples/example.xml	Sat Jul 07 11:35:17 2007 +0200
+++ b/examples/example.xml	Mon Jul 09 11:10:14 2007 +0200
@@ -90,7 +90,7 @@
               <position y="182" x="587"/>
               <connectionPointIn>
                 <relPosition y="16" x="0"/>
-                <connection refLocalId="11">
+                <connection refLocalId="11" formalParameter="Q1">
                   <position y="198" x="587"/>
                   <position y="198" x="517"/>
                 </connection>
@@ -184,7 +184,7 @@
                 <variable formalParameter="S1">
                   <connectionPointIn>
                     <relPosition y="37" x="0"/>
-                    <connection refLocalId="6">
+                    <connection refLocalId="6" formalParameter="OUT">
                       <position y="198" x="420"/>
                       <position y="198" x="369"/>
                       <position y="141" x="369"/>
@@ -195,7 +195,7 @@
                 <variable formalParameter="R">
                   <connectionPointIn>
                     <relPosition y="72" x="0"/>
-                    <connection refLocalId="8">
+                    <connection refLocalId="8" formalParameter="OUT">
                       <position y="233" x="420"/>
                       <position y="233" x="369"/>
                       <position y="282" x="369"/>
--- a/graphics/FBD_Objects.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/graphics/FBD_Objects.py	Mon Jul 09 11:10:14 2007 +0200
@@ -40,15 +40,15 @@
 class FBD_Block(Graphic_Element):
     
     # Create a new block
-    def __init__(self, parent, type, name, id = None, extension = 0, inputs = [], outputs = []):
+    def __init__(self, parent, type, name, id = None, extension = 0):
         Graphic_Element.__init__(self, parent)
         self.Type = None
+        self.Extension = None
         self.Name = name
         self.Id = id
-        self.Extension = extension
         self.Inputs = []
         self.Outputs = []
-        self.SetType(type)
+        self.SetType(type, extension)
     
     # Destructor
     def __del__(self):
@@ -107,7 +107,16 @@
             output.MoveConnected(exclude)
     
     # Returns the block connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test each input and output connector
+            for input in self.Inputs:
+                if name == input.GetName():
+                    return input
+            for output in self.Outputs:
+                if name == output.GetName():
+                    return output
         # Test each input connector
         for input in self.Inputs:
             input_pos = input.GetRelPosition()
@@ -137,9 +146,10 @@
         return None
     
     # Changes the block type
-    def SetType(self, type):
-        if type != self.Type: 
+    def SetType(self, type, extension):
+        if type != self.Type or self.Extension != extension: 
             self.Type = type
+            self.Extension = extension
             # Find the block definition from type given and create the corresponding
             # inputs and outputs
             blocktype = GetBlockType(type)
@@ -150,14 +160,14 @@
                     start = int(inputs[-1][0].replace("IN", ""))
                     for i in xrange(self.Extension - len(blocktype["inputs"])):
                         start += 1
-                        inputs.append(("IN%d"%start, inputs[-1][1], input[-1][2]))
+                        inputs.append(("IN%d"%start, inputs[-1][1], inputs[-1][2]))
             else:
                 raise ValueError, "This block type isn't defined"
             self.Clean()
             # Extract the inputs properties and create the corresponding connector
             self.Inputs = []
             for input_name, input_type, input_modifier in inputs:
-                connector = Connector(self, input_name, input_type, wxPoint(0, 0), WEST)
+                connector = Connector(self, input_name, input_type, wxPoint(0, 0), WEST, onlyone = True)
                 if input_modifier == "negated":
                     connector.SetNegated(True)
                 elif input_modifier != "none":
@@ -228,13 +238,13 @@
             self.RefreshModel(False)
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the block properties
         self.Parent.EditBlockContent(self)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnRightUp(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Popup the menu with special items for a block and a connector if one is handled
         connector = self.TestConnector(pos, False)
         if connector:
@@ -346,7 +356,14 @@
         return None
     
     # Returns the block connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test input and output connector if they exists
+            if self.Input and name == self.Input.GetName():
+                return self.Input
+            if self.Output and name == self.Output.GetName():
+                return self.Output
         # Test input connector if it exists
         if self.Input:
             input_pos = self.Input.GetRelPosition()
@@ -380,7 +397,7 @@
             self.Output = None
             # Create an input or output connector according to variable type
             if self.Type != INPUT:
-                self.Input = Connector(self, "", value_type, wxPoint(0, 0), WEST)
+                self.Input = Connector(self, "", value_type, wxPoint(0, 0), WEST, onlyone = True)
             if self.Type != OUTPUT:
                 self.Output = Connector(self, "", value_type, wxPoint(0, 0), EAST)
             self.RefreshConnectors()
@@ -404,15 +421,15 @@
         return text_width + 10, text_height + 10
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the variable properties
         self.Parent.EditVariableContent(self)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnRightUp(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Popup the menu with special items for a variable and a connector if it's handled
-        connector = self.TestConnectors(pos, False)
+        connector = self.TestConnector(pos, False)
         if connector:
             self.Handle = (HANDLE_CONNECTOR, connector)
             self.Parent.PopupVariableMenu(connector)
@@ -466,7 +483,7 @@
         self.Size = wxSize(0, 0)
         # Create an input or output connector according to connection type
         if self.Type == CONNECTOR:
-            self.Connector = Connector(self, "", "ANY", wxPoint(0, 0), WEST)
+            self.Connector = Connector(self, "", "ANY", wxPoint(0, 0), WEST, onlyone = True)
         else:
             self.Connector = Connector(self, "", "ANY", wxPoint(0, 0), EAST)
         self.RefreshConnectors()
@@ -514,7 +531,7 @@
         return None
     
     # Returns the connection connector
-    def GetConnector(self, position = None):
+    def GetConnector(self, position = None, name = None):
         return self.Connector
     
     # Returns the connection type
@@ -538,7 +555,7 @@
         return text_width + text_height + 20, text_height + 10
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         # Popup the default menu
         self.Parent.PopupDefaultMenu()
     
--- a/graphics/GraphicCommons.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/graphics/GraphicCommons.py	Mon Jul 09 11:10:14 2007 +0200
@@ -55,7 +55,7 @@
 # SFC constants
 SFC_STEP_DEFAULT_SIZE = (40, 30)      # Default size of a SFC step
 SFC_TRANSITION_SIZE = (20, 2)         # Size of a SFC transition
-SFC_DEFAULT_SEQUENCE_INTERVAL = 80    # Default size of the interval between two divergence branches
+SFC_DEFAULT_SEQUENCE_INTERVAL = 40    # Default size of the interval between two divergence branches
 SFC_SIMULTANEOUS_SEQUENCE_EXTRA = 20  # Size of extra lines for simultaneous divergence and convergence
 SFC_JUMP_SIZE = (12, 13)              # Size of a SFC jump to step
 SFC_WIRE_MIN_SIZE = 25                # Size of a wire between two elements
@@ -80,7 +80,12 @@
 
 # Contants for defining which mode is selected for each view 
 [MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, MODE_WIRE,
- MODE_INITIAL_STEP] = range(7)
+ MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP, MODE_TRANSITION,
+ MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION] = range(15)
+
+# Contants for defining which drawing mode is selected for app
+[FREEDRAWING_MODE, DRIVENDRAWING_MODE] = [1, 2]
+
 
 """
 Basic vector operations for calculate wire points
@@ -115,8 +120,8 @@
 Function that calculates the nearest point of the grid defined by scaling for the given point
 """
 
-def GetScaledEventPosition(event, scaling):
-    pos = event.GetPosition()
+def GetScaledEventPosition(event, dc, scaling):
+    pos = event.GetLogicalPosition(dc)
     if scaling:
         pos.x = round(float(pos.x) / float(scaling[0])) * scaling[0]
         pos.y = round(float(pos.y) / float(scaling[1])) * scaling[1]
@@ -166,8 +171,8 @@
         return self.currentBox
     
     # Method called when a new box starts to be edited
-    def OnLeftDown(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnLeftDown(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Save the point for calculate the box position and size
         self.startPoint = pos
         self.currentBox = wxRect(pos.x, pos.y, 0, 0)
@@ -175,8 +180,8 @@
         self.Redraw()
     
     # Method called when dragging with a box edited
-    def OnMotion(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnMotion(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Save the last position and size of the box for erasing it
         self.lastBox = wxRect(self.currentBox.x, self.currentBox.y, self.currentBox.width,
             self.currentBox.height)
@@ -196,7 +201,7 @@
         self.Redraw()
     
     # Method called when dragging is stopped
-    def OnLeftUp(self, event, scaling):
+    def OnLeftUp(self, event, dc, scaling):
         self.drawingSurface.SetCursor(wxNullCursor)
         self.lastBox = self.currentBox
         self.currentBox = None
@@ -204,7 +209,7 @@
 
     # Method that erase the last box and draw the new box
     def Redraw(self):
-        dc = wxClientDC(self.drawingSurface)
+        dc = self.drawingSurface.GetLogicalDC()
         dc.SetPen(wxPen(wxWHITE, 1, wxDOT))
         dc.SetBrush(wxTRANSPARENT_BRUSH)
         dc.SetLogicalFunction(wxXOR)
@@ -217,6 +222,27 @@
             dc.DrawRectangle(self.currentBox.x, self.currentBox.y, self.currentBox.width,
                 self.currentBox.height)
 
+    # Erase last box
+    def Erase(self):
+        dc = self.drawingSurface.GetLogicalDC()
+        dc.SetPen(wxPen(wxWHITE, 1, wxDOT))
+        dc.SetBrush(wxTRANSPARENT_BRUSH)
+        dc.SetLogicalFunction(wxXOR)
+        if self.lastBox:
+            dc.DrawRectangle(self.lastBox.x, self.lastBox.y, self.lastBox.width,
+                self.lastBox.height)
+        
+    # Draw current box
+    def Draw(self):
+        dc = self.drawingSurface.GetLogicalDC()
+        dc.SetPen(wxPen(wxWHITE, 1, wxDOT))
+        dc.SetBrush(wxTRANSPARENT_BRUSH)
+        dc.SetLogicalFunction(wxXOR)
+        if self.currentBox:
+            # Draw current box
+            dc.DrawRectangle(self.currentBox.x, self.currentBox.y, self.currentBox.width,
+                self.currentBox.height)
+
 
 #-------------------------------------------------------------------------------
 #                           Graphic element base class
@@ -335,8 +361,8 @@
         return 0, 0
     
     # Method called when a LeftDown event have been generated
-    def OnLeftDown(self, event, scaling):
-        pos = event.GetPosition()
+    def OnLeftDown(self, event, dc, scaling):
+        pos = event.GetLogicalPosition(dc)
         # Test if an handle have been clicked
         result = self.TestHandle(pos)
         # Find which type of handle have been clicked,
@@ -359,14 +385,14 @@
             self.Parent.SetCursor(wxStockCursor(wxCURSOR_HAND))
             self.SetSelected(False)
         # Initializes the last position
-        self.oldPos = GetScaledEventPosition(event, scaling)
+        self.oldPos = GetScaledEventPosition(event, dc, scaling)
     
     # Method called when a LeftUp event have been generated
-    def OnLeftUp(self, event, scaling):
+    def OnLeftUp(self, event, dc, scaling):
         # If a dragging have been initiated
         if self.Dragging and self.oldPos:
             # Calculate the movement of cursor and refreshes the element state
-            pos = GetScaledEventPosition(event, scaling)
+            pos = GetScaledEventPosition(event, dc, scaling)
             movex = pos.x - self.oldPos.x
             movey = pos.y - self.oldPos.y
             self.ProcessDragging(movex, movey)
@@ -375,20 +401,20 @@
         self.oldPos = None
 
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         self.SetSelected(True)
         self.oldPos = None
 
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         pass
     
     # Method called when a Motion event have been generated
-    def OnMotion(self, event, scaling):
+    def OnMotion(self, event, dc, scaling):
         # If the cursor is dragging and the element have been clicked
         if event.Dragging() and self.oldPos:
             # Calculate the movement of cursor
-            pos = GetScaledEventPosition(event, scaling)
+            pos = GetScaledEventPosition(event, dc, scaling)
             movex = pos.x - self.oldPos.x
             movey = pos.y - self.oldPos.y
             # If movement is greater than MIN_MOVE then a dragging is initiated
@@ -400,7 +426,7 @@
                 self.ProcessDragging(movex, movey)
         # If cursor just pass over the element, changes the cursor if it is on a handle
         else:
-            pos = event.GetPosition()
+            pos = event.GetLogicalPosition(dc)
             handle = self.TestHandle(pos)
             if handle == (1, 1) or handle == (3, 3):
                 wxCallAfter(self.Parent.SetCursor, wxStockCursor(wxCURSOR_SIZENWSE))
@@ -614,7 +640,7 @@
 class Connector:
     
     # Create a new connector
-    def __init__(self, parent, name, type, position, direction, negated = False, edge = "none"):
+    def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False):
         self.ParentBlock = parent
         self.Name = name
         self.Type = type
@@ -623,6 +649,7 @@
         self.Wires = []
         self.Negated = negated
         self.Edge = edge
+        self.OneConnected = onlyone
         self.Pen = wxBLACK_PEN
     
     # Change the connector pen
@@ -758,6 +785,22 @@
     def RefreshParentBlock(self):
         self.ParentBlock.RefreshModel(False)
     
+    # Returns all the blocks connected to this connector
+    def GetConnectedBlocks(self):
+        blocks = []
+        for wire, handle in self.Wires:
+            # Get other connector connected to each wire
+            if handle == 0:
+                connector = blocks.GetEndConnected()
+            else:
+                connector = blocks.GetStartConnected()
+            # Get parent block for this connector
+            if connector:
+                block = connector.GetParentBlock()
+                if block not in blocks:
+                    blocks.append(block)
+        return blocks
+    
     # Returns the connector negated property
     def IsNegated(self):
         return self.Negated
@@ -779,7 +822,7 @@
     # Tests if the point given is near from the end point of this connector
     def TestPoint(self, pt, exclude = True):
         parent_pos = self.ParentBlock.GetPosition()
-        if not (len(self.Wires) > 0 and self.Direction == WEST and exclude):
+        if not (len(self.Wires) > 0 and self.OneConnected and exclude):
             # Calculate a square around the end point of this connector
             x = parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE - ANCHOR_DISTANCE
             y = parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE - ANCHOR_DISTANCE
@@ -872,6 +915,14 @@
     def SetSize(width, height):
         pass
     
+    # Returns connector to which start point is connected
+    def GetStartConnected(self):
+        return self.StartConnected
+    
+    # Returns connector to which end point is connected
+    def GetEndConnected(self):
+        return self.EndConnected
+    
     # Unconnect the start and end points
     def Clean(self):
         if self.StartConnected:
@@ -1084,11 +1135,11 @@
         return connected
     
     # Returns the id of the block connected to the first or the last wire point
-    def GetConnectedId(self, index):
+    def GetConnectedInfos(self, index):
         if index == 0 and self.StartConnected:
-            return self.StartConnected.GetBlockId()
+            return self.StartConnected.GetBlockId(), self.StartConnected.GetName()
         elif index == -1 and self.EndConnected:
-            return self.EndConnected.GetBlockId()
+            return self.EndConnected.GetBlockId(), self.StartConnected.GetName()
         return None
     
     # Update the wire points position by keeping at most possible the current positions
@@ -1423,8 +1474,8 @@
             self.RefreshModel()
             
     # Method called when a LeftDown event have been generated
-    def OnLeftDown(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnLeftDown(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Test if a point have been handled
         #result = self.TestPoint(pos)
         #if result != None:
@@ -1441,12 +1492,12 @@
             self.Handle = (HANDLE_SEGMENT, result)
         # Execute the default method for a graphic element
         else:
-            Graphic_Element.OnLeftDown(self, event, scaling)
+            Graphic_Element.OnLeftDown(self, event, dc, scaling)
         self.oldPos = pos
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnRightUp(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Test if a segment has been handled
         result = self.TestSegment(pos)
         if result != None:
@@ -1455,16 +1506,16 @@
             self.Parent.PopupWireMenu()
         else:
             # Execute the default method for a graphic element
-            Graphic_Element.OnRightUp(self, event, scaling)
+            Graphic_Element.OnRightUp(self, event, dc, scaling)
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         self.ResetPoints()
         self.GeneratePoints()
         
     # Method called when a Motion event have been generated
-    def OnMotion(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnMotion(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         if not event.Dragging():
             # Test if a segment has been handled
             result = self.TestSegment(pos)
@@ -1485,10 +1536,10 @@
                 #    self.OverStart = False
                 #    self.OverEnd = False
                 # Execute the default method for a graphic element
-                Graphic_Element.OnMotion(self, event, scaling)
+                Graphic_Element.OnMotion(self, event, dc, scaling)
         else:
             # Execute the default method for a graphic element
-            Graphic_Element.OnMotion(self, event, scaling)
+            Graphic_Element.OnMotion(self, event, dc, scaling)
     
     # Refreshes the wire state according to move defined and handle selected
     def ProcessDragging(self, movex, movey):
@@ -1648,7 +1699,7 @@
         self.SetSize(width, height)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         # Popup the default menu
         self.Parent.PopupDefaultMenu()
     
@@ -1657,7 +1708,7 @@
         self.Parent.RefreshCommentModel(self)
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the comment content
         self.Parent.EditCommentContent(self)
     
--- a/graphics/LD_Objects.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/graphics/LD_Objects.py	Mon Jul 09 11:10:14 2007 +0200
@@ -43,6 +43,9 @@
         Graphic_Element.__init__(self, parent)
         self.Type = type
         self.Id = id
+        self.Extensions = [LD_LINE_SIZE / 2, LD_LINE_SIZE / 2]
+        if len(connectors) < 1:
+            connectors = [True]
         # Create a connector or a blank according to 'connectors' and add it in
         # the connectors list
         self.Connectors = []
@@ -56,10 +59,14 @@
     
     # Forbids to change the power rail size
     def SetSize(self, width, height):
-        pass
+        if isinstance(self.Parent, wxPanel) or self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.SetSize(self, width, height)
+            self.RefreshConnectors()
     
     # Forbids to select a power rail
     def HitTest(self, pt):
+        if isinstance(self.Parent, wxPanel) or self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            return Graphic_Element.HitTest(self, pt) or self.TestConnector(pt, False) != None
         return False
     
     # Deletes this power rail by calling the appropriate method
@@ -75,17 +82,17 @@
     # Refresh the power rail bounding box
     def RefreshBoundingBox(self):
         dc = wxClientDC(self.Parent)
-        if self.Type == LEFTRAIL:
-            bbx_x = self.Pos.x
-        elif self.Type == RIGHTRAIL:
-            bbx_x = self.Pos.x - CONNECTOR_SIZE
-        self.BoundingBox = wxRect(bbx_x, self.Pos.y, self.Size[0] + CONNECTOR_SIZE + 1, self.Size[1] + 1)
+        self.BoundingBox = wxRect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1] + 1)
     
     # Refresh the power rail size
     def RefreshSize(self):
         self.Size = wxSize(2, LD_LINE_SIZE * len(self.Connectors))
         self.RefreshBoundingBox()
     
+    # Returns the block minimum size
+    def GetMinSize(self):
+        return 2, LD_LINE_SIZE * len(self.Connectors)
+    
     # Add a connector or a blank to this power rail at the last place
     def AddConnector(self, connector = True):
         self.InsertConnector(len(self.Connectors), connector)
@@ -103,6 +110,26 @@
         self.RefreshSize()
         self.RefreshConnectors()
     
+    # Moves the divergence connector given
+    def MoveConnector(self, connector, movey):
+        position = connector.GetRelPosition()
+        connector.SetPosition(wxPoint(position.x, position.y + movey))
+        miny = self.Size[1]
+        maxy = 0
+        for connect in self.Connectors:
+            connect_pos = connect.GetRelPosition()
+            miny = min(miny, connect_pos.y)
+            maxy = max(maxy, connect_pos.y)
+        min_pos = self.Pos.y + miny - self.Extensions[0]
+        self.Pos.y = min(min_pos, self.Pos.y)
+        if min_pos == self.Pos.y:
+            for connect in self.Connectors:
+                connect_pos = connect.GetRelPosition()
+                connect.SetPosition(wxPoint(connect_pos.x, connect_pos.y - miny + self.Extensions[0]))
+        self.Size[1] = max(maxy - miny + self.Extensions[0] + self.Extensions[1], self.Size[1])
+        connector.MoveConnected()
+        self.RefreshBoundingBox()
+    
     # Returns the index in connectors list for the connector given
     def GetConnectorIndex(self, connector):
         if connector in self.Connectors:
@@ -123,7 +150,7 @@
     
     # Refresh the positions of the power rail connectors
     def RefreshConnectors(self):
-        position = LD_LINE_SIZE / 2
+        position = self.Extensions[0]
         for connector in self.Connectors:
             if connector:
                 if self.Type == LEFTRAIL:
@@ -140,7 +167,13 @@
                 connector.MoveConnected(exclude)
     
     # Returns the power rail connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test each connector if it exists
+            for connector in self.Connectors:
+                if connector and name == connector.GetName():
+                    return connector
         for connector in self.Connectors:
             if connector:
                 connector_pos = connector.GetRelPosition()
@@ -163,6 +196,63 @@
     def GetType(self):
         return self.Type
     
+    # Method called when a LeftDown event have been generated
+    def OnLeftDown(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
+        # Test if a connector have been handled
+        connector = self.TestConnector(pos, False)
+        if connector:
+            self.Handle = (HANDLE_CONNECTOR, connector)
+            self.Parent.SetCursor(wxStockCursor(wxCURSOR_HAND))
+            self.Selected = False
+            # Initializes the last position
+            self.oldPos = GetScaledEventPosition(event, dc, scaling)
+        else:
+            self.RealConnectors = {"Inputs":[],"Outputs":[]}
+            for input in self.Inputs:
+                position = input.GetRelPosition()
+                self.RealConnectors["Inputs"].append(float(position.x)/float(self.Size[0]))
+            for output in self.Outputs:
+                position = output.GetRelPosition()
+                self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0]))
+            Graphic_Element.OnLeftDown(self, event, dc, scaling)
+    
+    # Method called when a LeftUp event have been generated
+    def OnLeftUp(self, event, dc, scaling):
+        self.RealConnectors = None
+        handle_type, handle = self.Handle
+        if handle_type == HANDLE_CONNECTOR:
+            wires = handle.GetWires()
+            if len(wires) != 1:
+                return
+            if handle == wires[0][0].StartConnected:
+                block = wires[0][0].EndConnected.GetParentBlock()
+            else:
+                block = wires[0][0].StartConnected.GetParentBlock()
+            block.RefreshModel(False)
+        Graphic_Element.OnLeftUp(self, event, dc, scaling)
+    
+    # Method called when a RightUp event have been generated
+    def OnRightUp(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
+        # Popup the menu with special items for a block and a connector if one is handled
+        connector = self.TestConnector(pos, False)
+        if connector:
+            self.Handle = (HANDLE_CONNECTOR, connector)
+        #    self.Parent.PopupDivergenceMenu(True)
+        #else:
+            # Popup the divergence menu without delete branch
+        #    self.Parent.PopupDivergenceMenu(False)
+    
+    # Refreshes the divergence state according to move defined and handle selected
+    def ProcessDragging(self, movex, movey):
+        handle_type, handle = self.Handle
+        # A connector has been handled
+        if handle_type == HANDLE_CONNECTOR:
+            self.MoveConnector(handle, movey)
+        else:
+            Graphic_Element.ProcessDragging(self, movex, movey)
+    
     # Refreshes the power rail model
     def RefreshModel(self, move=True):
         self.Parent.RefreshPowerRailModel(self)
@@ -214,7 +304,9 @@
     
     # Forbids to change the contact size
     def SetSize(self, width, height):
-        pass
+        if isinstance(self.Parent, wxPanel) or self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.SetSize(self, width, height)
+            self.RefreshConnectors()
     
     # Delete this contact by calling the appropriate method
     def Delete(self):
@@ -243,13 +335,24 @@
             bbx_height = self.Size[1]
         self.BoundingBox = wxRect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
     
+    # Returns the block minimum size
+    def GetMinSize(self):
+        return LD_ELEMENT_SIZE
+    
     # Refresh the position of wire connected to contact
     def RefreshConnected(self, exclude = []):
         self.Input.MoveConnected(exclude)
         self.Output.MoveConnected(exclude)
     
     # Returns the contact connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test input and output connector
+            if name == self.Input.GetName():
+                return self.Input
+            if name == self.Output.GetName():
+                return self.Output
         # Test input connector
         input_pos = self.Input.GetRelPosition()
         if position.x == self.Pos.x + input_pos.x and position.y == self.Pos.y + input_pos.y:
@@ -274,6 +377,12 @@
             return self.Output
         return None
 
+    # Refresh the positions of the block connectors
+    def RefreshConnectors(self):
+        self.Input.SetPosition(wxPoint(0, self.Size[1] / 2 + 1))
+        self.Output.SetPosition(wxPoint(self.Size[0], self.Size[1] / 2 + 1))
+        self.RefreshConnected()
+
     # Changes the contact name
     def SetName(self, name):
         self.Name = name
@@ -291,7 +400,7 @@
         return self.Type
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the contact properties
         self.Parent.EditContactContent(self)
     
@@ -359,7 +468,9 @@
     
     # Forbids to change the contact size
     def SetSize(self, width, height):
-        pass
+        if isinstance(self.Parent, wxPanel) or self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.SetSize(self, width, height)
+            self.RefreshConnectors()
     
     # Delete this coil by calling the appropriate method
     def Delete(self):
@@ -387,6 +498,10 @@
             bbx_y = self.Pos.y
             bbx_height = self.Size[1]
         self.BoundingBox = wxRect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
+        
+    # Returns the block minimum size
+    def GetMinSize(self):
+        return LD_ELEMENT_SIZE
     
     # Refresh the position of wire connected to coil
     def RefreshConnected(self, exclude = []):
@@ -394,7 +509,14 @@
         self.Output.MoveConnected(exclude)
     
     # Returns the coil connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test input and output connector
+            if self.Input and name == self.Input.GetName():
+                return self.Input
+            if self.Output and name == self.Output.GetName():
+                return self.Output
         # Test input connector
         input_pos = self.Input.GetRelPosition()
         if position.x == self.Pos.x + input_pos.x and position.y == self.Pos.y + input_pos.y:
@@ -419,6 +541,12 @@
             return self.Output
         return None
     
+    # Refresh the positions of the block connectors
+    def RefreshConnectors(self):
+        self.Input.SetPosition(wxPoint(0, self.Size[1] / 2 + 1))
+        self.Output.SetPosition(wxPoint(self.Size[0], self.Size[1] / 2 + 1))
+        self.RefreshConnected()
+    
     # Changes the coil name
     def SetName(self, name):
         self.Name = name
@@ -436,7 +564,7 @@
         return self.Type
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the coil properties
         self.Parent.EditCoilContent(self)
     
--- a/graphics/SFC_Objects.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/graphics/SFC_Objects.py	Mon Jul 09 11:10:14 2007 +0200
@@ -148,7 +148,16 @@
             self.Action.MoveConnected(exclude)
     
     # Returns the step connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test input, output and action connector if they exists
+            if self.Input and name == self.Input.GetName():
+                return self.Input
+            if self.Output and name == self.Output.GetName():
+                return self.Output
+            if self.Action and name == self.Action.GetName():
+                return self.Action
         # Test input connector if it exists
         if self.Input:
             input_pos = self.Input.GetRelPosition()
@@ -312,7 +321,10 @@
     
     # Resize the divergence from position and size given
     def Resize(self, x, y, width, height):
-        self.UpdateSize(width, height)
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            self.UpdateSize(width, height)
+        else:
+            Graphic_Element.Resize(self, x, y, width, height)
     
     # Method called when a LeftDClick event have been generated
     def OnLeftDClick(self, event, scaling):
@@ -320,7 +332,7 @@
         self.Parent.EditStepContent(self)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         # Popup the menu with special items for a step
         self.Parent.PopupDefaultMenu()
     
@@ -329,7 +341,10 @@
         handle_type, handle = self.Handle
         if handle_type == HANDLE_MOVE:
             action_block = None
-            if self.Initial:
+            if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+                self.Move(movex, movey)
+                self.RefreshConnected()
+            elif self.Initial:
                 self.MoveActionBlock((movex, movey))
                 self.Move(movex, movey, self.Parent.Wires)
                 self.RefreshOutputPosition((movex, movey))
@@ -371,8 +386,11 @@
                 action_block.RefreshModel(False)
         # If step has moved, refresh the model of wires connected to output
         if move:
-            self.RefreshInputModel()
-            self.RefreshOutputModel(self.Initial)
+            if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+                self.RefreshInputModel()
+                self.RefreshOutputModel(self.Initial)
+            elif self.Output:
+                self.Output.RefreshWires()
     
     # Draws step
     def Draw(self, dc):
@@ -423,11 +441,13 @@
     
     # Forbids to change the transition size
     def SetSize(self, width, height):
-        pass
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.SetSize(self, width, height)
     
     # Forbids to resize the transition
     def Resize(self, x, y, width, height):
-        pass
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.Resize(self, x, y, width, height)
     
     # Delete this transition by calling the appropriate method
     def Delete(self):
@@ -479,7 +499,14 @@
         self.Output.MoveConnected(exclude)
     
     # Returns the transition connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test input and output connector
+            if name == self.Input.GetName():
+                return self.Input
+            if name == self.Output.GetName():
+                return self.Output
         # Test input connector
         input_pos = self.Input.GetRelPosition()
         if position.x == self.Pos.x + input_pos.x and position.y == self.Pos.y + input_pos.y:
@@ -568,31 +595,35 @@
                 output_block.MoveActionBlock((diffx, 0))
             output_block.Move(diffx, 0)
             output_block.RefreshOutputPosition()
-    
+
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the transition properties
         self.Parent.EditTransitionContent(self)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         # Popup the menu with special items for a step
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the transition state according to move defined and handle selected
     def ProcessDragging(self, movex, movey):
-        self.Move(movex, 0)
-        self.RefreshInputPosition()
-        self.RefreshOutputPosition()
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            self.Move(movex, 0)
+            self.RefreshInputPosition()
+            self.RefreshOutputPosition()
+        else:
+            Graphic_Element.ProcessDragging(self, movex, movey)
     
     # Refresh input element model
     def RefreshInputModel(self):
-        input = self.GetPreviousConnector()
-        if input:
-            input_block = input.GetParentBlock()
-            input_block.RefreshModel(False)
-            if not isinstance(input_block, SFC_Divergence):
-                input_block.RefreshInputModel()
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            input = self.GetPreviousConnector()
+            if input:
+                input_block = input.GetParentBlock()
+                input_block.RefreshModel(False)
+                if not isinstance(input_block, SFC_Divergence):
+                    input_block.RefreshInputModel()
     
     # Refresh output element model
     def RefreshOutputModel(self, move=False):
@@ -608,8 +639,11 @@
         self.Parent.RefreshTransitionModel(self)
         # If transition has moved, refresh the model of wires connected to output
         if move:
-            self.RefreshInputModel()
-            self.RefreshOutputModel()
+            if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+                self.RefreshInputModel()
+                self.RefreshOutputModel()
+            else:
+                self.Output.RefreshWires()
     
     # Draws transition
     def Draw(self, dc):
@@ -672,7 +706,8 @@
     
     # Forbids to resize the divergence
     def Resize(self, x, y, width, height):
-        pass
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.Resize(self, x, y, width, height)
     
     # Delete this divergence by calling the appropriate method
     def Delete(self):
@@ -774,7 +809,16 @@
         self.RefreshBoundingBox()
     
     # Returns the divergence connector that starts with the point given if it exists 
-    def GetConnector(self, position):
+    def GetConnector(self, position, name = None):
+        # if a name is given
+        if name:
+            # Test each input and output connector
+            for input in self.Inputs:
+                if name == input.GetName():
+                    return input
+            for output in self.Outputs:
+                if name == output.GetName():
+                    return output
         # Test input connector
         for input in self.Inputs:
             input_pos = input.GetPosition(False)
@@ -808,23 +852,27 @@
         for i, input in enumerate(self.Inputs):
             position = input.GetRelPosition()
             if self.RealConnectors:
-                input.SetPosition(wxPoint(int(round(self.RealConnectors["Inputs"][i] * width)), position.y))
+                input.SetPosition(wxPoint(int(round(self.RealConnectors["Inputs"][i] * width)), 0))
             else:
-                input.SetPosition(wxPoint(int(round(float(position.x)*float(width)/float(self.Size[0]))), position.y))
+                input.SetPosition(wxPoint(int(round(float(position.x)*float(width)/float(self.Size[0]))), 0))
             input.MoveConnected()
         for i, output in enumerate(self.Outputs):
             position = output.GetRelPosition()
             if self.RealConnectors:
-                output.SetPosition(wxPoint(int(round(self.RealConnectors["Outputs"][i] * width)), position.y))
+                output.SetPosition(wxPoint(int(round(self.RealConnectors["Outputs"][i] * width)), self.Size[1]))
             else:
-                output.SetPosition(wxPoint(int(round(float(position.x)*float(width)/float(self.Size[0]))), position.y))
+                output.SetPosition(wxPoint(int(round(float(position.x)*float(width)/float(self.Size[0]))), self.Size[1]))
             output.MoveConnected()
-        self.Size = wxSize(width, self.Size[1])
+        self.Size = wxSize(width, height)
         self.RefreshBoundingBox()
     
     # Returns the divergence minimum size
     def GetMinSize(self):
-        return 0, self.Size[1]
+        if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
+            return 0, 1
+        elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
+            return 0, 3
+        return 0, 0
     
     # Refresh the position of the block connected to connector
     def RefreshConnectedPosition(self, connector):
@@ -847,7 +895,7 @@
                 next_block.RefreshInputPosition()
             else:
                 next_block.RefreshOutputPosition()
-    
+
     # Refresh the position of this divergence
     def RefreshPosition(self):
         y = 0
@@ -885,8 +933,8 @@
                     output_block.RefreshOutputPosition(move)
     
     # Method called when a LeftDown event have been generated
-    def OnLeftDown(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnLeftDown(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Test if a connector have been handled
         connector = self.TestConnector(pos, False)
         if connector:
@@ -894,7 +942,7 @@
             self.Parent.SetCursor(wxStockCursor(wxCURSOR_HAND))
             self.Selected = False
             # Initializes the last position
-            self.oldPos = GetScaledEventPosition(event, scaling)
+            self.oldPos = GetScaledEventPosition(event, dc, scaling)
         else:
             self.RealConnectors = {"Inputs":[],"Outputs":[]}
             for input in self.Inputs:
@@ -903,10 +951,10 @@
             for output in self.Outputs:
                 position = output.GetRelPosition()
                 self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0]))
-            Graphic_Element.OnLeftDown(self, event, scaling)
+            Graphic_Element.OnLeftDown(self, event, dc, scaling)
     
     # Method called when a LeftUp event have been generated
-    def OnLeftUp(self, event, scaling):
+    def OnLeftUp(self, event, dc, scaling):
         self.RealConnectors = None
         handle_type, handle = self.Handle
         if handle_type == HANDLE_CONNECTOR:
@@ -923,11 +971,11 @@
                     block.RefreshInputModel()
                 else:
                     block.RefreshOutputModel()
-        Graphic_Element.OnLeftUp(self, event, scaling)
+        Graphic_Element.OnLeftUp(self, event, dc, scaling)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
-        pos = GetScaledEventPosition(event, scaling)
+    def OnRightUp(self, event, dc, scaling):
+        pos = GetScaledEventPosition(event, dc, scaling)
         # Popup the menu with special items for a block and a connector if one is handled
         connector = self.TestConnector(pos, False)
         if connector:
@@ -943,11 +991,14 @@
         # A connector has been handled
         if handle_type == HANDLE_CONNECTOR:
             self.MoveConnector(handle, movex)
-            self.RefreshConnectedPosition(handle)
+            if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+                self.RefreshConnectedPosition(handle)
+        elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.ProcessDragging(self, movex, movey)
     
     # Refresh output element model
     def RefreshOutputModel(self, move=False):
-        if move:
+        if move and self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
             for output in self.Outputs:
                 wires = output.GetWires()
                 if len(wires) != 1:
@@ -962,7 +1013,11 @@
         self.Parent.RefreshDivergenceModel(self)
         # If divergence has moved, refresh the model of wires connected to outputs
         if move:
-            self.RefreshOutputModel()
+            if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+                self.RefreshOutputModel()
+            else:
+                for output in self.Outputs:
+                    output.RefreshWires()
     
     # Draws divergence
     def Draw(self, dc):
@@ -974,8 +1029,8 @@
         elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
             dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, 
                         self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y)
-            dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + 3, 
-                        self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y + 3)
+            dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + self.Size[1], 
+                        self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y + self.Size[1])
         # Draw inputs and outputs connectors
         for input in self.Inputs:
             input.Draw(dc)
@@ -1004,15 +1059,17 @@
         
     # Destructor
     def __del__(self):
-        self.Inputs = None
+        self.Input = None
     
     # Forbids to change the jump size
     def SetSize(self, width, height):
-        pass
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.SetSize(self, width, height)
     
     # Forbids to resize jump
     def Resize(self, x, y, width, height):
-        pass
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            Graphic_Element.Resize(self, x, y, width, height)
     
     # Delete this jump by calling the appropriate method
     def Delete(self):
@@ -1020,8 +1077,7 @@
     
     # Unconnect input
     def Clean(self):
-        if self.Input:
-            self.Input.UnConnect()
+        self.Input.UnConnect()
     
     # Refresh the jump bounding box
     def RefreshBoundingBox(self):
@@ -1034,19 +1090,23 @@
     
     # Returns the connector connected to input
     def GetPreviousConnector(self):
-        if self.Input:
-            wires = self.Input.GetWires()
-            if len(wires) == 1:
-                return wires[0][0].EndConnected
+        wires = self.Input.GetWires()
+        if len(wires) == 1:
+            return wires[0][0].EndConnected
         return None
     
+    # Refresh the element connectors position
+    def RefreshConnectors(self):
+        self.Input.SetPosition(wxPoint(self.Size[0] / 2, 0))
+        self.RefreshConnected()
+    
     # Refresh the position of wires connected to jump
     def RefreshConnected(self, exclude = []):
         if self.Input:
             self.Input.MoveConnected(exclude)
     
     # Returns input jump connector 
-    def GetConnector(self, position = None):
+    def GetConnector(self, position = None, name = None):
         return self.Input
     
     # Test if point given is on jump input connector
@@ -1091,28 +1151,32 @@
         pass
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the jump properties
         self.Parent.EditJumpContent(self)
     
     # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, scaling):
+    def OnRightUp(self, event, dc, scaling):
         # Popup the default menu
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the jump state according to move defined and handle selected
     def ProcessDragging(self, movex, movey):
-        self.Move(movex, 0)
-        self.RefreshInputPosition()
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            self.Move(movex, 0)
+            self.RefreshInputPosition()
+        else:
+            Graphic_Element.ProcessDragging(self, movex, movey)
     
     # Refresh input element model
     def RefreshInputModel(self):
-        input = self.GetPreviousConnector()
-        if input:
-            input_block = input.GetParentBlock()
-            input_block.RefreshModel(False)
-            if not isinstance(input_block, SFC_Divergence):
-                input_block.RefreshInputModel()
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            input = self.GetPreviousConnector()
+            if input:
+                input_block = input.GetParentBlock()
+                input_block.RefreshModel(False)
+                if not isinstance(input_block, SFC_Divergence):
+                    input_block.RefreshInputModel()
     
     # Refresh output element model
     def RefreshOutputModel(self, move=False):
@@ -1122,7 +1186,8 @@
     def RefreshModel(self, move=True):
         self.Parent.RefreshJumpModel(self)
         if move:
-            self.RefreshInputModel()
+            if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+                self.RefreshInputModel()
     
     # Draws divergence
     def Draw(self, dc):
@@ -1171,10 +1236,19 @@
     def GetLineNumber(self):
         return len(self.Actions)
     
+    def GetLineSize(self):
+        if len(self.Actions) > 1:
+            return self.Size[1] / len(self.Actions)
+        else:
+            return SFC_ACTION_MIN_SIZE[1]
+    
     # Forbids to resize the action block
     def Resize(self, x, y, width, height):
-        if x == 0:
-            self.SetSize(width, self.Size[1])
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            if x == 0:
+                self.SetSize(width, self.Size[1])
+        else:
+            Graphic_Element.Resize(self, x, y, width, height)
     
     # Delete this action block by calling the appropriate method
     def Delete(self):
@@ -1193,7 +1267,7 @@
         self.Input.MoveConnected(exclude)
     
     # Returns input action block connector 
-    def GetConnector(self, position = None):
+    def GetConnector(self, position = None, name = None):
         return self.Input
     
     # Test if point given is on action block input connector
@@ -1219,8 +1293,12 @@
             if "indicator" in action and action["indicator"] != "":
                 width, height = dc.GetTextExtent(action["indicator"])
                 self.ColSize[2] = max(self.ColSize[2], width + 10)
-        self.Size = wxSize(max(self.ColSize[0] + self.ColSize[1] + self.ColSize[2],
-            SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1])
+        if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
+            line_size = self.GetLineSize()
+            self.Size = wxSize(self.ColSize[0] + self.ColSize[1] + self.ColSize[2], len(self.Actions) * line_size)
+        else:
+            self.Size = wxSize(max(self.ColSize[0] + self.ColSize[1] + self.ColSize[2],
+                SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1])
         self.RefreshBoundingBox()
         if self.Input:
             wires = self.Input.GetWires()
@@ -1239,21 +1317,25 @@
             SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1]
     
     # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, scaling):
+    def OnLeftDClick(self, event, dc, scaling):
         # Edit the action block properties
         self.Parent.EditActionBlockContent(self)
     
     # Refreshes the action block state according to move defined and handle selected
     def ProcessDragging(self, movex, movey):
-        handle_type, handle = self.Handle
-        if handle_type == HANDLE_MOVE:
-            wires = self.Input.GetWires()
-            if len(wires) == 1:
-                input_pos = wires[0][0].EndConnected.GetPosition(False)
-                if self.Pos.x - input_pos.x + movex >= SFC_WIRE_MIN_SIZE:
-                    self.Move(movex, 0)
+        if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
+            handle_type, handle = self.Handle
+            if handle_type == HANDLE_MOVE:
+                wires = self.Input.GetWires()
+                if len(wires) == 1:
+                    input_pos = wires[0][0].EndConnected.GetPosition(False)
+                    if self.Pos.x - input_pos.x + movex >= SFC_WIRE_MIN_SIZE:
+                        self.Move(movex, 0)
+            else:
+                Graphic_Element.ProcessDragging(self, movex, movey)
         else:
             Graphic_Element.ProcessDragging(self, movex, movey)
+
     
    # Refreshes the action block model
     def RefreshModel(self, move=True):
@@ -1270,27 +1352,29 @@
                 self.Pos.x + colsize[0], self.Pos.y + self.Size[1])
         dc.DrawLine(self.Pos.x + colsize[0] + colsize[1], self.Pos.y, 
                 self.Pos.x + colsize[0] + colsize[1], self.Pos.y + self.Size[1])
+        line_size = self.GetLineSize()
         for i, action in enumerate(self.Actions):
             if i != 0:
-                dc.DrawLine(self.Pos.x, self.Pos.y + i * SFC_ACTION_MIN_SIZE[1], 
-                    self.Pos.x + self.Size[0], self.Pos.y + i * SFC_ACTION_MIN_SIZE[1])
+                dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size, 
+                    self.Pos.x + self.Size[0], self.Pos.y + i * line_size)
             text_width, text_height = dc.GetTextExtent(action["qualifier"])
             if "duration" in action:
                 dc.DrawText(action["qualifier"], self.Pos.x + (colsize[0] - text_width) / 2,
-                    self.Pos.y + i * SFC_ACTION_MIN_SIZE[1] + SFC_ACTION_MIN_SIZE[1] / 2 - text_height)
+                    self.Pos.y + i * line_size + line_size / 2 - text_height)
                 text_width, text_height = dc.GetTextExtent(action["duration"])
                 dc.DrawText(action["duration"], self.Pos.x + (colsize[0] - text_width) / 2,
-                    self.Pos.y + i * SFC_ACTION_MIN_SIZE[1] + SFC_ACTION_MIN_SIZE[1] / 2)
+                    self.Pos.y + i * line_size + line_size / 2)
             else:
                 dc.DrawText(action["qualifier"], self.Pos.x + (colsize[0] - text_width) / 2,
-                        self.Pos.y + i * SFC_ACTION_MIN_SIZE[1] + (SFC_ACTION_MIN_SIZE[1] - text_height) / 2)
+                        self.Pos.y + i * line_size + (line_size - text_height) / 2)
             text_width, text_height = dc.GetTextExtent(action["value"])
             dc.DrawText(action["value"], self.Pos.x + colsize[0] + (colsize[1] - text_width) / 2,
-                    self.Pos.y + i * SFC_ACTION_MIN_SIZE[1] + (SFC_ACTION_MIN_SIZE[1] - text_height) / 2)
+                    self.Pos.y + i * line_size + (line_size - text_height) / 2)
             if "indicator" in action:
                 text_width, text_height = dc.GetTextExtent(action["indicator"])
                 dc.DrawText(action["indicator"], self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - text_width) / 2,
-                        self.Pos.y + i * SFC_ACTION_MIN_SIZE[1] + (SFC_ACTION_MIN_SIZE[1] - text_height) / 2)
+                        self.Pos.y + i * line_size + (line_size - text_height) / 2)
         # Draw input connector
         self.Input.Draw(dc)
         Graphic_Element.Draw(self, dc)
+
--- a/plcopen/TC6_XML_V10_B.xsd	Sat Jul 07 11:35:17 2007 +0200
+++ b/plcopen/TC6_XML_V10_B.xsd	Mon Jul 09 11:10:14 2007 +0200
@@ -571,7 +571,7 @@
 			<xsd:element name="DATE"/>
 			<xsd:element name="DT"/>
 			<xsd:element name="TOD"/>
-			<xsd:element name="string">
+			<xsd:element name="STRING">
 				<xsd:complexType>
 					<xsd:annotation>
 						<xsd:documentation>The single byte character string type</xsd:documentation>
@@ -579,7 +579,7 @@
 					<xsd:attribute name="length" type="xsd:unsignedLong" use="optional"/>
 				</xsd:complexType>
 			</xsd:element>
-			<xsd:element name="wstring">
+			<xsd:element name="WSTRING">
 				<xsd:complexType>
 					<xsd:annotation>
 						<xsd:documentation>The wide character (WORD) string type</xsd:documentation>
--- a/plcopen/plcopen.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/plcopen/plcopen.py	Mon Jul 09 11:10:14 2007 +0200
@@ -966,6 +966,17 @@
         return None
     setattr(cls, "getConnectionPoints", getConnectionPoints)
 
+    def setConnectionParameter(self, idx, parameter):
+        if self.content:
+            self.content["value"][idx].setFormalParameter(parameter)
+    setattr(cls, "setConnectionParameter", setConnectionParameter)
+    
+    def getConnectionParameter(self, idx):
+        if self.content:
+            return self.content["value"][idx].getFormalParameter()
+        return None
+    setattr(cls, "getConnectionParameter", getConnectionParameter)
+
 if "connectionPointOut" in PLCOpenClasses:
     cls = PLCOpenClasses["connectionPointOut"]
 
--- a/plcopen/structures.py	Sat Jul 07 11:35:17 2007 +0200
+++ b/plcopen/structures.py	Mon Jul 09 11:10:14 2007 +0200
@@ -159,8 +159,7 @@
     ("ANY_INT", "ANY_NUM"),
     ("ANY_SINT", "ANY_INT"),
     ("ANY_UINT", "ANY_INT"),
-    ("REAL", "ANY_REAL"),
-    ("LREAL", "ANY_REAL"),
+	("BOOL", "ANY_BIT"),
     ("SINT", "ANY_SINT"),
     ("INT", "ANY_SINT"),
     ("DINT", "ANY_SINT"),
@@ -169,17 +168,19 @@
     ("UINT", "ANY_UINT"),
     ("UDINT", "ANY_UINT"),
     ("ULINT", "ANY_UINT"),
+    ("REAL", "ANY_REAL"),
+    ("LREAL", "ANY_REAL"),
     ("TIME", "ANY_MAGNITUDE"),
-    ("BOOL", "ANY_BIT"),
+    ("DATE", "ANY_DATE"),
+    ("TOD", "ANY_DATE"),
+    ("DT", "ANY_DATE"),
+    ("STRING", "ANY_STRING"),
     ("BYTE", "ANY_NBIT"),
     ("WORD", "ANY_NBIT"),
     ("DWORD", "ANY_NBIT"),
-    ("LWORD", "ANY_NBIT"),
-    ("STRING", "ANY_STRING"),
-    #("WSTRING", "ANY_STRING"), # TODO
-    ("DATE", "ANY_DATE"),
-    ("TOD", "ANY_DATE"),
-    ("DT", "ANY_DATE")]
+    ("LWORD", "ANY_NBIT")
+    #("WSTRING", "ANY_STRING") # TODO
+]
 
 TypeHierarchy = dict(TypeHierarchy_list)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test.xml	Mon Jul 09 11:10:14 2007 +0200
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://www.plcopen.org/xml/tc6.xsd"
+         xmlns:xhtml="http://www.w3.org/1999/xhtml"
+         xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd http://www.plcopen.org/xml/tc6.xsd">
+  <fileHeader contentDescription=""
+              companyName="test"
+              companyURL=""
+              productName="test"
+              productRelease=""
+              productVersion="test"
+              creationDateTime="2007-07-09 08:54:39"/>
+  <contentHeader name="test">
+    <coordinateInfo>
+      <fbd>
+        <scaling y="0" x="0"/>
+      </fbd>
+      <ld>
+        <scaling y="0" x="0"/>
+      </ld>
+      <sfc>
+        <scaling y="0" x="0"/>
+      </sfc>
+    </coordinateInfo>
+  </contentHeader>
+  <types>
+    <dataTypes/>
+    <pous/>
+  </types>
+  <instances>
+    <configurations/>
+  </instances>
+</project>