Adding support for direct array variable declaration in variable panel (still disable cause matiec doesn't support this feature)
authorlaurent
Wed, 30 Mar 2011 15:49:09 +0200
changeset 507 42150e041dbe
parent 504 f88e0ebd8fe4
child 508 01f49e491be5
Adding support for direct array variable declaration in variable panel (still disable cause matiec doesn't support this feature)
DataTypeEditor.py
PLCControler.py
PLCGenerator.py
VariablePanel.py
dialogs/ArrayTypeDialog.py
dialogs/__init__.py
--- a/DataTypeEditor.py	Tue Feb 22 17:05:07 2011 +0100
+++ b/DataTypeEditor.py	Wed Mar 30 15:49:09 2011 +0200
@@ -479,7 +479,7 @@
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
 
         self.ArrayBaseType = wx.ComboBox(id=ID_DATATYPEEDITORARRAYBASETYPE, 
-              name='SubrangeBaseType', parent=self.ArrayPanel, pos=wx.Point(0, 0),
+              name='ArrayBaseType', parent=self.ArrayPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 28), style=wx.CB_READONLY)
         self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, id=ID_DATATYPEEDITORARRAYBASETYPE)
 
--- a/PLCControler.py	Tue Feb 22 17:05:07 2011 +0100
+++ b/PLCControler.py	Wed Mar 30 15:49:09 2011 +0200
@@ -898,9 +898,33 @@
             # Create variable and change its properties
             tempvar = plcopen.varListPlain_variable()
             tempvar.setname(var["Name"])
-
+            
             var_type = plcopen.dataType()
-            if var["Type"] in self.GetBaseTypes():
+            if isinstance(var["Type"], TupleType):
+                if var["Type"][0] == "array":
+                    array_type, base_type_name, dimensions = var["Type"]
+                    array = plcopen.derivedTypes_array()
+                    for i, dimension in enumerate(dimensions):
+                        dimension_range = plcopen.rangeSigned()
+                        dimension_range.setlower(dimension[0])
+                        dimension_range.setupper(dimension[1])
+                        if i == 0:
+                            array.setdimension([dimension_range])
+                        else:
+                            array.appenddimension(dimension_range)
+                    if base_type_name in self.GetBaseTypes():
+                        if base_type_name == "STRING":
+                            array.baseType.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
+                        elif base_type_name == "WSTRING":
+                            array.baseType.setcontent({"name" : "wstring", "value" : plcopen.wstring()})
+                        else:
+                            array.baseType.setcontent({"name" : base_type_name, "value" : None})
+                    else:
+                        derived_datatype = plcopen.derivedTypes_derived()
+                        derived_datatype.setname(base_type_name)
+                        array.baseType.setcontent({"name" : "derived", "value" : derived_datatype})
+                    var_type.setcontent({"name" : "array", "value" : array})
+            elif var["Type"] in self.GetBaseTypes():
                 if var["Type"] == "STRING":
                     var_type.setcontent({"name" : "string", "value" : plcopen.elementaryTypes_string()})
                 elif var["Type"] == "WSTRING":
@@ -941,6 +965,16 @@
         vartype_content = var.gettype().getcontent()
         if vartype_content["name"] == "derived":
             tempvar["Type"] = vartype_content["value"].getname()
+        elif vartype_content["name"] == "array":
+            dimensions = []
+            for dimension in vartype_content["value"].getdimension():
+                dimensions.append((dimension.getlower(), dimension.getupper()))
+            base_type = vartype_content["value"].baseType.getcontent()
+            if base_type["value"] is None:
+                base_type_name = base_type["name"]
+            else:
+                base_type_name = base_type["value"].getname()
+            tempvar["Type"] = ("array", base_type_name, dimensions)
         elif vartype_content["name"] in ["string", "wstring"]:
             tempvar["Type"] = vartype_content["name"].upper()
         else:
