dialogs/ActionBlockDialog.py
changeset 409 34c9f624c2fe
child 534 d506a353b3d3
equal deleted inserted replaced
408:0e389fa5b160 409:34c9f624c2fe
       
     1 # -*- coding: utf-8 -*-
       
     2 
       
     3 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     4 #based on the plcopen standard. 
       
     5 #
       
     6 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     7 #
       
     8 #See COPYING file for copyrights details.
       
     9 #
       
    10 #This library is free software; you can redistribute it and/or
       
    11 #modify it under the terms of the GNU General Public
       
    12 #License as published by the Free Software Foundation; either
       
    13 #version 2.1 of the License, or (at your option) any later version.
       
    14 #
       
    15 #This library is distributed in the hope that it will be useful,
       
    16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    18 #General Public License for more details.
       
    19 #
       
    20 #You should have received a copy of the GNU General Public
       
    21 #License along with this library; if not, write to the Free Software
       
    22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    23 
       
    24 import wx
       
    25 import wx.grid
       
    26 
       
    27 #-------------------------------------------------------------------------------
       
    28 #                            Action Block Dialog
       
    29 #-------------------------------------------------------------------------------
       
    30 
       
    31 def GetActionTableColnames():
       
    32     _ = lambda x: x
       
    33     return [_("Qualifier"), _("Duration"), _("Type"), _("Value"), _("Indicator")]
       
    34 
       
    35 def GetTypeList():
       
    36     _ = lambda x: x
       
    37     return [_("Action"), _("Variable"), _("Inline")]
       
    38 
       
    39 class ActionTable(wx.grid.PyGridTableBase):
       
    40     
       
    41     """
       
    42     A custom wx.Grid Table using user supplied data
       
    43     """
       
    44     def __init__(self, parent, data, colnames):
       
    45         # The base class must be initialized *first*
       
    46         wx.grid.PyGridTableBase.__init__(self)
       
    47         self.data = data
       
    48         self.colnames = colnames
       
    49         self.Parent = parent
       
    50         # XXX
       
    51         # we need to store the row length and collength to
       
    52         # see if the table has changed size
       
    53         self._rows = self.GetNumberRows()
       
    54         self._cols = self.GetNumberCols()
       
    55     
       
    56     def GetNumberCols(self):
       
    57         return len(self.colnames)
       
    58         
       
    59     def GetNumberRows(self):
       
    60         return len(self.data)
       
    61 
       
    62     def GetColLabelValue(self, col, translate=True):
       
    63         if col < len(self.colnames):
       
    64             colname = self.colnames[col]
       
    65             if translate:
       
    66                 return _(colname)
       
    67         return colname
       
    68 
       
    69     def GetRowLabelValues(self, row, translate=True):
       
    70         return row
       
    71 
       
    72     def GetValue(self, row, col):
       
    73         if row < self.GetNumberRows():
       
    74             colname = self.GetColLabelValue(col, False)
       
    75             name = str(self.data[row].get(colname, ""))
       
    76             if colname == "Type":
       
    77                 return _(name)
       
    78             return name
       
    79     
       
    80     def GetValueByName(self, row, colname):
       
    81         return self.data[row].get(colname)
       
    82 
       
    83     def SetValue(self, row, col, value):
       
    84         if col < len(self.colnames):
       
    85             colname = self.GetColLabelValue(col, False)
       
    86             if colname == "Type":
       
    87                 value = self.Parent.TranslateType[value]
       
    88             self.data[row][colname] = value
       
    89         
       
    90     def ResetView(self, grid):
       
    91         """
       
    92         (wx.Grid) -> Reset the grid view.   Call this to
       
    93         update the grid if rows and columns have been added or deleted
       
    94         """
       
    95         grid.BeginBatch()
       
    96         for current, new, delmsg, addmsg in [
       
    97             (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
       
    98             (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
       
    99         ]:
       
   100             if new < current:
       
   101                 msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
       
   102                 grid.ProcessTableMessage(msg)
       
   103             elif new > current:
       
   104                 msg = wx.grid.GridTableMessage(self,addmsg,new-current)
       
   105                 grid.ProcessTableMessage(msg)
       
   106                 self.UpdateValues(grid)
       
   107         grid.EndBatch()
       
   108 
       
   109         self._rows = self.GetNumberRows()
       
   110         self._cols = self.GetNumberCols()
       
   111         # update the column rendering scheme
       
   112         self._updateColAttrs(grid)
       
   113 
       
   114         # update the scrollbars and the displayed part of the grid
       
   115         grid.AdjustScrollbars()
       
   116         grid.ForceRefresh()
       
   117 
       
   118     def UpdateValues(self, grid):
       
   119         """Update all displayed values"""
       
   120         # This sends an event to the grid table to update all of the values
       
   121         msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
       
   122         grid.ProcessTableMessage(msg)
       
   123 
       
   124     def _updateColAttrs(self, grid):
       
   125         """
       
   126         wx.Grid -> update the column attributes to add the
       
   127         appropriate renderer given the column name.
       
   128 
       
   129         Otherwise default to the default renderer.
       
   130         """
       
   131         
       
   132         for row in range(self.GetNumberRows()):
       
   133             for col in range(self.GetNumberCols()):
       
   134                 editor = None
       
   135                 renderer = None
       
   136                 readonly = False
       
   137                 colname = self.GetColLabelValue(col, False)
       
   138                 if colname == "Qualifier":
       
   139                     editor = wx.grid.GridCellChoiceEditor()
       
   140                     editor.SetParameters(self.Parent.QualifierList)
       
   141                 if colname == "Duration":
       
   142                     editor = wx.grid.GridCellTextEditor()
       
   143                     renderer = wx.grid.GridCellStringRenderer()
       
   144                     if self.Parent.DurationList[self.data[row]["Qualifier"]]:
       
   145                         readonly = False
       
   146                     else:
       
   147                         readonly = True
       
   148                         self.data[row]["Duration"] = ""
       
   149                 elif colname == "Type":
       
   150                     editor = wx.grid.GridCellChoiceEditor()
       
   151                     editor.SetParameters(self.Parent.TypeList)
       
   152                 elif colname == "Value":
       
   153                     type = self.data[row]["Type"]
       
   154                     if type == "Action":
       
   155                         editor = wx.grid.GridCellChoiceEditor()
       
   156                         editor.SetParameters(self.Parent.ActionList)
       
   157                     elif type == "Variable":
       
   158                         editor = wx.grid.GridCellChoiceEditor()
       
   159                         editor.SetParameters(self.Parent.VariableList)
       
   160                     elif type == "Inline":
       
   161                         editor = wx.grid.GridCellTextEditor()
       
   162                         renderer = wx.grid.GridCellStringRenderer()
       
   163                 elif colname == "Indicator":
       
   164                     editor = wx.grid.GridCellChoiceEditor()
       
   165                     editor.SetParameters(self.Parent.VariableList)
       
   166                     
       
   167                 grid.SetCellEditor(row, col, editor)
       
   168                 grid.SetCellRenderer(row, col, renderer)
       
   169                 grid.SetReadOnly(row, col, readonly)
       
   170                 
       
   171                 grid.SetCellBackgroundColour(row, col, wx.WHITE)
       
   172     
       
   173     def SetData(self, data):
       
   174         self.data = data
       
   175     
       
   176     def GetData(self):
       
   177         return self.data
       
   178     
       
   179     def GetCurrentIndex(self):
       
   180         return self.CurrentIndex
       
   181     
       
   182     def SetCurrentIndex(self, index):
       
   183         self.CurrentIndex = index
       
   184     
       
   185     def AppendRow(self, row_content):
       
   186         self.data.append(row_content)
       
   187 
       
   188     def RemoveRow(self, row_index):
       
   189         self.data.pop(row_index)
       
   190         
       
   191     def MoveRow(self, row_index, move, grid):
       
   192         new_index = max(0, min(row_index + move, len(self.data) - 1))
       
   193         if new_index != row_index:
       
   194             self.data.insert(new_index, self.data.pop(row_index))
       
   195             grid.SetGridCursor(new_index, grid.GetGridCursorCol())
       
   196 
       
   197     def Empty(self):
       
   198         self.data = []
       
   199         self.editors = []
       
   200 
       
   201 [ID_ACTIONBLOCKDIALOG, ID_ACTIONBLOCKDIALOGVARIABLESGRID, 
       
   202  ID_ACTIONBLOCKDIALOGSTATICTEXT1, ID_ACTIONBLOCKDIALOGADDBUTTON,
       
   203  ID_ACTIONBLOCKDIALOGDELETEBUTTON, ID_ACTIONBLOCKDIALOGUPBUTTON, 
       
   204  ID_ACTIONBLOCKDIALOGDOWNBUTTON, 
       
   205 ] = [wx.NewId() for _init_ctrls in range(7)]
       
   206 
       
   207 class ActionBlockDialog(wx.Dialog):
       
   208     
       
   209     if wx.VERSION < (2, 6, 0):
       
   210         def Bind(self, event, function, id = None):
       
   211             if id is not None:
       
   212                 event(self, id, function)
       
   213             else:
       
   214                 event(self, function)
       
   215     
       
   216     def _init_coll_flexGridSizer1_Items(self, parent):
       
   217         parent.AddSizer(self.TopSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
       
   218         parent.AddSizer(self.GridButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT)
       
   219         parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
       
   220         
       
   221     def _init_coll_flexGridSizer1_Growables(self, parent):
       
   222         parent.AddGrowableCol(0)
       
   223         parent.AddGrowableRow(0)
       
   224         
       
   225     def _init_coll_TopSizer_Items(self, parent):
       
   226         parent.AddWindow(self.staticText1, 0, border=0, flag=wx.GROW)
       
   227         parent.AddWindow(self.ActionsGrid, 0, border=0, flag=wx.GROW)
       
   228     
       
   229     def _init_coll_TopSizer_Growables(self, parent):
       
   230         parent.AddGrowableCol(0)
       
   231         parent.AddGrowableRow(1)
       
   232 
       
   233     def _init_coll_GridButtonSizer_Items(self, parent):
       
   234         parent.AddWindow(self.AddButton, 0, border=10, flag=wx.GROW|wx.LEFT)
       
   235         parent.AddWindow(self.DeleteButton, 0, border=10, flag=wx.GROW|wx.LEFT)
       
   236         parent.AddWindow(self.UpButton, 0, border=10, flag=wx.GROW|wx.LEFT)
       
   237         parent.AddWindow(self.DownButton, 0, border=10, flag=wx.GROW|wx.LEFT)
       
   238 
       
   239     def _init_sizers(self):
       
   240         self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
       
   241         self.TopSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
       
   242         self.GridButtonSizer = wx.BoxSizer(wx.HORIZONTAL)
       
   243         
       
   244         self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
       
   245         self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
       
   246         self._init_coll_TopSizer_Items(self.TopSizer)
       
   247         self._init_coll_TopSizer_Growables(self.TopSizer)
       
   248         self._init_coll_GridButtonSizer_Items(self.GridButtonSizer)
       
   249         
       
   250         self.SetSizer(self.flexGridSizer1)
       
   251     
       
   252     def _init_ctrls(self, prnt):
       
   253         wx.Dialog.__init__(self, id=ID_ACTIONBLOCKDIALOG,
       
   254               name='ActionBlockDialog', parent=prnt, pos=wx.Point(376, 223),
       
   255               size=wx.Size(500, 300), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
       
   256               title=_('Edit action block properties'))
       
   257         self.SetClientSize(wx.Size(500, 300))
       
   258 
       
   259         self.staticText1 = wx.StaticText(id=ID_ACTIONBLOCKDIALOGSTATICTEXT1,
       
   260               label=_('Actions:'), name='staticText1', parent=self,
       
   261               pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0)
       
   262 
       
   263         self.ActionsGrid = wx.grid.Grid(id=ID_ACTIONBLOCKDIALOGVARIABLESGRID,
       
   264               name='ActionsGrid', parent=self, pos=wx.Point(0, 0), 
       
   265               size=wx.Size(0, 0), style=wx.VSCROLL)
       
   266         self.ActionsGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
       
   267               'Sans'))
       
   268         self.ActionsGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
       
   269               False, 'Sans'))
       
   270         self.ActionsGrid.DisableDragGridSize()
       
   271         self.ActionsGrid.EnableScrolling(False, True)
       
   272         self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnActionsGridCellChange)
       
   273 
       
   274         self.AddButton = wx.Button(id=ID_ACTIONBLOCKDIALOGADDBUTTON, label=_('Add'),
       
   275               name='AddButton', parent=self, pos=wx.Point(0, 0),
       
   276               size=wx.DefaultSize, style=0)
       
   277         self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_ACTIONBLOCKDIALOGADDBUTTON)
       
   278 
       
   279         self.DeleteButton = wx.Button(id=ID_ACTIONBLOCKDIALOGDELETEBUTTON, label=_('Delete'),
       
   280               name='DeleteButton', parent=self, pos=wx.Point(0, 0),
       
   281               size=wx.DefaultSize, style=0)
       
   282         self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_ACTIONBLOCKDIALOGDELETEBUTTON)
       
   283 
       
   284         self.UpButton = wx.Button(id=ID_ACTIONBLOCKDIALOGUPBUTTON, label='^',
       
   285               name='UpButton', parent=self, pos=wx.Point(0, 0),
       
   286               size=wx.Size(32, 32), style=0)
       
   287         self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_ACTIONBLOCKDIALOGUPBUTTON)
       
   288 
       
   289         self.DownButton = wx.Button(id=ID_ACTIONBLOCKDIALOGDOWNBUTTON, label='v',
       
   290               name='DownButton', parent=self, pos=wx.Point(0, 0),
       
   291               size=wx.Size(32, 32), style=0)
       
   292         self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_ACTIONBLOCKDIALOGDOWNBUTTON)
       
   293 
       
   294         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
       
   295         if wx.VERSION >= (2, 5, 0):
       
   296             self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
       
   297         else:
       
   298             self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
       
   299         
       
   300         self._init_sizers()
       
   301 
       
   302     def __init__(self, parent):
       
   303         self._init_ctrls(parent)
       
   304         
       
   305         self.DefaultValue = {"Qualifier" : "N", "Duration" : "", "Type" : "Action", "Value" : "", "Indicator" : ""}
       
   306         self.Table = ActionTable(self, [], GetActionTableColnames())
       
   307         typelist = GetTypeList()       
       
   308         self.TypeList = ",".join(map(_,typelist))
       
   309         self.TranslateType = dict([(_(value), value) for value in typelist])
       
   310         self.ColSizes = [60, 90, 80, 110, 80]
       
   311         self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
       
   312         
       
   313         self.ActionsGrid.SetTable(self.Table)
       
   314         self.ActionsGrid.SetRowLabelSize(0)
       
   315         
       
   316         for col in range(self.Table.GetNumberCols()):
       
   317             attr = wx.grid.GridCellAttr()
       
   318             attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
       
   319             self.ActionsGrid.SetColAttr(col, attr)
       
   320             self.ActionsGrid.SetColMinimalWidth(col, self.ColSizes[col])
       
   321             self.ActionsGrid.AutoSizeColumn(col, False)
       
   322         
       
   323         self.Table.ResetView(self.ActionsGrid)
       
   324 
       
   325     def OnOK(self, event):
       
   326         self.ActionsGrid.SetGridCursor(0, 0)
       
   327         self.EndModal(wx.ID_OK)
       
   328 
       
   329     def OnAddButton(self, event):
       
   330         self.Table.AppendRow(self.DefaultValue.copy())
       
   331         self.Table.ResetView(self.ActionsGrid)
       
   332         event.Skip()
       
   333 
       
   334     def OnDeleteButton(self, event):
       
   335         row = self.ActionsGrid.GetGridCursorRow()
       
   336         self.Table.RemoveRow(row)
       
   337         self.Table.ResetView(self.ActionsGrid)
       
   338         event.Skip()
       
   339 
       
   340     def OnUpButton(self, event):
       
   341         row = self.ActionsGrid.GetGridCursorRow()
       
   342         self.Table.MoveRow(row, -1, self.ActionsGrid)
       
   343         self.Table.ResetView(self.ActionsGrid)
       
   344         event.Skip()
       
   345 
       
   346     def OnDownButton(self, event):
       
   347         row = self.ActionsGrid.GetGridCursorRow()
       
   348         self.Table.MoveRow(row, 1, self.ActionsGrid)
       
   349         self.Table.ResetView(self.ActionsGrid)
       
   350         event.Skip()
       
   351 
       
   352     def OnActionsGridCellChange(self, event):
       
   353         self.Table.ResetView(self.ActionsGrid)
       
   354         event.Skip()
       
   355 
       
   356     def SetQualifierList(self, list):
       
   357         self.QualifierList = "," + ",".join(list)
       
   358         self.DurationList = list
       
   359 
       
   360     def SetVariableList(self, list):
       
   361         self.VariableList = "," + ",".join([variable["Name"] for variable in list])
       
   362         
       
   363     def SetActionList(self, list):
       
   364         self.ActionList = "," + ",".join(list)
       
   365 
       
   366     def SetValues(self, actions):
       
   367         for action in actions:
       
   368             row = {"Qualifier" : action["qualifier"], "Value" : action["value"]}
       
   369             if action["type"] == "reference":
       
   370                 if action["value"] in self.ActionList:
       
   371                     row["Type"] = "Action"
       
   372                 elif action["value"] in self.VariableList:
       
   373                     row["Type"] = "Variable"
       
   374                 else:
       
   375                     row["Type"] = "Inline"
       
   376             else:
       
   377                 row["Type"] = "Inline"
       
   378             if "duration" in action:
       
   379                 row["Duration"] = action["duration"]
       
   380             else:
       
   381                 row["Duration"] = ""
       
   382             if "indicator" in action:
       
   383                 row["Indicator"] = action["indicator"]
       
   384             else:
       
   385                 row["Indicator"] = ""
       
   386             self.Table.AppendRow(row)
       
   387         self.Table.ResetView(self.ActionsGrid)
       
   388     
       
   389     def GetValues(self):
       
   390         values = []
       
   391         for data in self.Table.GetData():
       
   392             action = {"qualifier" : data["Qualifier"], "value" : data["Value"]}
       
   393             if data["Type"] in ["Action", "Variable"]:
       
   394                 action["type"] = "reference"
       
   395             else:
       
   396                 action["type"] = "inline"
       
   397             if data["Duration"] != "":
       
   398                 action["duration"] = data["Duration"]
       
   399             if data["Indicator"] != "":
       
   400                 action["indicator"] = data["Indicator"]
       
   401             values.append(action)
       
   402         return values