Adding support for allowing declarations of function block into POU interface
authorlbessard
Fri, 10 Aug 2007 16:14:33 +0200
changeset 68 66308e07402c
parent 67 3a1b0afdaf84
child 69 8fbff50141f8
Adding support for allowing declarations of function block into POU interface
PLCControler.py
PLCGenerator.py
PLCOpenEditor.py
TextViewer.py
examples/example.xml
plcopen/plcopen.py
--- a/PLCControler.py	Thu Aug 09 18:07:44 2007 +0200
+++ b/PLCControler.py	Fri Aug 10 16:14:33 2007 +0200
@@ -269,23 +269,6 @@
                 pou_type = pou.getPouType().getValue()
                 pou_infos = {"name": pou.getName(), "type": ITEM_POU}
                 pou_values = []
-##                var_types = {"Input": {"name": "Input", "type": ITEM_CLASS, "values": []},
-##                         "Output": {"name": "Output", "type": ITEM_CLASS, "values": []},
-##                         "InOut": {"name": "InOut", "type": ITEM_CLASS, "values": []},
-##                         "External": {"name": "External", "type": ITEM_CLASS, "values": []},
-##                         "Local": {"name": "Local", "type": ITEM_CLASS, "values": []},
-##                         "Temp": {"name": "Temp", "type": ITEM_CLASS, "values": []},
-##                         "Global": {"name": "Global", "type": ITEM_CLASS, "values": []}}
-##                for var in self.GetPouInterfaceVars(pou):
-##                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
-##                    if var["Class"] in var_types.keys():
-##                        var_types[var["Class"]]["values"].append(var_values)
-##                pou_values.append({"name": "Interface", "type": ITEM_CLASS, 
-##                    "values": [var_types["Input"], var_types["Output"], var_types["InOut"], var_types["External"]]})
-##                pou_values.append({"name": "Variables", "type": ITEM_CLASS, 
-##                    "values": [var_types["Local"], var_types["Temp"]]})
-##                if pou_type == "program":
-##                    pou_values.append(var_types["Global"])
                 if pou.getBodyType() == "SFC":
                     transitions = []
                     for transition in pou.getTransitionList():
@@ -302,21 +285,11 @@
             for config in self.Project.getConfigurations():
                 config_name = config.getName()
                 config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []}
-##                config_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
-##                for var in self.GetConfigurationGlobalVars(config_name):
-##                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
-##                    config_vars["values"].append(var_values)
                 resources = {"name": "Resources", "type": ITEM_UNEDITABLE, "values": []}
                 for resource in config.getResource():
                     resource_name = resource.getName()
                     resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []}
-##                    resource_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
-##                    for var in self.GetConfigurationResourceGlobalVars(config_name, resource_name):
-##                        var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
-##                        resource_vars["values"].append(var_values)
-##                    resource_infos["values"].append(resource_vars)
                     resources["values"].append(resource_infos)
-##                config_infos["values"] = [config_vars, resources]
                 config_infos["values"] = [resources]
                 configurations["values"].append(config_infos)
             infos["values"] = [{"name": "Properties", "type": ITEM_UNEDITABLE, "values": []},
@@ -672,6 +645,7 @@
                         tempvar["Type"] = var_type
                     else:
                         tempvar["Type"] = var_type.getName()
+                    tempvar["Edit"] = True
                     initial = var.getInitialValue()
                     if initial:
                         tempvar["Initial Value"] = initial.getValue()
@@ -719,6 +693,7 @@
                         tempvar["Type"] = var_type
                     else:
                         tempvar["Type"] = var_type.getName()
+                    tempvar["Edit"] = True
                     initial = var.getInitialValue()
                     if initial:
                         tempvar["Initial Value"] = initial.getValue()
@@ -757,8 +732,10 @@
                     var_type = var.getType().getValue()
                     if isinstance(var_type, (StringType, UnicodeType)):
                         tempvar["Type"] = var_type
+                        tempvar["Edit"] = True
                     else:
                         tempvar["Type"] = var_type.getName()
+                        tempvar["Edit"] = not pou.hasBlock(tempvar["Name"])
                     initial = var.getInitialValue()
                     if initial:
                         tempvar["Initial Value"] = initial.getValue()
@@ -896,6 +873,34 @@
             return blocktypes
         return []
 
+    # Return Function Block types checking for recursion
+    def GetFunctionBlockTypes(self):
+        if self.CurrentElementEditing != None:
+            if self.Project:
+                current_name = self.ElementsOpened[self.CurrentElementEditing]
+                words = current_name.split("::")
+                if len(words) == 1:
+                    name = current_name
+                else:
+                    name = words[1]
+                type = self.GetPouType(name)
+            else:
+                name = ""
+                type = None
+            blocktypes = []
+            for category in BlockTypes[:-1]:
+                if category["name"] != "SVGUI function blocks":
+                    for block in category["list"]:
+                        if block["type"] != "function":
+                            blocktypes.append(block["name"])
+            if self.Project:
+                for blocktype in BlockTypes[-1]["list"]:
+                    if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] != "function"):
+                        blocktypes.append(blocktype["name"])
+            return blocktypes
+        return []
+
+
     # Return Block types checking for recursion
     def GetBlockResource(self):
         blocktypes = []
--- a/PLCGenerator.py	Thu Aug 09 18:07:44 2007 +0200
+++ b/PLCGenerator.py	Fri Aug 10 16:14:33 2007 +0200
@@ -61,6 +61,7 @@
         self.ReturnType = None
         self.Interface = []
         self.InitialSteps = []
+        self.BlockComputed = {}
         self.SFCNetworks = {"Steps":{}, "Transitions":{}, "Actions":{}}
         self.ActionNumber = 0
         self.Program = ""
@@ -84,15 +85,15 @@
             located = False
             for var in varlist["value"].getVariable():
                 type = var.getType().getValue()
+                if not isinstance(type, (StringType, UnicodeType)):
+                    type = type.getName()
                 initial = var.getInitialValue()
                 if initial:
                     initial_value = initial.getValue()
                 else:
                     initial_value = None
                 address = var.getAddress()