--- a/PLCGenerator.py	Tue Feb 22 17:05:07 2011 +0100
+++ b/PLCGenerator.py	Wed Mar 30 15:49:09 2011 +0200
@@ -265,6 +265,20 @@
                 # Variable type is a string type
                 elif vartype_content["name"] in ["string", "wstring"]:
                     var_type = vartype_content["name"].upper()
+                # Variable type is an array
+                elif vartype_content["name"] == "array":
+                    base_type = vartype_content["value"].baseType.getcontent()
+                    # Array derived directly from a user defined type 
+                    if base_type["name"] == "derived":
+                        basetype_name = base_type["value"].getname()
+                        self.GenerateDataType(basetype_name)
+                    # Array derived directly from a string type 
+                    elif base_type["name"] in ["string", "wstring"]:
+                        basetype_name = base_type["name"].upper()
+                    # Array derived directly from an elementary type 
+                    else:
+                        basetype_name = base_type["name"]
+                    var_type = "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (dimension.getlower(), dimension.getupper()), vartype_content["value"].getdimension())), basetype_name)
                 # Variable type is an elementary type
                 else:
                     var_type = vartype_content["name"]
@@ -320,6 +334,20 @@
                 # Variable type is a string type
                 elif vartype_content["name"] in ["string", "wstring"]:
                     var_type = vartype_content["name"].upper()
+                # Variable type is an array
+                elif vartype_content["name"] == "array":
+                    base_type = vartype_content["value"].baseType.getcontent()
+                    # Array derived directly from a user defined type 
+                    if base_type["name"] == "derived":
+                        basetype_name = base_type["value"].getname()
+                        self.GenerateDataType(basetype_name)
+                    # Array derived directly from a string type 
+                    elif base_type["name"] in ["string", "wstring"]:
+                        basetype_name = base_type["name"].upper()
+                    # Array derived directly from an elementary type 
+                    else:
+                        basetype_name = base_type["name"]
+                    var_type = "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (dimension.getlower(), dimension.getupper()), vartype_content["value"].getdimension())), basetype_name)
                 # Variable type is an elementary type
                 else:
                     var_type = vartype_content["name"]
@@ -588,14 +616,27 @@
                             initial_value = None
                         address = var.getaddress()
                         if vartype_content["name"] in ["string", "wstring"]:
-                            if address is not None:
-                                located.append((vartype_content["name"].upper(), var.getname(), address, initial_value))
+                            var_type = vartype_content["name"].upper()
+                        # Variable type is an array
+                        elif vartype_content["name"] == "array":
+                            base_type = vartype_content["value"].baseType.getcontent()
+                            # Array derived directly from a user defined type 
+                            if base_type["name"] == "derived":
+                                basetype_name = base_type["value"].getname()
+                                self.GenerateDataType(basetype_name)
+                            # Array derived directly from a string type 
+                            elif base_type["name"] in ["string", "wstring"]:
+                                basetype_name = base_type["name"].upper()
+                            # Array derived directly from an elementary type 
                             else:
-                                variables.append((vartype_content["name"].upper(), var.getname(), None, initial_value))
-                        elif address is not None:
-                            located.append((vartype_content["name"], var.getname(), address, initial_value))
+                                basetype_name = base_type["name"]
+                            var_type = "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (x.getlower(), x.getupper()), vartype_content["value"].getdimension())), basetype_name)
                         else:
-                            variables.append((vartype_content["name"], var.getname(), None, initial_value))
+                            var_type = vartype_content["name"]
+                        if address is not None:
+                            located.append((var_type, var.getname(), address, initial_value))
+                        else:
+                            variables.append((var_type, var.getname(), None, initial_value))
                 if varlist["value"].getconstant():
                     option = "CONSTANT"
                 elif varlist["value"].getretain():
--- a/VariablePanel.py	Tue Feb 22 17:05:07 2011 +0100
+++ b/VariablePanel.py	Wed Mar 30 15:49:09 2011 +0200
@@ -28,6 +28,7 @@
 
 from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS
 from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
