90 grid.SetCellTextColour(row, col, wx.BLUE) |
98 grid.SetCellTextColour(row, col, wx.BLUE) |
91 else: |
99 else: |
92 grid.SetCellTextColour(row, col, wx.BLACK) |
100 grid.SetCellTextColour(row, col, wx.BLACK) |
93 grid.SetReadOnly(row, col, True) |
101 grid.SetReadOnly(row, col, True) |
94 self.ResizeRow(grid, row) |
102 self.ResizeRow(grid, row) |
95 |
103 |
96 def AppendItem(self, data): |
104 def RefreshValues(self, grid): |
97 self.data.append(data) |
105 for col in xrange(self.GetNumberCols()): |
98 |
106 colname = self.GetColLabelValue(col, False) |
99 def InsertItem(self, idx, data): |
107 if colname == "Value": |
100 self.data.insert(idx, data) |
108 for row in xrange(self.GetNumberRows()): |
101 |
109 grid.SetCellValue(row, col, str(self.data[row].GetValue())) |
102 def RemoveItem(self, idx): |
110 if self.IsForced(row): |
103 self.data.pop(idx) |
111 grid.SetCellTextColour(row, col, wx.BLUE) |
|
112 else: |
|
113 grid.SetCellTextColour(row, col, wx.BLACK) |
|
114 |
|
115 def AppendItem(self, item): |
|
116 self.data.append(item) |
|
117 |
|
118 def InsertItem(self, idx, item): |
|
119 self.data.insert(idx, item) |
|
120 |
|
121 def RemoveItem(self, item): |
|
122 self.data.remove(item) |
104 |
123 |
105 def MoveItem(self, idx, new_idx): |
124 def MoveItem(self, idx, new_idx): |
106 self.data.insert(new_idx, self.data.pop(idx)) |
125 self.data.insert(new_idx, self.data.pop(idx)) |
107 |
126 |
108 def GetItem(self, idx): |
127 def GetItem(self, idx): |
109 return self.data[idx] |
128 return self.data[idx] |
110 |
129 |
|
130 |
|
131 #------------------------------------------------------------------------------- |
|
132 # Debug Variable Table Panel Drop Target |
|
133 #------------------------------------------------------------------------------- |
|
134 |
|
135 """ |
|
136 Class that implements a custom drop target class for Debug Variable Table Panel |
|
137 """ |
|
138 |
111 class DebugVariableTableDropTarget(wx.TextDropTarget): |
139 class DebugVariableTableDropTarget(wx.TextDropTarget): |
112 |
140 |
113 def __init__(self, parent): |
141 def __init__(self, parent): |
|
142 """ |
|
143 Constructor |
|
144 @param window: Reference to the Debug Variable Panel |
|
145 """ |
114 wx.TextDropTarget.__init__(self) |
146 wx.TextDropTarget.__init__(self) |
115 self.ParentWindow = parent |
147 self.ParentWindow = parent |
116 |
148 |
117 def __del__(self): |
149 def __del__(self): |
|
150 """ |
|
151 Destructor |
|
152 """ |
|
153 # Remove reference to Debug Variable Panel |
118 self.ParentWindow = None |
154 self.ParentWindow = None |
119 |
155 |
120 def OnDropText(self, x, y, data): |
156 def OnDropText(self, x, y, data): |
|
157 """ |
|
158 Function called when mouse is dragged over Drop Target |
|
159 @param x: X coordinate of mouse pointer |
|
160 @param y: Y coordinate of mouse pointer |
|
161 @param data: Text associated to drag'n drop |
|
162 """ |
121 message = None |
163 message = None |
122 try: |
164 try: |
123 values = eval(data) |
165 values = eval(data) |
|
166 if not isinstance(values, TupleType): |
|
167 raise ValueError |
124 except: |
168 except: |
125 message = _("Invalid value \"%s\" for debug variable")%data |
169 message = _("Invalid value \"%s\" for debug variable") % data |
126 values = None |
|
127 if not isinstance(values, TupleType): |
|
128 message = _("Invalid value \"%s\" for debug variable")%data |
|
129 values = None |
170 values = None |
130 |
171 |
131 if message is not None: |
172 if message is not None: |
132 wx.CallAfter(self.ShowMessage, message) |
173 wx.CallAfter(self.ShowMessage, message) |
133 elif values is not None and values[1] == "debug": |
174 |
|
175 elif values[1] == "debug": |
134 grid = self.ParentWindow.VariablesGrid |
176 grid = self.ParentWindow.VariablesGrid |
|
177 |
|
178 # Get row where variable was dropped |
135 x, y = grid.CalcUnscrolledPosition(x, y) |
179 x, y = grid.CalcUnscrolledPosition(x, y) |
136 row = grid.YToRow(y - grid.GetColLabelSize()) |
180 row = grid.YToRow(y - grid.GetColLabelSize()) |
|
181 |
|
182 # If no row found add variable at table end |
137 if row == wx.NOT_FOUND: |
183 if row == wx.NOT_FOUND: |
138 row = self.ParentWindow.Table.GetNumberRows() |
184 row = self.ParentWindow.Table.GetNumberRows() |
|
185 |
|
186 # Add variable to table |
139 self.ParentWindow.InsertValue(values[0], row, force=True) |
187 self.ParentWindow.InsertValue(values[0], row, force=True) |
140 |
188 |
141 def ShowMessage(self, message): |
189 def ShowMessage(self, message): |
142 dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) |
190 """ |
|
191 Show error message in Error Dialog |
|
192 @param message: Error message to display |
|
193 """ |
|
194 dialog = wx.MessageDialog(self.ParentWindow, |
|
195 message, |
|
196 _("Error"), |
|
197 wx.OK|wx.ICON_ERROR) |
143 dialog.ShowModal() |
198 dialog.ShowModal() |
144 dialog.Destroy() |
199 dialog.Destroy() |
145 |
200 |
|
201 |
|
202 #------------------------------------------------------------------------------- |
|
203 # Debug Variable Table Panel |
|
204 #------------------------------------------------------------------------------- |
|
205 |
|
206 """ |
|
207 Class that implements a panel displaying debug variable values in a table |
|
208 """ |
|
209 |
146 class DebugVariableTablePanel(wx.Panel, DebugViewer): |
210 class DebugVariableTablePanel(wx.Panel, DebugViewer): |
147 |
211 |
148 def __init__(self, parent, producer, window): |
212 def __init__(self, parent, producer, window): |
|
213 """ |
|
214 Constructor |
|
215 @param parent: Reference to the parent wx.Window |
|
216 @param producer: Object receiving debug value and dispatching them to |
|
217 consumers |
|
218 @param window: Reference to Beremiz frame |
|
219 """ |
149 wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) |
220 wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) |
150 |
221 |
|
222 # Save Reference to Beremiz frame |
151 self.ParentWindow = window |
223 self.ParentWindow = window |
152 |
224 |
|
225 # Variable storing flag indicating that variable displayed in table |
|
226 # received new value and then table need to be refreshed |
153 self.HasNewData = False |
227 self.HasNewData = False |
154 |
228 |
155 DebugViewer.__init__(self, producer, True) |
229 DebugViewer.__init__(self, producer, True) |
|
230 |
|
231 # Construction of window layout by creating controls and sizers |
156 |
232 |
157 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) |
233 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) |
158 main_sizer.AddGrowableCol(0) |
234 main_sizer.AddGrowableCol(0) |
159 main_sizer.AddGrowableRow(1) |
235 main_sizer.AddGrowableRow(1) |
160 |
236 |
161 button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
237 button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
162 main_sizer.AddSizer(button_sizer, border=5, |
238 main_sizer.AddSizer(button_sizer, border=5, |
163 flag=wx.ALIGN_RIGHT|wx.ALL) |
239 flag=wx.ALIGN_RIGHT|wx.ALL) |
|
240 |
|
241 # Creation of buttons for navigating in table |
164 |
242 |
165 for name, bitmap, help in [ |
243 for name, bitmap, help in [ |
166 ("DeleteButton", "remove_element", _("Remove debug variable")), |
244 ("DeleteButton", "remove_element", _("Remove debug variable")), |
167 ("UpButton", "up", _("Move debug variable up")), |
245 ("UpButton", "up", _("Move debug variable up")), |
168 ("DownButton", "down", _("Move debug variable down"))]: |
246 ("DownButton", "down", _("Move debug variable down"))]: |
169 button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), |
247 button = wx.lib.buttons.GenBitmapButton(self, |
|
248 bitmap=GetBitmap(bitmap), |
170 size=wx.Size(28, 28), style=wx.NO_BORDER) |
249 size=wx.Size(28, 28), style=wx.NO_BORDER) |
171 button.SetToolTipString(help) |
250 button.SetToolTipString(help) |
172 setattr(self, name, button) |
251 setattr(self, name, button) |
173 button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
252 button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
174 |
253 |
175 self.VariablesGrid = CustomGrid(self, size=wx.Size(-1, 150), style=wx.VSCROLL) |
254 # Creation of grid and associated table |
|
255 |
|
256 self.VariablesGrid = CustomGrid(self, |
|
257 size=wx.Size(-1, 150), style=wx.VSCROLL) |
|
258 # Define grid drop target |
176 self.VariablesGrid.SetDropTarget(DebugVariableTableDropTarget(self)) |
259 self.VariablesGrid.SetDropTarget(DebugVariableTableDropTarget(self)) |
177 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, |
260 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, |
178 self.OnVariablesGridCellRightClick) |
261 self.OnVariablesGridCellRightClick) |
179 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, |
262 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, |
180 self.OnVariablesGridCellLeftClick) |
263 self.OnVariablesGridCellLeftClick) |
181 main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) |
264 main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) |
182 |
265 |
183 self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames()) |
266 self.Table = DebugVariableTable(self, [], |
|
267 GetDebugVariablesTableColnames()) |
184 self.VariablesGrid.SetTable(self.Table) |
268 self.VariablesGrid.SetTable(self.Table) |
185 self.VariablesGrid.SetButtons({"Delete": self.DeleteButton, |
269 self.VariablesGrid.SetButtons({"Delete": self.DeleteButton, |
186 "Up": self.UpButton, |
270 "Up": self.UpButton, |
187 "Down": self.DownButton}) |
271 "Down": self.DownButton}) |
188 |
272 |
|
273 # Definition of function associated to navigation buttons |
|
274 |
189 def _AddVariable(new_row): |
275 def _AddVariable(new_row): |
190 return self.VariablesGrid.GetGridCursorRow() |
276 return self.VariablesGrid.GetGridCursorRow() |
191 setattr(self.VariablesGrid, "_AddRow", _AddVariable) |
277 setattr(self.VariablesGrid, "_AddRow", _AddVariable) |
192 |
278 |
193 def _DeleteVariable(row): |
279 def _DeleteVariable(row): |
194 item = self.Table.GetItem(row) |
280 item = self.Table.GetItem(row) |
195 self.RemoveDataConsumer(item) |
281 self.RemoveDataConsumer(item) |
196 self.Table.RemoveItem(row) |
282 self.Table.RemoveItem(item) |
197 self.RefreshView() |
283 self.RefreshView() |
198 setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) |
284 setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) |
199 |
285 |
200 def _MoveVariable(row, move): |
286 def _MoveVariable(row, move): |
201 new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1)) |
287 new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1)) |
219 self.VariablesGrid.RefreshButtons() |
307 self.VariablesGrid.RefreshButtons() |
220 |
308 |
221 self.SetSizer(main_sizer) |
309 self.SetSizer(main_sizer) |
222 |
310 |
223 def RefreshNewData(self, *args, **kwargs): |
311 def RefreshNewData(self, *args, **kwargs): |
|
312 """ |
|
313 Called to refresh Table according to values received by variables |
|
314 Can receive any parameters (not used here) |
|
315 """ |
|
316 # Refresh 'Value' column of table if new data have been received since |
|
317 # last refresh |
224 if self.HasNewData: |
318 if self.HasNewData: |
225 self.HasNewData = False |
319 self.HasNewData = False |
226 self.RefreshView(only_values=True) |
320 self.RefreshView(only_values=True) |
227 DebugViewer.RefreshNewData(self, *args, **kwargs) |
321 DebugViewer.RefreshNewData(self, *args, **kwargs) |
228 |
322 |
229 def RefreshView(self, only_values=False): |
323 def RefreshView(self, only_values=False): |
|
324 """ |
|
325 Function refreshing table layout and values |
|
326 @param only_values: True if only 'Value' column need to be updated |
|
327 """ |
|
328 # Block refresh until table layout and values are completely updated |
230 self.Freeze() |
329 self.Freeze() |
231 |
330 |
|
331 # Update only 'value' column from table |
232 if only_values: |
332 if only_values: |
233 for col in xrange(self.Table.GetNumberCols()): |
333 self.Table.RefreshValues(self.VariablesGrid) |
234 if self.Table.GetColLabelValue(col, False) == "Value": |
334 |
235 for row in xrange(self.Table.GetNumberRows()): |
335 # Update complete table layout refreshing table navigation buttons |
236 self.VariablesGrid.SetCellValue(row, col, str(self.Table.GetValueByName(row, "Value"))) |
336 # state according to |
237 if self.Table.IsForced(row): |
|
238 self.VariablesGrid.SetCellTextColour(row, col, wx.BLUE) |
|
239 else: |
|
240 self.VariablesGrid.SetCellTextColour(row, col, wx.BLACK) |
|
241 else: |
337 else: |
242 self.Table.ResetView(self.VariablesGrid) |
338 self.Table.ResetView(self.VariablesGrid) |
|
339 self.VariablesGrid.RefreshButtons() |
|
340 |
|
341 self.Thaw() |
|
342 |
|
343 def ResetView(self): |
|
344 """ |
|
345 Function removing all variables denugged from table |
|
346 @param only_values: True if only 'Value' column need to be updated |
|
347 """ |
|
348 # Unsubscribe all variables debugged |
|
349 self.UnsubscribeAllDataConsumers() |
|
350 |
|
351 # Clear table content |
|
352 self.Table.Empty() |
|
353 |
|
354 # Update table layout |
|
355 self.Freeze() |
|
356 self.Table.ResetView(self.VariablesGrid) |
243 self.VariablesGrid.RefreshButtons() |
357 self.VariablesGrid.RefreshButtons() |
244 |
|
245 self.Thaw() |
358 self.Thaw() |
246 |
359 |
247 def UnsubscribeObsoleteData(self): |
360 def SubscribeAllDataConsumers(self): |
248 self.SubscribeAllDataConsumers() |
361 """ |
249 |
362 Function refreshing table layout and values |
250 items = [(idx, item) for idx, item in enumerate(self.Table.GetData())] |
363 @param only_values: True if only 'Value' column need to be updated |
251 items.reverse() |
364 """ |
252 for idx, item in items: |
365 DebugViewer.SubscribeAllDataConsumers(self) |
|
366 |
|
367 # Navigate through variable displayed in table, removing those that |
|
368 # doesn't exist anymore in PLC |
|
369 for item in self.Table.GetData()[:]: |
253 iec_path = item.GetVariable() |
370 iec_path = item.GetVariable() |
254 if self.GetDataType(iec_path) is None: |
371 if self.GetDataType(iec_path) is None: |
255 self.RemoveDataConsumer(item) |
372 self.RemoveDataConsumer(item) |
256 self.Table.RemoveItem(idx) |
373 self.Table.RemoveItem(idx) |
257 else: |
374 else: |
258 self.AddDataConsumer(iec_path.upper(), item) |
375 self.AddDataConsumer(iec_path.upper(), item) |
259 item.RefreshVariableType() |
376 item.RefreshVariableType() |
|
377 |
|
378 # Update table layout |
260 self.Freeze() |
379 self.Freeze() |
261 self.Table.ResetView(self.VariablesGrid) |
380 self.Table.ResetView(self.VariablesGrid) |
262 self.VariablesGrid.RefreshButtons() |
381 self.VariablesGrid.RefreshButtons() |
263 self.Thaw() |
382 self.Thaw() |
264 |
383 |
265 def ResetView(self): |
384 def GetForceVariableMenuFunction(self, item): |
266 self.UnsubscribeAllDataConsumers() |
385 """ |
267 |
386 Function returning callback function for contextual menu 'Force' item |
268 self.Table.Empty() |
387 @param item: Debug Variable item where contextual menu was opened |
269 self.Freeze() |
388 @return: Callback function |
270 self.Table.ResetView(self.VariablesGrid) |
389 """ |
271 self.VariablesGrid.RefreshButtons() |
|
272 self.Thaw() |
|
273 |
|
274 def GetForceVariableMenuFunction(self, iec_path, item): |
|
275 iec_type = self.GetDataType(iec_path) |
|
276 def ForceVariableFunction(event): |
390 def ForceVariableFunction(event): |
277 if iec_type is not None: |
391 # Get variable path and data type |
278 dialog = ForceVariableDialog(self, iec_type, str(item.GetValue())) |
392 iec_path = item.GetVariable() |
279 if dialog.ShowModal() == wx.ID_OK: |
393 iec_type = self.GetDataType(iec_path) |
280 self.ForceDataValue(iec_path.upper(), dialog.GetValue()) |
394 |
|
395 # Return immediately if not data type found |
|
396 if iec_type is None: |
|
397 return |
|
398 |
|
399 # Open dialog for entering value to force variable |
|
400 dialog = ForceVariableDialog(self, iec_type, str(item.GetValue())) |
|
401 |
|
402 # If valid value entered, force variable |
|
403 if dialog.ShowModal() == wx.ID_OK: |
|
404 self.ForceDataValue(iec_path.upper(), dialog.GetValue()) |
|
405 |
281 return ForceVariableFunction |
406 return ForceVariableFunction |
282 |
407 |
283 def GetReleaseVariableMenuFunction(self, iec_path): |
408 def GetReleaseVariableMenuFunction(self, iec_path): |
|
409 """ |
|
410 Function returning callback function for contextual menu 'Release' item |
|
411 @param iec_path: Debug Variable path where contextual menu was opened |
|
412 @return: Callback function |
|
413 """ |
284 def ReleaseVariableFunction(event): |
414 def ReleaseVariableFunction(event): |
|
415 # Release variable |
285 self.ReleaseDataValue(iec_path) |
416 self.ReleaseDataValue(iec_path) |
286 return ReleaseVariableFunction |
417 return ReleaseVariableFunction |
287 |
418 |
288 def OnVariablesGridCellLeftClick(self, event): |
419 def OnVariablesGridCellLeftClick(self, event): |
289 if event.GetCol() == 0: |
420 """ |
290 row = event.GetRow() |
421 Called when left mouse button is pressed on a table cell |
291 data = wx.TextDataObject(str((self.Table.GetValueByName(row, "Variable"), "debug"))) |
422 @param event: wx.grid.GridEvent |
|
423 """ |
|
424 # Initiate a drag and drop if the cell clicked was in 'Variable' column |
|
425 if self.Table.GetColLabelValue(event.GetCol(), False) == "Variable": |
|
426 item = self.Table.GetItem(event.GetRow()) |
|
427 data = wx.TextDataObject(str((item.GetVariable(), "debug"))) |
292 dragSource = wx.DropSource(self.VariablesGrid) |
428 dragSource = wx.DropSource(self.VariablesGrid) |
293 dragSource.SetData(data) |
429 dragSource.SetData(data) |
294 dragSource.DoDragDrop() |
430 dragSource.DoDragDrop() |
|
431 |
295 event.Skip() |
432 event.Skip() |
296 |
433 |
297 def OnVariablesGridCellRightClick(self, event): |
434 def OnVariablesGridCellRightClick(self, event): |
298 row, col = event.GetRow(), event.GetCol() |
435 """ |
299 if self.Table.GetColLabelValue(col, False) == "Value": |
436 Called when right mouse button is pressed on a table cell |
300 iec_path = self.Table.GetValueByName(row, "Variable").upper() |
437 @param event: wx.grid.GridEvent |
301 |
438 """ |
|
439 # Open a contextual menu if the cell clicked was in 'Value' column |
|
440 if self.Table.GetColLabelValue(event.GetCol(), False) == "Value": |
|
441 row = event.GetRow() |
|
442 |
|
443 # Get variable path |
|
444 item = self.Table.GetItem(row) |
|
445 iec_path = item.GetVariable().upper() |
|
446 |
|
447 # Create contextual menu |
302 menu = wx.Menu(title='') |
448 menu = wx.Menu(title='') |
303 |
449 |
304 new_id = wx.NewId() |
450 # Add menu items |
305 menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Force value")) |
451 for text, enable, callback in [ |
306 self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction(iec_path.upper(), self.Table.GetItem(row)), id=new_id) |
452 (_("Force value"), True, |
307 |
453 self.GetForceVariableMenuFunction(item)), |
308 new_id = wx.NewId() |
454 # Release menu item is enabled only if variable is forced |
309 menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Release value")) |
455 (_("Release value"), self.Table.IsForced(row), |
310 self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), id=new_id) |
456 self.GetReleaseVariableMenuFunction(iec_path))]: |
311 |
457 |
312 if self.Table.IsForced(row): |
458 new_id = wx.NewId() |
313 menu.Enable(new_id, True) |
459 menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=text) |
314 else: |
460 menu.Enable(new_id, enable) |
315 menu.Enable(new_id, False) |
461 self.Bind(wx.EVT_MENU, callback, id=new_id) |
316 |
462 |
|
463 # Popup contextual menu |
317 self.PopupMenu(menu) |
464 self.PopupMenu(menu) |
318 |
465 |
319 menu.Destroy() |
466 menu.Destroy() |
320 event.Skip() |
467 event.Skip() |
321 |
468 |
322 def InsertValue(self, iec_path, idx = None, force=False): |
469 def InsertValue(self, iec_path, index=None, force=False): |
|
470 """ |
|
471 Insert a new variable to debug in table |
|
472 @param iec_path: Variable path to debug |
|
473 @param index: Row where insert the variable in table (default None, |
|
474 insert at last position) |
|
475 @param force: Force insertion of variable even if not defined in |
|
476 producer side |
|
477 """ |
|
478 # Return immediately if variable is already debugged |
323 for item in self.Table.GetData(): |
479 for item in self.Table.GetData(): |
324 if iec_path == item.GetVariable(): |
480 if iec_path == item.GetVariable(): |
325 return |
481 return |
326 if idx is None: |
482 |
327 idx = self.Table.GetNumberRows() |
483 # Insert at last position if index not defined |
|
484 if index is None: |
|
485 index = self.Table.GetNumberRows() |
|
486 |
|
487 # Subscribe variable to producer |
328 item = DebugVariableItem(self, iec_path) |
488 item = DebugVariableItem(self, iec_path) |
329 result = self.AddDataConsumer(iec_path.upper(), item) |
489 result = self.AddDataConsumer(iec_path.upper(), item) |
|
490 |
|
491 # Insert variable in table if subscription done or insertion forced |
330 if result is not None or force: |
492 if result is not None or force: |
331 self.Table.InsertItem(idx, item) |
493 self.Table.InsertItem(index, item) |
332 self.RefreshView() |
494 self.RefreshView() |
333 |
495 |
334 def ResetGraphicsValues(self): |
496 def ResetGraphicsValues(self): |
|
497 """ |
|
498 Called to reset graphics values when PLC is started |
|
499 (Nothing to do because no graphic values here. Defined for |
|
500 compatibility with Debug Variable Graphic Panel) |
|
501 """ |
335 pass |
502 pass |
336 |
503 |