-                if address == "":
-                    address = None
-                else:
+                if address:
                     located = True
                 variables.append((type, var.getName(), address, initial_value))
             self.Interface.append((varTypeNames[varlist["name"]], varlist["value"].getRetain(), 
@@ -159,10 +160,7 @@
                 variable = instance.outputVariables.getVariable()[0]
                 return self.ExtractModifier(variable, "%s(%s)"%(type, ", ".join(vars)))
             elif block_infos["type"] == "functionBlock":
-                if self.Interface[-1][0] != "VAR" or self.Interface[-1][1] or self.Interface[-1][2] or self.Interface[-1][3]:
-                    self.Interface.append(("VAR", False, False, False, []))
-                if not self.IsAlreadyDefined(name):
-                    self.Interface[-1][4].append((type, name, None, None))
+                if not self.BlockComputed.get(name, False):
                     vars = []
                     for variable in instance.inputVariables.getVariable():
                         connections = variable.connectionPointIn.getConnections()
@@ -171,6 +169,7 @@
                             value = self.ComputeFBDExpression(body, connections[0])
                             vars.append(self.ExtractModifier(variable, "%s := %s"%(parameter, value)))
                     self.Program += "  %s(%s);\n"%(name, ", ".join(vars))
+                    self.BlockComputed[name] = True
                 connectionPoint = link.getPosition()[-1]
                 for variable in instance.outputVariables.getVariable():
                     blockPointx, blockPointy = variable.connectionPointOut.getRelPosition()
--- a/PLCOpenEditor.py	Thu Aug 09 18:07:44 2007 +0200
+++ b/PLCOpenEditor.py	Fri Aug 10 16:14:33 2007 +0200
@@ -301,13 +301,9 @@
             self.FileMenu = wx.Menu(title=u'')
         else:
             self.FileMenu = None
-
         self.EditMenu = wx.Menu(title=u'')
-
         self.HelpMenu = wx.Menu(title='')
-
         self.SFCMenu = wx.Menu(title='')
-
         self.ConfigMenu = wx.Menu(title='')
 
         self._init_coll_menuBar1_Menus(self.menuBar1)
@@ -912,156 +908,6 @@
         data = self.ProjectTree.GetPyData(selected)
         if name == "Properties":
             self.ShowProperties()
-##        elif data == ITEM_CLASS:
-##            item = self.ProjectTree.GetItemParent(selected)
-##            item_type = self.ProjectTree.GetPyData(item)
-##            while item_type not in [ITEM_POU, ITEM_RESOURCE, ITEM_CONFIGURATION] and item.IsOk():
-##                item = self.ProjectTree.GetItemParent(item)
-##                item_type = self.ProjectTree.GetPyData(item)
-##            item_name = self.ProjectTree.GetItemText(item)
-##            if item_type == ITEM_POU:
-##                dialog = EditVariableDialog(self, item_name, self.Controler.GetPouType(item_name), self.Controler.PouIsUsed(item_name), name)
-##                dialog.SetPouNames(self.Controler.GetProjectPouNames())
-##                values = {}
-##                values["returnType"] = self.Controler.GetPouInterfaceReturnTypeByName(item_name)
-##                values["data"] = self.Controler.GetPouInterfaceVarsByName(item_name)
-##                dialog.SetValues(values)
-##                if dialog.ShowModal() == wx.ID_OK:
-##                    new_values = dialog.GetValues()
-##                    if "returnType" in new_values:
-##                        self.Controler.SetPouInterfaceReturnType(item_name, new_values["returnType"])
-##                    self.Controler.SetPouInterfaceVars(item_name, new_values["data"])
-##                    pou_names = self.Controler.GetElementsOpenedNames()
-##                    if item_name in pou_names:
-##                        window = self.TabsOpened.GetPage(pou_names.index(item_name))
-##                        if isinstance(window, TextViewer):
-##                            varlist = []
-##                            if "returnType" in new_values:
-##                                varlist.append(name)
-##                            for var in new_values["data"]:
-##                                varlist.append(var["Name"])
-##                            window.SetVariables(varlist)
-##                dialog.Destroy()
-##                self.RefreshProjectTree()
-##            elif item_type == ITEM_CONFIGURATION:
-##                dialog = EditVariableDialog(self, item_name, None, False, name)
-##                dialog.SetPouNames(self.Controler.GetProjectPouNames())
-##                values = {"data" : self.Controler.GetConfigurationGlobalVars(item_name)}
-##                dialog.SetValues(values)
-##                if dialog.ShowModal() == wx.ID_OK:
-##                    new_values = dialog.GetValues()
-##                    self.Controler.SetConfigurationGlobalVars(item_name, new_values["data"])
-##                dialog.Destroy()
-##                self.RefreshProjectTree()
-##            elif item_type == ITEM_RESOURCE:
-##                config = self.ProjectTree.GetItemParent(item)
-##                config_type = self.ProjectTree.GetPyData(config)
-##                while config_type != ITEM_CONFIGURATION and config.IsOk():
-##                    config = self.ProjectTree.GetItemParent(config)
-##                    config_type = self.ProjectTree.GetPyData(config)
-##                if config.IsOk():
-##                    config_name = self.ProjectTree.GetItemText(config)
-##                    dialog = EditVariableDialog(self, item_name, None, False, name)
-##                    values = {"data" : self.Controler.GetConfigurationResourceGlobalVars(config_name, item_name)}
-##                    dialog.SetValues(values)
-##                    if dialog.ShowModal() == wx.ID_OK:
-##                        new_values = dialog.GetValues()
-##                        self.Controler.SetConfigurationResourceGlobalVars(config_name, item_name, new_values["data"])
-##                    dialog.Destroy()
-##                    self.RefreshProjectTree()
-##        elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
-##            if data == ITEM_POU:
-##                idx = self.Controler.OpenElementEditing(name)
-##                language = self.Controler.GetPouBodyType(name)
-##                varlist = []
-##                returnType = self.Controler.GetPouInterfaceReturnTypeByName(name)
-##                if returnType:
-##                    varlist.append(name)
-##                vars = self.Controler.GetPouInterfaceVarsByName(name)
-##                if vars:
-##                    for var in vars:
-##                        varlist.append(var["Name"])
-##                self.EditVariable.SetPou(self.Controler.GetPouType(name), self.Controler.PouIsUsed(name))
-##                self.EditVariable.SetValues({"returnType":returnType,"data":vars})
-##            else:
-##                parent = self.ProjectTree.GetItemParent(selected)
-##                parent_name = self.ProjectTree.GetItemText(parent)
-##                grandparent = self.ProjectTree.GetItemParent(parent)
-##                grandparent_name = self.ProjectTree.GetItemText(grandparent)
-##                if data == ITEM_TRANSITION:
-##                    idx = self.Controler.OpenPouTransitionEditing(grandparent_name, name)
-##                    language = self.Controler.GetTransitionBodyType(grandparent_name, name)
-##                elif data == ITEM_ACTION:
-##                    idx = self.Controler.OpenPouActionEditing(grandparent_name, name)
-##                    language = self.Controler.GetActionBodyType(grandparent_name, name)
-##                varlist = [name]
-##                vars = self.Controler.GetPouInterfaceVarsByName(grandparent_name)
-##                if vars:
-##                    for var in vars:
-##                        varlist.append(var["Name"])
-##                self.EditVariable.SetPou(self.Controler.GetPouType(grandparent_name), self.Controler.PouIsUsed(grandparent_name))
-##                self.EditVariable.SetValues({"returnType":returnType,"data":vars})
-##            if idx != None:
-##                if language == "FBD":
-##                    new_window = Viewer(self.TabsOpened, self, self.Controler)
-##                elif language == "LD":
-##                    new_window = LD_Viewer(self.TabsOpened, self, self.Controler)
-##                elif language == "SFC":
-##                    new_window = SFC_Viewer(self.TabsOpened, self, self.Controler)
-##                elif language in ["IL", "ST"]:
-##                    new_window = TextViewer(self.TabsOpened, self, self.Controler)
-##                    new_window.SetTextSyntax(language)
-##                    if language == "IL":
-##                        new_window.SetKeywords(IL_KEYWORDS)
-##                    else:
-##                        new_window.SetKeywords(ST_KEYWORDS)
-##                    new_window.SetVariables(varlist)
-##                    new_window.SetFunctions(self.Controler.GetBlockTypes())
-##                else:
-##                    return
-##                new_window.RefreshView()
-##                self.TabsOpened.AddPage(new_window, "")
-##                self.TabsOpened.SetSelection(idx)
-##                self.RefreshTabsOpenedTitles()
-##                self.RefreshFileMenu()
-##                self.RefreshEditMenu()
-##                self.RefreshToolBar()
-##            else:
-##                if data == ITEM_POU:
-##                    idx = self.Controler.ChangeElementEditing(name)
-##                elif data == ITEM_TRANSITION:
-##                    idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name)
-##                elif data == ITEM_ACTION:
-##                    idx = self.Controler.ChangePouActionEditing(grandparent_name, name)
-##                if idx != None:
-##                    self.TabsOpened.SetSelection(idx)
-##                    self.RefreshFileMenu()
-##                    self.RefreshEditMenu()
-##                    self.RefreshToolBar()
-##        elif data == ITEM_RESOURCE:
-##            item = self.ProjectTree.GetItemParent(selected)
-##            item_type = self.ProjectTree.GetPyData(item)
-##            while item_type != ITEM_CONFIGURATION:
-##                item = self.ProjectTree.GetItemParent(item)
-##                item_type = self.ProjectTree.GetPyData(item)
-##            config_name = self.ProjectTree.GetItemText(item)
-##            idx = self.Controler.OpenConfigurationResourceEditing(config_name, name)
-##            if idx != None:
-##                new_window = ResourceEditor(self.TabsOpened, self, self.Controler)
-##                new_window.RefreshView()
-##                self.TabsOpened.AddPage(new_window, "")
-##                self.TabsOpened.SetSelection(idx)
-##                self.RefreshTabsOpenedTitles()
-##                self.RefreshFileMenu()
-##                self.RefreshEditMenu()
-##                self.RefreshToolBar()
-##            else:
-##                idx = self.Controler.ChangeConfigurationResourceEditing(parent_name, name)
-##                if idx != None:
-##                    self.TabsOpened.SetSelection(idx)
-##                    self.RefreshFileMenu()
-##                    self.RefreshEditMenu()
-##                    self.RefreshToolBar()
         elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE, ITEM_CONFIGURATION]:
             if data == ITEM_CONFIGURATION:
                 idx = self.Controler.OpenConfigurationEditing(name)
@@ -1968,7 +1814,7 @@
         return values
 
 #-------------------------------------------------------------------------------
-#                            Pou Interface Dialog
+#                            Pou Editor Panel
 #-------------------------------------------------------------------------------
 
 class VariableTable(wx.grid.PyGridTableBase):
@@ -2009,9 +1855,6 @@
             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):
             colname = self.GetColLabelValue(col)