+from dialogs import ArrayTypeDialog
 
 CWD = os.path.split(os.path.realpath(__file__))[0]
 
@@ -120,7 +121,11 @@
             if col == 0:
                 return self.data[row]["Number"]
             colname = self.GetColLabelValue(col, False)
-            value = str(self.data[row].get(colname, ""))
+            value = self.data[row].get(colname, "")
+            if colname == "Type" and isinstance(value, TupleType):
+                if value[0] == "array":
+                    return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1])
+            value = str(value)
             if colname in ["Class", "Option"]:
                 return _(value)
             return value
@@ -774,7 +779,11 @@
             bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
             pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
             classtype = self.Table.GetValueByName(row, "Class")
-
+            
+            #new_id = wx.NewId()
+            #AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array"))
+            #self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id)
+            
             if classtype in ["Input", "Output", "InOut", "External", "Global"] or \
             poutype != "function" and bodytype in ["ST", "IL"]:
                 functionblock_menu = wx.Menu(title='')
@@ -807,6 +816,20 @@
             self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
         return VariableTypeFunction
     
+    def VariableArrayTypeFunction(self, event):
+        row = self.VariablesGrid.GetGridCursorRow()
+        dialog = ArrayTypeDialog(self, 
+                                 self.Controler.GetDataTypes(self.TagName), 
+                                 self.Table.GetValueByName(row, "Type"))
+        if dialog.ShowModal() == wx.ID_OK:
+            self.Table.SetValueByName(row, "Type", dialog.GetValue())
+            self.Table.ResetView(self.VariablesGrid)
+            self.SaveValues(False)
+            self.ParentWindow.RefreshEditor(variablepanel = False)
+            self.Controler.BufferProject()
+            self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
+        dialog.Destroy()
+    
     def OnVariablesGridCellLeftClick(self, event):
         row = event.GetRow()
         if event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit"):
@@ -1204,4 +1227,3 @@
             message.Destroy()
         else:
             self.EndModal(wx.ID_OK)
