bct (owner)

Revisions

gist: 181104 Download_button fork
public
Public Clone URL: git://gist.github.com/181104.git
Embed All Files: show embed
Python #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# This is a stripped-down wxPython program with a custom wxPyGridCellEditor that
# crashes on my machine (wxPython 2.8.10.1 with Python 2.5 on Windows XP).
#
# I can make the program crash in two ways, I'm not sure they're related.
# Short way:
# 1. Edit the first row's "Class" field. You should get a drop-down with "Local"
# and "Temp".
# 2. Select a value from the drop-down. The program crashes.
#
# Long way:
# 1. Edit the first row's "Location" field. You should see a text area with a
# button in the cell.
# 2. Close that cell editor (click somewhere else in the screen).
# 3. Edit the first row's "Type" field. You should get a menu.
# 4. Select a value from the menu.
# 5. The program crashes.
#
#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 wx, wx.grid
 
from types import TupleType
 
# these are mock values
 
# Compatibility function for wx versions < 2.6
def AppendMenu(parent, help, id, kind, text):
    if wx.VERSION >= (2, 6, 0):
        parent.Append(help=help, id=id, kind=kind, text=text)
    else:
        parent.Append(helpString=help, id=id, kind=kind, item=text)
 
LOCATIONDATATYPES = {"X" : ["BOOL"],
                     "B" : ["SINT", "USINT", "BYTE", "STRING"],
                     "W" : ["INT", "UINT", "WORD", "WSTRING"],
                     "D" : ["DINT", "UDINT", "REAL", "DWORD"],
                     "L" : ["LINT", "ULINT", "LREAL", "LWORD"]}
 
IEC_KEYWORDS = []
 
def TestIdentifier(identifier):
    return True
 
def _(x):
    return x
 
#-------------------------------------------------------------------------------
# Variables Editor Panel
#-------------------------------------------------------------------------------
 
def GetFilterChoiceTransfer():
    _ = lambda x : x
    return {_("All"): _("All"), _("Interface"): _("Interface"),
            _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"),
            _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"),
            _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")}
VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()])
 