@@ -2019,6 +1862,14 @@
                 self.old_value = self.data[row][colname]
             self.data[row][colname] = value
     
+    def GetValueByName(self, row, colname):
+        if row < self.GetNumberRows():
+            return self.data[row].get(colname)
+
+    def SetValueByName(self, row, colname, value):
+        if row < self.GetNumberRows():
+            self.data[row][colname] = value
+
     def GetOldValue(self):
         return self.old_value
     
@@ -2077,37 +1928,34 @@
                 editor = None
                 renderer = None
                 colname = self.GetColLabelValue(col)
-                grid.SetReadOnly(row, col, False)
-                if col == 0:
-                    grid.SetReadOnly(row, col, True)
-                elif colname == "Name":
-                    if self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
-                        grid.SetReadOnly(row, col, True)
-                    else:
+                if col != 0 and self.GetValueByName(row, "Edit"):
+                    grid.SetReadOnly(row, col, False)
+                    if colname == "Name":
+                        if self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
+                            grid.SetReadOnly(row, col, True)
+                        else:
+                            editor = wx.grid.GridCellTextEditor()
+                            renderer = wx.grid.GridCellStringRenderer()
+                    elif colname in ["Initial Value","Location"]:
                         editor = wx.grid.GridCellTextEditor()
                         renderer = wx.grid.GridCellStringRenderer()
-                elif colname in ["Initial Value","Location"]:
-                    editor = wx.grid.GridCellTextEditor()
-                    renderer = wx.grid.GridCellStringRenderer()
-                elif colname == "Class":
-                    if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
-                        grid.SetReadOnly(row, col, True)
-                    else:
+                    elif colname == "Class":
+                        if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
+                            grid.SetReadOnly(row, col, True)
+                        else:
+                            editor = wx.grid.GridCellChoiceEditor()
+                            excluded = []
+                            if self.Parent.PouIsUsed:
+                                excluded.extend(["Input","Output","InOut"])    
+                            editor.SetParameters(",".join([choice for choice in self.Parent.ClassList if choice not in excluded]))
+                    elif colname in ["Retain", "Constant"]:
                         editor = wx.grid.GridCellChoiceEditor()
-                        excluded = []
-                        if self.Parent.PouIsUsed:
-                            excluded.extend(["Input","Output","InOut"])    
-                        editor.SetParameters(",".join([choice for choice in self.Parent.ClassList if choice not in excluded]))
-                elif colname == "Type":
-                    if self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
-                        grid.SetReadOnly(row, col, True)
-                    else:
-                        editor = wx.grid.GridCellChoiceEditor()
-                        editor.SetParameters(self.Parent.TypeList)
-                elif colname in ["Retain", "Constant"]:
-                    editor = wx.grid.GridCellChoiceEditor()
-                    editor.SetParameters(self.Parent.OptionList)
-                    
+                        editor.SetParameters(self.Parent.OptionList)
+                    elif colname == "Type":
+                        editor = wx.grid.GridCellTextEditor()
+                else:
+                    grid.SetReadOnly(row, col, True)
+                
                 grid.SetCellEditor(row, col, editor)
                 grid.SetCellRenderer(row, col, renderer)
                 
@@ -2177,15 +2025,7 @@
  ID_POUEDITORPANELSTATICTEXT2, ID_POUEDITORPANELSTATICTEXT3,
 ] = [wx.NewId() for _init_ctrls in range(12)]
 
-class PouEditorPanel(wx.Panel):
-    def _init_coll_MainPanelSizer_Items(self, parent):
-        parent.AddWindow(self.Viewer, 0, border=0, flag=wx.GROW)
-        parent.AddSizer(self.VariablePanelSizer, 0, border=0, flag=wx.GROW)
-
-    def _init_coll_MainPanelSizer_Growables(self, parent):
-        parent.AddGrowableCol(0)
-        parent.AddGrowableRow(0)
-    
+class PouEditorPanel(wx.SplitterWindow):
     def _init_coll_VariablePanelSizer_Items(self, parent):
         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
         parent.AddSizer(self.ControlPanelSizer, 0, border=0, flag=wx.GROW)