-        
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dialogs/ArrayTypeDialog.py	Wed Mar 30 15:49:09 2011 +0200
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+
+#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
+#based on the plcopen standard. 
+#
+#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
+#
+#See COPYING file for copyrights details.
+#
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU General Public
+#License as published by the Free Software Foundation; either
+#version 2.1 of the License, or (at your option) any later version.
+#
+#This library is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#General Public License for more details.
+#
+#You should have received a copy of the GNU General Public
+#License along with this library; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import re
+from types import TupleType
+
+import wx
+import wx.gizmos
+
+DIMENSION_MODEL = re.compile("([0-9]+)\.\.([0-9]+)$")
+
+[ID_ARRAYTYPEDIALOG, ID_ARRAYTYPEDIALOGBASETYPE, 
+ ID_ARRAYTYPEDIALOGDIMENSIONS, ID_ARRAYTYPEDIALOGDIALOGSTATICTEXT1, 
+] = [wx.NewId() for _init_ctrls in range(4)]
+
+class ArrayTypeDialog(wx.Dialog):
+    
+    if wx.VERSION < (2, 6, 0):
+        def Bind(self, event, function, id = None):
+            if id is not None:
+                event(self, id, function)
+            else:
+                event(self, function)
+    
+    def _init_coll_flexGridSizer1_Items(self, parent):
+        parent.AddSizer(self.TopSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+        parent.AddWindow(self.Dimensions, 0, border=20, flag=wx.GROW|wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT)
+        parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+        
+    def _init_coll_flexGridSizer1_Growables(self, parent):
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(1)
+        
+    def _init_coll_TopSizer_Items(self, parent):
+        parent.AddWindow(self.staticText1, 1, border=0, flag=wx.GROW)
+        parent.AddWindow(self.BaseType, 1, border=0, flag=wx.GROW)
+    
+    def _init_sizers(self):
+        self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
+        self.TopSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
+        self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
+        self._init_coll_TopSizer_Items(self.TopSizer)
+        
+        self.SetSizer(self.flexGridSizer1)
+    
+    def _init_ctrls(self, prnt):
+        wx.Dialog.__init__(self, id=ID_ARRAYTYPEDIALOG,
+              name='ArrayTypeDialog', parent=prnt, pos=wx.Point(376, 223),
+              size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
+              title=_('Edit array type properties'))
+        self.SetClientSize(wx.Size(500, 300))
+        
+        self.staticText1 = wx.StaticText(id=ID_ARRAYTYPEDIALOGDIALOGSTATICTEXT1,
+              label=_('Base Type:'), name='staticText1', parent=self,
+              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+
+        self.BaseType = wx.ComboBox(id=ID_ARRAYTYPEDIALOGBASETYPE, 
+              name='BaseType', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 28), style=wx.CB_READONLY)
+        
+        self.Dimensions = wx.gizmos.EditableListBox(id=ID_ARRAYTYPEDIALOGDIMENSIONS, 
+              name='ArrayDimensions', parent=self, label=_("Dimensions:"), pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=wx.gizmos.EL_ALLOW_NEW | wx.gizmos.EL_ALLOW_EDIT | wx.gizmos.EL_ALLOW_DELETE)
+        self.Dimensions.GetListCtrl().Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnDimensionsChanged)
+        new_button = self.Dimensions.GetNewButton()
+        new_button.SetToolTipString(_("New item"))
+        new_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+        del_button = self.Dimensions.GetDelButton()
+        del_button.SetToolTipString(_("Delete item"))
+        del_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+        up_button = self.Dimensions.GetUpButton()
+        up_button.SetToolTipString(_("Move up"))
+        up_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+        down_button = self.Dimensions.GetDownButton()
+        down_button.SetToolTipString(_("Move down"))
+        down_button.Bind(wx.EVT_BUTTON, self.OnDimensionsChanged)
+        
+        self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+        if wx.VERSION >= (2, 5, 0):
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
+        else:
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
+        
+        self._init_sizers()
+
+    def __init__(self, parent, datatypes, infos):
+        self._init_ctrls(parent)
+        
+        for datatype in datatypes:
+            self.BaseType.Append(datatype)
+        
+        if isinstance(infos, TupleType) and infos[0] == "array":
+            self.BaseType.SetStringSelection(infos[1])
+            self.Dimensions.SetStrings(map(lambda x : "..".join(x), infos[2]))
+        elif infos in datatypes:
+            self.BaseType.SetStringSelection(infos)
+        
+    def GetDimensions(self):
+        dimensions_list = []
+        for dimensions in self.Dimensions.GetStrings():
+            result = DIMENSION_MODEL.match(dimensions)
+            if result is None:
+                message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!")%dimensions, _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+                return None
+            bounds = result.groups()
+            if int(bounds[0]) >= int(bounds[1]):
+                message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.")%dimensions, _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+                return None
+            dimensions_list.append(bounds)
+        return dimensions_list
+    
+    def OnDimensionsChanged(self, event):
+        wx.CallAfter(self.GetDimensions)
+        event.Skip()
+    
+    def OnOK(self, event):
+        if self.GetDimensions() is not None:
+            self.EndModal(wx.ID_OK)
+            
+    def GetValue(self):
+        return "array", self.BaseType.GetStringSelection(), self.GetDimensions()
\ No newline at end of file
--- a/dialogs/__init__.py	Tue Feb 22 17:05:07 2011 +0100
+++ b/dialogs/__init__.py	Wed Mar 30 15:49:09 2011 +0200
@@ -34,4 +34,5 @@
 from SFCStepNameDialog import SFCStepNameDialog
 from SFCTransitionDialog import SFCTransitionDialog
 from SFCDivergenceDialog import SFCDivergenceDialog
-from ForceVariableDialog import ForceVariableDialog
\ No newline at end of file
+from ForceVariableDialog import ForceVariableDialog
+from ArrayTypeDialog import ArrayTypeDialog