class VariableTable(wx.grid.PyGridTableBase):
    
    """
A custom wx.grid.Grid Table using user supplied data
"""
    def __init__(self, parent, data):
        # The base class must be initialized *first*
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data
        self.old_value = None
        self.colnames = ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value")]
        self.Parent = parent
        # XXX
        # we need to store the row length and collength to
        # see if the table has changed size
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()
    
    def GetNumberCols(self):
        return len(self.colnames)
        
    def GetNumberRows(self):
        return len(self.data)
 
    def GetColLabelValue(self, col, translate=True):
        if col < len(self.colnames):
            if translate:
                return _(self.colnames[col])
            return self.colnames[col]
 
    def GetRowLabelValues(self, row, translate=True):
        return row
 
    def GetValue(self, row, col):
        if row < self.GetNumberRows():
            if col == 0:
                return self.data[row]["Number"]
            colname = self.GetColLabelValue(col, False)
            value = str(self.data[row].get(colname, ""))
            if colname == "Class":
                return _(value)
            return value
    
    def SetValue(self, row, col, value):
        if col < len(self.colnames):
            colname = self.GetColLabelValue(col, False)
            if colname == "Name":
                self.old_value = self.data[row][colname]
            elif colname == "Class":
                value = VARIABLE_CLASSES_DICT[value]
            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 ResetView(self, grid):
        """
(wx.grid.Grid) -> Reset the grid view. Call this to
update the grid if rows and columns have been added or deleted
"""
        grid.BeginBatch()
        for current, new, delmsg, addmsg in [
            (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
            (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
        ]:
            if new < current:
                msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
                grid.ProcessTableMessage(msg)
            elif new > current:
                msg = wx.grid.GridTableMessage(self,addmsg,new-current)
                grid.ProcessTableMessage(msg)
                self.UpdateValues(grid)
        grid.EndBatch()
 
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()
        # update the column rendering scheme
        self._updateColAttrs(grid)
 
        # update the scrollbars and the displayed part of the grid
        grid.AdjustScrollbars()
        grid.ForceRefresh()
 
    def UpdateValues(self, grid):
        """Update all displayed values"""
        # This sends an event to the grid table to update all of the values
        msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
        grid.ProcessTableMessage(msg)
 
    def _updateColAttrs(self, grid):
        """
wx.grid.Grid -> update the column attributes to add the
appropriate renderer given the column name.
 
Otherwise default to the default renderer.
"""
        
        for row in range(self.GetNumberRows()):
            for col in range(self.GetNumberCols()):
                editor = None
                renderer = None
                colname = self.GetColLabelValue(col, False)
 
                if col != 0 and self.GetValueByName(row, "Edit"):
                    grid.SetReadOnly(row, col, False)
                    if colname == "Name":
                        editor = wx.grid.GridCellTextEditor()
                        renderer = wx.grid.GridCellStringRenderer()
                    elif colname == "Initial Value":
                        editor = wx.grid.GridCellTextEditor()
                        renderer = wx.grid.GridCellStringRenderer()
                    elif colname == "Location":
                        #editor = wx.grid.GridCellTextEditor()
                        editor = LocationCellEditor(self)
                        renderer = wx.grid.GridCellStringRenderer()
                    elif colname == "Class":
                        editor = wx.grid.GridCellChoiceEditor()
                        editor.SetParameters(",".join(["Local", "Temp"]))
                    elif colname == "Type":
                        editor = wx.grid.GridCellTextEditor()
                else:
                    grid.SetReadOnly(row, col, True)
                
                grid.SetCellEditor(row, col, editor)
                grid.SetCellRenderer(row, col, renderer)
                
    def SetData(self, data):
        self.data = data
    
    def GetRow(self, row_index):
        return self.data[row_index]
 
[ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID,
 ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE,
 ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON,
 ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON,
 ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1,
 ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3,
] = [wx.NewId() for _init_ctrls in range(12)]
 
class VariablePanel(wx.Panel):
    
    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_MainSizer_Items(self, parent):
        parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
    
    def _init_coll_MainSizer_Growables(self, parent):
        parent.AddGrowableCol(0)
        parent.AddGrowableRow(0)
    
    def _init_sizers(self):
        self.MainSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=0)
        
        self._init_coll_MainSizer_Items(self.MainSizer)
        self._init_coll_MainSizer_Growables(self.MainSizer)
        
        self.SetSizer(self.MainSizer)
 
    def _init_ctrls(self, prnt):
        wx.Panel.__init__(self, id=ID_VARIABLEEDITORPANEL,
              name='VariableEditorPanel', parent=prnt, pos=wx.Point(0, 0),
              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
 
        self.VariablesGrid = wx.grid.Grid(id=ID_VARIABLEEDITORPANELVARIABLESGRID,
              name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
              size=wx.Size(0, 0), 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.SetSelectionBackground(wx.WHITE)
        self.VariablesGrid.SetSelectionForeground(wx.BLACK)
 
        if wx.VERSION >= (2, 6, 0):
            self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
            self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
        else:
            wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
            wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
        
        self._init_sizers()
 
    def __init__(self, parent):
        self._init_ctrls(parent)
        self.ParentWindow = parent
 
        self.Table = VariableTable(self, [])
 
        self.VariablesGrid.SetTable(self.Table)
        self.VariablesGrid.SetRowLabelSize(0)
 
        for col in range(self.Table.GetNumberCols()):
            self.VariablesGrid.AutoSizeColumn(col, False)
    
        # add a new row for testing
        new_row = {"Name" : "", "Class" : "Local", "Type" : "INT", "Location" : "", "Initial Value" : "", "Edit" : True}
 
        row_index = -1
        self.Values = [new_row]
 
        self.RefreshValues(row_index)
    
    def OnVariablesGridCellChange(self, event):
        row, col = event.GetRow(), event.GetCol()
        colname = self.Table.GetColLabelValue(col)
        value =