@@ -2223,14 +2063,11 @@
         parent.AddGrowableRow(0)
 
     def _init_sizers(self):
-        self.MainPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
         self.VariablePanelSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=0)
         self.ControlPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
         self.ChoicePanelSizer = wx.GridSizer(cols=1, hgap=5, rows=4, vgap=5)
         self.ButtonPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0)
         
-        self._init_coll_MainPanelSizer_Items(self.MainPanelSizer)
-        self._init_coll_MainPanelSizer_Growables(self.MainPanelSizer)
         self._init_coll_VariablePanelSizer_Items(self.VariablePanelSizer)
         self._init_coll_VariablePanelSizer_Growables(self.VariablePanelSizer)
         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
@@ -2239,16 +2076,18 @@
         self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
         self._init_coll_ButtonPanelSizer_Growables(self.ButtonPanelSizer)
         
-        self.SetSizer(self.MainPanelSizer)
+        self.VariablePanel.SetSizer(self.VariablePanelSizer)
 
     def _init_ctrls(self, prnt, element_type):
-        wx.Panel.__init__(self, id=ID_POUEDITORPANEL,
+        wx.SplitterWindow.__init__(self, id=ID_POUEDITORPANEL,
               name='EditVariablePanel', parent=prnt, pos=wx.Point(0, 0),
-              size=wx.Size(-1, -1), style=0)
+              size=wx.Size(-1, -1), style=wx.SP_3D)
+        self.SetNeedUpdating(True)
+        self.SetMinimumPaneSize(1)
         
         if element_type == "config":
             self.Viewer = wx.Panel(id=ID_POUEDITORPANELVIEWER,
-              name='ConfigPanel', parent=self, pos=wx.Point(0, 0),
+              name='ConfigPanel', parent=self.splitterWindow1, pos=wx.Point(0, 0),
               size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
             self.Viewer.ResetBuffer = lambda: None
             self.Viewer.RefreshView = lambda: None
@@ -2268,25 +2107,29 @@
             else:
                 self.Viewer.SetKeywords(ST_KEYWORDS)
         
+        self.VariablePanel = wx.Panel(id=ID_POUEDITORPANELVIEWER,
+              name='VariablePanel', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
+        
         self.staticText1 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT1,
-              label='Return Type:', name='staticText1', parent=self,
+              label='Return Type:', name='staticText1', parent=self.VariablePanel,
               pos=wx.Point(0, 0), size=wx.Size(95, 17), style=0)
 
         self.ReturnType = wx.Choice(id=ID_POUEDITORPANELRETURNTYPE,
-              name='ReturnType', parent=self, pos=wx.Point(0, 0),
+              name='ReturnType', parent=self.VariablePanel, pos=wx.Point(0, 0),
               size=wx.Size(145, 24), style=0)
 
         self.staticText2 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT2,
-              label='Class Filter:', name='staticText2', parent=self,
+              label='Class Filter:', name='staticText2', parent=self.VariablePanel,
               pos=wx.Point(0, 0), size=wx.Size(95, 17), style=0)
 
         self.ClassFilter = wx.Choice(id=ID_POUEDITORPANELCLASSFILTER,
-              name='ClassFilter', parent=self, pos=wx.Point(0, 0),
+              name='ClassFilter', parent=self.VariablePanel, pos=wx.Point(0, 0),
               size=wx.Size(145, 24), style=0)
         self.Bind(wx.EVT_CHOICE, self.OnClassFilter, id=ID_POUEDITORPANELCLASSFILTER)
 
         self.VariablesGrid = wx.grid.Grid(id=ID_POUEDITORPANELVARIABLESGRID,
-              name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
+              name='VariablesGrid', parent=self.VariablePanel, pos=wx.Point(0, 0), 
               size=wx.Size(0, 150), style=wx.VSCROLL)
         self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
               'Sans'))
@@ -2295,29 +2138,31 @@
         self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
         self.VariablesGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnVariablesGridSelectCell)
         self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
-        
+        self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
         self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
         
         self.AddButton = wx.Button(id=ID_POUEDITORPANELADDBUTTON, label='Add',
-              name='AddButton', parent=self, pos=wx.Point(345, 340),
+              name='AddButton', parent=self.VariablePanel, pos=wx.Point(345, 340),
               size=wx.Size(72, 32), style=0)
         self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_POUEDITORPANELADDBUTTON)
 
         self.DeleteButton = wx.Button(id=ID_POUEDITORPANELDELETEBUTTON, label='Delete',
-              name='DeleteButton', parent=self, pos=wx.Point(425, 340),
+              name='DeleteButton', parent=self.VariablePanel, pos=wx.Point(425, 340),
               size=wx.Size(72, 32), style=0)
         self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_POUEDITORPANELDELETEBUTTON)
 
         self.UpButton = wx.Button(id=ID_POUEDITORPANELUPBUTTON, label='^',
-              name='UpButton', parent=self, pos=wx.Point(505, 340),
+              name='UpButton', parent=self.VariablePanel, pos=wx.Point(505, 340),
               size=wx.Size(32, 32), style=0)
         self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_POUEDITORPANELUPBUTTON)
 
         self.DownButton = wx.Button(id=ID_POUEDITORPANELDOWNBUTTON, label='v',
-              name='DownButton', parent=self, pos=wx.Point(545, 340),
+              name='DownButton', parent=self.VariablePanel, pos=wx.Point(545, 340),
               size=wx.Size(32, 32), style=0)
         self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_POUEDITORPANELDOWNBUTTON)
 
+        self.SplitHorizontally(self.Viewer, self.VariablePanel, -200)
+
         self._init_sizers()
 
     def __init__(self, parent, window, controler, element_type, pou_name = None, transition_name = None, action_name = None, config_name = None, resource_name = None):
@@ -2354,23 +2199,23 @@
         
         if pou_type in ["config", "resource"]:
             self.DefaultTypes = {"All" : "Global"}
-            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
+            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"}
         else:
             self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
-            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
+            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"}
         if pou_type in ["config", "resource"] or pou_type == "program":
-            self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"])
+            self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant", "Edit"])
             if pou_type not in ["config", "resource"]:
                 self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp","Global","Access"]
             else:
                 self.FilterChoices = ["All","Global","Access"]
-            self.ColSizes = [40, 80, 70, 80, 80, 80, 60, 70]
-            self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
-        else:
-            self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Initial Value", "Retain", "Constant"])
+            self.ColSizes = [40, 80, 70, 80, 80, 80, 60, 70, 50]
+            self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_LEFT]
+        else:
+            self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Initial Value", "Retain", "Constant", "Edit"])
             self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp"]
-            self.ColSizes = [40, 120, 70, 80, 120, 60, 70]
-            self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
+            self.ColSizes = [40, 120, 70, 80, 120, 60, 70, 50]
+            self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER, wx.ALIGN_LEFT]
         for choice in self.FilterChoices:
             self.ClassFilter.Append(choice)
         reverse_transfer = {}
@@ -2380,7 +2225,7 @@
         self.RefreshTypeList()
 
         self.OptionList = "Yes,No"
-        self.TypeList = ",".join([value for value, parent in TypeHierarchy_list if not value.startswith("ANY")])
+        self.TypeList = [value for value, parent in TypeHierarchy_list if not value.startswith("ANY")]
         
         if pou_type == "function":
             for value, parent in TypeHierarchy_list:
@@ -2424,10 +2269,21 @@
             self.PouIsUsed = self.Controler.PouIsUsed(self.PouName)
             returnType = self.Controler.GetCurrentElementEditingInterfaceReturnType()
             self.Values = self.Controler.GetCurrentElementEditingInterfaceVars()
+        
+        if returnType and self.ReturnType.IsEnabled():
+            self.ReturnType.SetStringSelection(returnType)
+        
+        self.RefreshValues()
+        self.RefreshViewerVarList()
+        self.RefreshButtons()
+        self.Viewer.RefreshView()
+    
+    def RefreshViewerVarList(self):
+        if self.ElementType not in ["config", "ressource"]:
             varlist = [var["Name"] for var in self.Values]
-            if self.ElementType == "transtion":
+            if self.ElementType == "transition":
                 language = self.Controler.GetTransitionBodyType(self.PouName, self.TransitionName)
-                varlist.append(self.ActionName)
+                varlist.append(self.TransitionName)
             elif self.ElementType == "action":
                 language = self.Controler.GetActionBodyType(self.PouName, self.ActionName)
                 varlist.append(self.ActionName)
@@ -2437,12 +2293,6 @@
             if language in ["IL", "ST"]:
                 self.Viewer.SetVariables(varlist)
                 self.Viewer.SetFunctions(self.Controler.GetBlockTypes())
-        
-        if returnType and self.ReturnType.IsEnabled():
-            self.ReturnType.SetStringSelection(returnType)
-        self.RefreshValues()
-        self.RefreshButtons()
-        self.Viewer.RefreshView()
     
     def OnClassFilter(self, event):
         self.Filter = self.FilterChoiceTransfer[self.ClassFilter.GetStringSelection()]
@@ -2480,6 +2330,7 @@
         else:
             new_row["Class"] = self.Filter
         self.Values.append(new_row)
+        self.SaveValues()
         self.RefreshValues()
         self.RefreshButtons()
         event.Skip()
@@ -2487,6 +2338,7 @@
     def OnDeleteButton(self, event):
         row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
         self.Values.remove(row)
+        self.SaveValues()
         self.RefreshValues()
         self.RefreshButtons()
         event.Skip()
@@ -2534,6 +2386,7 @@
                 self.Controler.BufferProject()
                 self.Parent.RefreshTitle()
                 self.Parent.RefreshEditMenu()
+                self.RefreshViewerVarList()
                 self.Viewer.RefreshView()
                 event.Skip()
         else:
@@ -2541,6 +2394,49 @@
             event.Skip()
 
     def OnVariablesGridCellLeftClick(self, event):
+        if event.GetCol() == "#":
+            row = event.GetRow()
+            var_name = self.Table.GetValueByName(row, "Name")
+            var_class = self.Table.GetValueByName(row, "Class")
+            var_type = self.Table.GetValueByName(row, "Type")
+            data = wx.TextDataObject(str((var_name, var_class, var_type)))
+            dragSource = wx.DropSource(self.VariablesGrid)
+            dragSource.SetData(data)
+            dragSource.DoDragDrop()
+        event.Skip()
+    
+    def OnVariablesGridEditorShown(self, event):
+        row, col = event.GetRow(), event.GetCol() 
+        if self.Table.GetColLabelValue(col) == "Type":
+            type_menu = wx.Menu(title='')
+            base_menu = wx.Menu(title='')
+            for base_type in self.TypeList:
+                new_id = wx.NewId()
+                base_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
+                self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
+            type_menu.AppendMenu(-1, "Base Types", base_menu, '')
+            functionblock_menu = wx.Menu(title='')
+            for functionblock_type in self.Controler.GetFunctionBlockTypes():
+                new_id = wx.NewId()
+                functionblock_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
+                self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
+            type_menu.AppendMenu(-1, "Function Block Types", functionblock_menu, '')
+            rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
+            self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize())
+            event.Veto()
+        else:
+            event.Skip()
+    
+    def GetVariableTypeFunction(self, base_type):
+        def VariableTypeFunction(event):
+            row = self.VariablesGrid.GetGridCursorRow()
+            self.Table.SetValueByName(row, "Type", base_type)
+            self.SaveValues()
+            self.Table.ResetView(self.VariablesGrid)
+            event.Skip()
+        return VariableTypeFunction
+    
+    def OnVariablesGridCellLeftClick(self, event):
         if event.GetCol() == 0:
             row = event.GetRow()
             var_name = self.Table.GetValueByName(row, "Name")
@@ -2590,310 +2486,6 @@
             self.Parent.RefreshTitle()
             self.Parent.RefreshEditMenu()
 
-##[ID_EDITVARIABLEDIALOG, ID_EDITVARIABLEDIALOGMAINPANEL, 
-## ID_EDITVARIABLEDIALOGVARIABLESGRID, ID_EDITVARIABLEDIALOGRETURNTYPE, 
-## ID_EDITVARIABLEDIALOGCLASSFILTER, ID_EDITVARIABLEDIALOGADDBUTTON,
-## ID_EDITVARIABLEDIALOGDELETEBUTTON, ID_EDITVARIABLEDIALOGUPBUTTON, 
-## ID_EDITVARIABLEDIALOGDOWNBUTTON, ID_EDITVARIABLEDIALOGSTATICTEXT1, 
-## ID_EDITVARIABLEDIALOGSTATICTEXT2, ID_EDITVARIABLEDIALOGSTATICTEXT3,
-##] = [wx.NewId() for _init_ctrls in range(12)]
-##
-##class EditVariableDialog(wx.Dialog):
-##    def _init_coll_flexGridSizer1_Items(self, parent):
-##        parent.AddWindow(self.MainPanel, 0, border=0, flag=0)
-##        parent.AddWindow(self.ButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT)
-##
-##    def _init_sizers(self):
-##        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
-##
-##        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
-##
-##        self.SetSizer(self.flexGridSizer1)
-##
-##    def _init_ctrls(self, prnt, name):
-##        wx.Dialog.__init__(self, id=ID_EDITVARIABLEDIALOG,
-##              name='EditVariableDialog', parent=prnt, pos=wx.Point(376, 223),
-##              size=wx.Size(600, 440), style=wx.DEFAULT_DIALOG_STYLE,
-##              title='Edit variables of %s'%name)
-##        self.SetClientSize(wx.Size(600, 440))
-##
-##        self.MainPanel = wx.Panel(id=ID_EDITVARIABLEDIALOGMAINPANEL,
-##              name='MainPanel', parent=self, pos=wx.Point(0, 0),
-##              size=wx.Size(600, 440), style=wx.TAB_TRAVERSAL)
-##        self.MainPanel.SetAutoLayout(True)
-##
-##        self.staticText1 = wx.StaticText(id=ID_EDITVARIABLEDIALOGSTATICTEXT1,
-##              label='Return Type:', name='staticText1', parent=self.MainPanel,
-##              pos=wx.Point(24, 29), size=wx.Size(95, 17), style=0)
-##
-##        self.ReturnType = wx.Choice(id=ID_EDITVARIABLEDIALOGRETURNTYPE,
-##              name='ReturnType', parent=self.MainPanel, pos=wx.Point(124, 24),
-##              size=wx.Size(145, 24), style=0)
-##
-##        self.staticText2 = wx.StaticText(id=ID_EDITVARIABLEDIALOGSTATICTEXT2,
-##              label='Class Filter:', name='staticText2', parent=self.MainPanel,
-##              pos=wx.Point(324, 29), size=wx.Size(95, 17), style=0)
-##
-##        self.ClassFilter = wx.Choice(id=ID_EDITVARIABLEDIALOGCLASSFILTER,
-##              name='ClassFilter', parent=self.MainPanel, pos=wx.Point(424, 24),
-##              size=wx.Size(145, 24), style=0)
-##        self.Bind(wx.EVT_CHOICE, self.OnClassFilter, id=ID_EDITVARIABLEDIALOGCLASSFILTER)
-##
-##        self.staticText3 = wx.StaticText(id=ID_EDITVARIABLEDIALOGSTATICTEXT3,
-##              label='Variables:', name='staticText3', parent=self.MainPanel,
-##              pos=wx.Point(24, 60), size=wx.Size(95, 17), style=0)
-##
-##        self.VariablesGrid = wx.grid.Grid(id=ID_EDITVARIABLEDIALOGVARIABLESGRID,
-##              name='VariablesGrid', parent=self.MainPanel, pos=wx.Point(24, 80), 
-##              size=wx.Size(550, 250), style=wx.VSCROLL)
-##        self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
-##              'Sans'))
-##        self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
-##              False, 'Sans'))
-##        self.VariablesGrid.DisableDragGridSize()
-##        self.VariablesGrid.EnableScrolling(False, True)
-##        self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
-##        self.VariablesGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnVariablesGridSelectCell)
-##
-##        self.AddButton = wx.Button(id=ID_EDITVARIABLEDIALOGADDBUTTON, label='Add',
-##              name='AddButton', parent=self.MainPanel, pos=wx.Point(345, 340),
-##              size=wx.Size(72, 32), style=0)
-##        self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_EDITVARIABLEDIALOGADDBUTTON)
-##
-##        self.DeleteButton = wx.Button(id=ID_EDITVARIABLEDIALOGDELETEBUTTON, label='Delete',
-##              name='DeleteButton', parent=self.MainPanel, pos=wx.Point(425, 340),
-##              size=wx.Size(72, 32), style=0)
-##        self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_EDITVARIABLEDIALOGDELETEBUTTON)
-##
-##        self.UpButton = wx.Button(id=ID_EDITVARIABLEDIALOGUPBUTTON, label='^',
-##              name='UpButton', parent=self.MainPanel, pos=wx.Point(505, 340),
-##              size=wx.Size(32, 32), style=0)
-##        self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_EDITVARIABLEDIALOGUPBUTTON)
-##
-##        self.DownButton = wx.Button(id=ID_EDITVARIABLEDIALOGDOWNBUTTON, label='v',
-##              name='DownButton', parent=self.MainPanel, pos=wx.Point(545, 340),
-##              size=wx.Size(32, 32), style=0)
-##        self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_EDITVARIABLEDIALOGDOWNBUTTON)
-##
-##        self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
-##        self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())       
-##
-##        self._init_sizers()
-##
-##    def __init__(self, parent, name, pou_type, pou_is_used, filter = "All"):
-##        self._init_ctrls(parent, name)
-##
-##        self.Filter = filter
-##        self.PouIsUsed = pou_is_used
-##        self.FilterChoices = []
-##        self.FilterChoiceTransfer = {"All" : "All", "Interface" : "Interface", 
-##            "   Input" : "Input", "   Output" : "Output", "   InOut" : "InOut", 
-##            "   External" : "External", "Variables" : "Variables", "   Local" : "Local",
-##            "   Temp" : "Temp", "Global" : "Global", "Access" : "Access"}
-##        
-##        if pou_type:
-##            self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
-##            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
-##        else:
-##            self.DefaultTypes = {"All" : "Global"}
-##            self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"}
-##        if not pou_type or pou_type == "program":
-##            self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"])
-##            if pou_type:
-##                self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp","Global","Access"]
-##            else:
-##                self.FilterChoices = ["All","Global","Access"]
-##            self.ColSizes = [80, 70, 80, 80, 80, 60, 70]
-##            self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
-##        else:
-##            self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Initial Value", "Retain", "Constant"])
-##            self.FilterChoices = ["All","Interface","   Input","   Output","   InOut","   External","Variables","   Local","   Temp"]
-##            self.ColSizes = [120, 70, 80, 120, 60, 70]
-##            self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
-##        for choice in self.FilterChoices:
-##            self.ClassFilter.Append(choice)
-##        reverse_transfer = {}
-##        for filter, choice in self.FilterChoiceTransfer.items():
-##            reverse_transfer[choice] = filter
-##        self.ClassFilter.SetStringSelection(reverse_transfer[self.Filter])
-##        self.RefreshTypeList()
-##        self.RefreshButtons()
-##
-##        self.OptionList = "Yes,No"
-##        self.TypeList = ",".join([value for value, parent in TypeHierarchy_list if not value.startswith("ANY")])
-##        
-##        if pou_type == "function":
-##            for value, parent in TypeHierarchy_list:
-##                if not value.startswith("ANY"):
-##                    self.ReturnType.Append(value)
-##            self.ReturnType.Enable(True)
-##        else:
-##            self.ReturnType.Enable(False)
-##            self.staticText2.Hide()
-##            self.ReturnType.Hide()
-##        
-##        self.VariablesGrid.SetTable(self.Table)
-##        self.VariablesGrid.SetRowLabelSize(0)
-##        
-##        self.Table.ResetView(self.VariablesGrid)
-##
-##        self.PouNames = []
-##
-##        if self.PouIsUsed:
-##            wx.CallAfter(self.WarningMessage, name)
-##    
-##    def WarningMessage(self, name):
-##        message = wx.MessageDialog(self, "\"%s\" is used by one or more POUs. Its interface can't be changed!"%name, "WARNING", wx.OK|wx.ICON_EXCLAMATION)
-##        message.ShowModal()
-##        message.Destroy()
-##    
-##    def OnOK(self, event):
-##        self.VariablesGrid.SetGridCursor(0, 0)
-##        error = []
-##        if self.ReturnType.IsEnabled() and self.ReturnType.GetStringSelection() == "":
-##            error.append("Return Type")
-##        if len(error) > 0:
-##            text = ""
-##            for i, item in enumerate(error):
-##                if i == 0:
-##                    text += item
-##                elif i == len(error) - 1:
-##                    text += " and %s"%item
-##                else:
-##                    text += ", %s"%item 
-##            message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR)
-##            message.ShowModal()
-##            message.Destroy()
-##        else:
-##            self.EndModal(wx.ID_OK)
-##
-##    def OnClassFilter(self, event):
-##        self.Filter = self.FilterChoiceTransfer[self.ClassFilter.GetStringSelection()]
-##        self.RefreshTypeList()
-##        self.RefreshValues()
-##        self.RefreshButtons()
-##        event.Skip()
-##
-##    def RefreshTypeList(self):
-##        if self.Filter == "All":
-##            self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]]
-##        elif self.Filter == "Interface":
-##            self.ClassList = ["Input","Output","InOut","External"]
-##        elif self.Filter == "Variables":
-##            self.ClassList = ["Local","Temp"]
-##        else:
-##            self.ClassList = [self.Filter]
-##
-##    def RefreshButtons(self):
-##        table_length = len(self.Table.data)
-##        row_class = None
-##        if table_length and self.PouIsUsed:
-##            row = self.VariablesGrid.GetGridCursorRow()
-##            row_class = self.Table.GetValueByName(row, "Class")
-##        self.AddButton.Enable(not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"])
-##        self.DeleteButton.Enable(table_length > 0 and row_class not in ["Input", "Output", "InOut"])
-##        self.UpButton.Enable(table_length > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
-##        self.DownButton.Enable(table_length > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
-##    
-##    def OnAddButton(self, event):
-##        new_row = self.DefaultValue.copy()
-##        if self.Filter in self.DefaultTypes:
-##            new_row["Class"] = self.DefaultTypes[self.Filter]
-##        else:
-##            new_row["Class"] = self.Filter
-##        self.Values.append(new_row)
-##        self.RefreshValues()
-##        self.RefreshButtons()
-##        event.Skip()
-##
-##    def OnDeleteButton(self, event):
-##        row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
-##        self.Values.remove(row)
-##        self.RefreshValues()
-##        self.RefreshButtons()
-##        event.Skip()
-##
-##    def OnUpButton(self, event):
-##        self.MoveValue(self.VariablesGrid.GetGridCursorRow(), -1)
-##        self.RefreshButtons()
-##        event.Skip()
-##
-##    def OnDownButton(self, event):
-##        self.MoveValue(self.VariablesGrid.GetGridCursorRow(), 1)
-##        self.RefreshButtons()
-##        event.Skip()
-##
-##    def OnVariablesGridCellChange(self, event):
-##        row, col = event.GetRow(), event.GetCol()
-##        colname = self.Table.GetColLabelValue(col)
-##        value = self.Table.GetValue(row, col)
-##        if colname == "Name":
-##            if not TestIdentifier(value):
-##                message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%value, "Error", wx.OK|wx.ICON_ERROR)
-##                message.ShowModal()
-##                message.Destroy()
-##                event.Veto()
-##            elif value.upper() in IEC_KEYWORDS:
-##                message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%value, "Error", wx.OK|wx.ICON_ERROR)
-##                message.ShowModal()
-##                message.Destroy()
-##                event.Veto()
-##            elif value.upper() in self.PouNames:
-##                message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%value, "Error", wx.OK|wx.ICON_ERROR)
-##                message.ShowModal()
-##                message.Destroy()
-##                event.Veto()
-##            elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]:
-##                message = wx.MessageDialog(self, "A variable with \"%s\" as name exists in this pou!"%value, "Error", wx.OK|wx.ICON_ERROR)
-##                message.ShowModal()
-##                message.Destroy()
-##                event.Veto()
-##            else:
-##                event.Skip()
-##        else:
-##            event.Skip()
-##
-##    def OnVariablesGridSelectCell(self, event):
-##        wx.CallAfter(self.RefreshButtons)
-##        event.Skip()
-##
-##    def SetPouNames(self, pou_names):
-##        self.PouNames = [pou_name.upper() for pou_name in pou_names]
-##
-##    def SetValues(self, values):
-##        for item, value in values.items():
-##            if item == "returnType" and value and self.ReturnType.IsEnabled():
-##                self.ReturnType.SetStringSelection(value)
-##            if item == "data":
-##                self.Values = value
-##        self.RefreshValues()
-##
-##    def MoveValue(self, value_index, move):
-##        new_index = max(0, min(value_index + move, len(self.Values) - 1))
-##        if new_index != value_index:
-##            self.Values.insert(new_index, self.Values.pop(value_index))
-##            self.RefreshValues()
-##            self.VariablesGrid.SetGridCursor(new_index, self.VariablesGrid.GetGridCursorCol())
-##        else:
-##            self.RefreshValues()
-##    
-##    def RefreshValues(self):
-##        if len(self.Table.data) > 0:
-##            self.VariablesGrid.SetGridCursor(0, 0)
-##        data = []
-##        for variable in self.Values:
-##            if variable["Class"] in self.ClassList:
-##                data.append(variable)
-##        self.Table.SetData(data)
-##        self.Table.ResetView(self.VariablesGrid)
-##                
-##    def GetValues(self):
-##        values = {}
-##        if self.ReturnType.IsEnabled():
-##            values["returnType"] = self.ReturnType.GetStringSelection()
-##        values["data"] = self.Values
-##        return values
-
 #-------------------------------------------------------------------------------
 #                               Exception Handler
 #-------------------------------------------------------------------------------
--- a/TextViewer.py	Thu Aug 09 18:07:44 2007 +0200
+++ b/TextViewer.py	Fri Aug 10 16:14:33 2007 +0200
@@ -195,7 +195,7 @@
         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:
+                if blocktype["type"] == "function" and blocktype["name"] not in self.Keywords and blocktype["name"] not in self.Variables:
                     self.Functions.append(blocktype["name"].upper())
         self.Colourise(0, -1)
     
--- a/examples/example.xml	Thu Aug 09 18:07:44 2007 +0200
+++ b/examples/example.xml	Fri Aug 10 16:14:33 2007 +0200
@@ -90,7 +90,7 @@
               </connectionPointIn>
               <expression>OUT</expression>
             </outVariable>
-            <block localId="6" height="84" width="99" instanceName="" typeName="AND">
+            <block localId="6" height="84" width="99" typeName="AND">
               <position y="105" x="235"/>
               <inputVariables>
                 <variable formalParameter="IN1" edge="rising">
@@ -132,7 +132,7 @@
               </connectionPointOut>
               <expression>IN3</expression>
             </inVariable>
-            <block localId="8" height="87" width="99" instanceName="" typeName="OR">
+            <block localId="8" height="87" width="99" typeName="OR">
               <position y="246" x="235"/>
               <inputVariables>
                 <variable formalParameter="IN1" negated="true">
@@ -442,6 +442,13 @@
               </type>
             </variable>
           </inputVars>
+          <localVars>
+            <variable name="SR1">
+              <type>
+                <derived name="SR"/>
+              </type>
+            </variable>
+          </localVars>
         </interface>
         <actions>
           <action name="ACT1">
@@ -467,41 +474,6 @@
           <transition name="TR2">
             <body>
               <FBD>
-                <block localId="1" height="82" width="107" typeName="AND">
-                  <position y="61" x="160"/>
-                  <inputVariables>
-                    <variable formalParameter="IN1">
-                      <connectionPointIn>
-                        <relPosition y="35" x="0"/>
-                        <connection refLocalId="2">
-                          <position y="96" x="160"/>
-                          <position y="96" x="120"/>
-                          <position y="72" x="120"/>
-                          <position y="72" x="81"/>
-                        </connection>
-                      </connectionPointIn>
-                    </variable>
-                    <variable formalParameter="IN2">
-                      <connectionPointIn>
-                        <relPosition y="66" x="0"/>
-                        <connection refLocalId="3">
-                          <position y="127" x="160"/>
-                          <position y="127" x="120"/>
-                          <position y="153" x="120"/>
-                          <position y="153" x="81"/>
-                        </connection>
-                      </connectionPointIn>
-                    </variable>
-                  </inputVariables>
-                  <inOutVariables/>
-                  <outputVariables>
-                    <variable formalParameter="OUT">
-                      <connectionPointOut>
-                        <relPosition y="35" x="107"/>
-                      </connectionPointOut>
-                    </variable>
-                  </outputVariables>
-                </block>
                 <inVariable localId="2" width="54" height="27">
                   <position y="59" x="27"/>
                   <connectionPointOut>
@@ -517,16 +489,51 @@
                   <expression>IN2</expression>
                 </inVariable>
                 <outVariable localId="4" width="57" height="27">
-                  <position y="83" x="351"/>
+                  <position y="82" x="340"/>
                   <connectionPointIn>
                     <relPosition y="13" x="0"/>
-                    <connection refLocalId="1" formalParameter="OUT">
-                      <position y="96" x="351"/>
-                      <position y="96" x="267"/>
+                    <connection refLocalId="5" formalParameter="Q1">
+                      <position y="95" x="340"/>
+                      <position y="95" x="261"/>
                     </connection>
                   </connectionPointIn>
                   <expression>TR2</expression>
                 </outVariable>
+                <block localId="5" height="70" width="100" instanceName="SR1" typeName="SR">
+                  <position y="63" x="161"/>
+                  <inputVariables>
+                    <variable formalParameter="S1">
+                      <connectionPointIn>
+                        <relPosition y="32" x="0"/>
+                        <connection refLocalId="2">
+                          <position y="95" x="161"/>
+                          <position y="95" x="121"/>
+                          <position y="72" x="121"/>
+                          <position y="72" x="81"/>
+                        </connection>
+                      </connectionPointIn>
+                    </variable>
+                    <variable formalParameter="R">
+                      <connectionPointIn>
+                        <relPosition y="57" x="0"/>
+                        <connection refLocalId="3">
+                          <position y="120" x="161"/>
+                          <position y="120" x="121"/>
+                          <position y="153" x="121"/>
+                          <position y="153" x="81"/>
+                        </connection>
+                      </connectionPointIn>
+                    </variable>
+                  </inputVariables>
+                  <inOutVariables/>
+                  <outputVariables>
+                    <variable formalParameter="Q1">
+                      <connectionPointOut>
+                        <relPosition y="32" x="100"/>
+                      </connectionPointOut>
+                    </variable>
+                  </outputVariables>
+                </block>
               </FBD>
             </body>
           </transition>
--- a/plcopen/plcopen.py	Thu Aug 09 18:07:44 2007 +0200
+++ b/plcopen/plcopen.py	Fri Aug 10 16:14:33 2007 +0200
@@ -413,7 +413,12 @@
     def addPouVar(self, type, name):
         content = self.interface.getContent()
         if len(content) == 0 or content[-1]["name"] != "localVars":
-            self.interface.appendContent("localVars", PLCOpenClasses["varList"]())
+            content.append({"name" : "localVars", "value" : PLCOpenClasses["varList"]()})
+        else:
+            varlist = content[-1]["value"]
+            variables = varlist.getVariable()
+            if varlist.getConstant() or varlist.getRetain() or len(variables) > 0 and variables[0].getAddress():
+                content.append({"name" : "localVars", "value" : PLCOpenClasses["varList"]()})
         var = PLCOpenClasses["varListPlain_variable"]()
         var.setName(name)
         var_type = PLCOpenClasses["dataType"]()
@@ -438,7 +443,23 @@
                 content.remove(varlist)
                 break
     setattr(cls, "removePouVar", removePouVar)
-        
+    
+    def hasBlock(self, name):
+        if self.getBodyType() in ["FBD", "LD", "SFC"]:
+            for instance in self.getInstances():
+                if isinstance(instance, PLCOpenClasses["block"]) and instance.getInstanceName() == name:
+                    return True
+            for transition in self.transitions.getTransition():
+                result = transition.hasBlock(name)
+                if result:
+                    return result
+            for action in self.actions.getAction():
+                result = action.hasBlock(name)
+                if result:
+                    return result
+        return False
+    setattr(cls, "hasBlock", hasBlock)
+    
     def addTransition(self, name, type):
         if not self.transitions:
             self.addTransitions()
@@ -540,6 +561,14 @@
         self.body.updateElementName(old_name, new_name)
     setattr(cls, "updateElementName", updateElementName)
 
+    def hasBlock(self, name):
+        if self.getBodyType() in ["FBD", "LD", "SFC"]:
+            for instance in self.getInstances():
+                if isinstance(instance, PLCOpenClasses["block"]) and instance.getInstanceName() == name:
+                    return True
+        return False
+    setattr(cls, "hasBlock", hasBlock)
+
 cls = PLCOpenClasses.get("actions_action", None)
 if cls:
     setattr(cls, "setBodyType", setBodyType)
@@ -557,6 +586,14 @@
         self.body.updateElementName(old_name, new_name)
     setattr(cls, "updateElementName", updateElementName)
 
+    def hasBlock(self, name):
+        if self.getBodyType() in ["FBD", "LD", "SFC"]:
+            for instance in self.getInstances():
+                if isinstance(instance, PLCOpenClasses["block"]) and instance.getInstanceName() == name:
+                    return True
+        return False
+    setattr(cls, "hasBlock", hasBlock)
+
 cls = PLCOpenClasses.get("body", None)
 if cls:
     def appendContentInstance(self, name, instance):