lbessard@27: #!/usr/bin/env python lbessard@27: # -*- coding: utf-8 -*- lbessard@27: lbessard@27: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor lbessard@27: #based on the plcopen standard. lbessard@27: # lbessard@58: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD lbessard@27: # lbessard@27: #See COPYING file for copyrights details. lbessard@27: # lbessard@27: #This library is free software; you can redistribute it and/or lbessard@27: #modify it under the terms of the GNU General Public lbessard@27: #License as published by the Free Software Foundation; either lbessard@27: #version 2.1 of the License, or (at your option) any later version. lbessard@27: # lbessard@27: #This library is distributed in the hope that it will be useful, lbessard@27: #but WITHOUT ANY WARRANTY; without even the implied warranty of lbessard@27: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU lbessard@58: #General Public License for more details. lbessard@27: # lbessard@27: #You should have received a copy of the GNU General Public lbessard@27: #License along with this library; if not, write to the Free Software lbessard@27: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA lbessard@27: lbessard@27: import wx Laurent@714: import wx.lib.buttons lbessard@64: import wx.grid lbessard@27: laurent@586: from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD laurent@604: from controls import CustomGrid, CustomTable, EditorPanel, DurationCellEditor Laurent@714: from utils.BitmapLibrary import GetBitmap lbessard@121: lbessard@121: #------------------------------------------------------------------------------- lbessard@121: # Configuration Editor class lbessard@121: #------------------------------------------------------------------------------- lbessard@121: lbessard@121: [ID_CONFIGURATIONEDITOR, lbessard@121: ] = [wx.NewId() for _init_ctrls in range(1)] lbessard@121: laurent@586: class ConfigurationEditor(EditorPanel): laurent@586: laurent@586: ID = ID_CONFIGURATIONEDITOR laurent@586: VARIABLE_PANEL_TYPE = "config" laurent@586: laurent@586: def GetBufferState(self): laurent@586: return self.Controler.GetBufferState() laurent@586: laurent@586: def Undo(self): laurent@586: self.Controler.LoadPrevious() laurent@586: self.ParentWindow.CloseTabsWithoutModel() laurent@586: laurent@586: def Redo(self): laurent@586: self.Controler.LoadNext() laurent@586: self.ParentWindow.CloseTabsWithoutModel() laurent@586: laurent@586: def HasNoModel(self): laurent@586: return self.Controler.GetEditedElement(self.TagName) is None laurent@586: lbessard@365: lbessard@27: #------------------------------------------------------------------------------- lbessard@27: # Resource Editor class lbessard@27: #------------------------------------------------------------------------------- lbessard@27: laurent@391: def GetTasksTableColnames(): laurent@391: _ = lambda x : x laurent@560: return [_("Name"), _("Triggering"), _("Single"), _("Interval"), _("Priority")] laurent@560: laurent@560: def GetTaskTriggeringOptions(): laurent@560: _ = lambda x : x laurent@560: return [_("Interrupt"), _("Cyclic")] laurent@560: TASKTRIGGERINGOPTIONS_DICT = dict([(_(option), option) for option in GetTaskTriggeringOptions()]) laurent@391: laurent@391: def GetInstancesTableColnames(): laurent@391: _ = lambda x : x laurent@391: return [_("Name"), _("Type"), _("Task")] laurent@391: laurent@604: class ResourceTable(CustomTable): lbessard@27: lbessard@27: """ lbessard@64: A custom wx.grid.Grid Table using user supplied data lbessard@27: """ lbessard@27: def __init__(self, parent, data, colnames): lbessard@27: # The base class must be initialized *first* laurent@604: CustomTable.__init__(self, parent, data, colnames) lbessard@27: self.ColAlignements = [] lbessard@27: self.ColSizes = [] laurent@604: lbessard@27: def GetColAlignements(self): lbessard@27: return self.ColAlignements lbessard@27: lbessard@27: def SetColAlignements(self, list): lbessard@27: self.ColAlignements = list lbessard@27: lbessard@27: def GetColSizes(self): lbessard@27: return self.ColSizes lbessard@27: lbessard@27: def SetColSizes(self, list): lbessard@27: self.ColSizes = list lbessard@27: lbessard@27: def GetValue(self, row, col): lbessard@27: if row < self.GetNumberRows(): laurent@560: colname = self.GetColLabelValue(col, False) laurent@560: value = str(self.data[row].get(colname, "")) laurent@560: if colname == "Triggering": laurent@560: return _(value) laurent@560: return value laurent@560: lbessard@27: def SetValue(self, row, col, value): lbessard@27: if col < len(self.colnames): laurent@560: colname = self.GetColLabelValue(col, False) laurent@560: if colname == "Triggering": laurent@560: value = TASKTRIGGERINGOPTIONS_DICT[value] laurent@560: self.data[row][colname] = value lbessard@27: lbessard@27: def _updateColAttrs(self, grid): lbessard@27: """ lbessard@64: wx.grid.Grid -> update the column attributes to add the lbessard@27: appropriate renderer given the column name. lbessard@27: lbessard@27: Otherwise default to the default renderer. lbessard@27: """ lbessard@27: lbessard@27: for col in range(self.GetNumberCols()): lbessard@64: attr = wx.grid.GridCellAttr() lbessard@64: attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) lbessard@27: grid.SetColAttr(col, attr) lbessard@27: grid.SetColSize(col, self.ColSizes[col]) lbessard@27: lbessard@27: for row in range(self.GetNumberRows()): laurent@566: row_highlights = self.Highlights.get(row, {}) lbessard@27: for col in range(self.GetNumberCols()): lbessard@27: editor = None lbessard@27: renderer = None laurent@391: colname = self.GetColLabelValue(col, False) lbessard@27: grid.SetReadOnly(row, col, False) laurent@564: if colname == "Name": lbessard@64: editor = wx.grid.GridCellTextEditor() lbessard@64: renderer = wx.grid.GridCellStringRenderer() laurent@564: elif colname == "Interval": laurent@564: editor = DurationCellEditor(self) laurent@564: renderer = wx.grid.GridCellStringRenderer() laurent@564: if self.GetValueByName(row, "Triggering") != "Cyclic": lbessard@27: grid.SetReadOnly(row, col, True) lbessard@27: elif colname == "Single": lbessard@64: editor = wx.grid.GridCellChoiceEditor() lbessard@27: editor.SetParameters(self.Parent.VariableList) laurent@560: if self.GetValueByName(row, "Triggering") != "Interrupt": lbessard@27: grid.SetReadOnly(row, col, True) laurent@560: elif colname == "Triggering": laurent@560: editor = wx.grid.GridCellChoiceEditor() laurent@578: editor.SetParameters(",".join([""] + map(_, GetTaskTriggeringOptions()))) lbessard@27: elif colname == "Type": lbessard@64: editor = wx.grid.GridCellChoiceEditor() lbessard@27: editor.SetParameters(self.Parent.TypeList) lbessard@27: elif colname == "Priority": lbessard@64: editor = wx.grid.GridCellNumberEditor() lbessard@27: editor.SetParameters("0,65535") lbessard@27: elif colname == "Task": lbessard@64: editor = wx.grid.GridCellChoiceEditor() lbessard@27: editor.SetParameters(self.Parent.TaskList) lbessard@27: lbessard@27: grid.SetCellEditor(row, col, editor) lbessard@27: grid.SetCellRenderer(row, col, renderer) lbessard@27: laurent@566: highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] laurent@566: grid.SetCellBackgroundColour(row, col, highlight_colours[0]) laurent@566: grid.SetCellTextColour(row, col, highlight_colours[1]) laurent@604: self.ResizeRow(grid, row) laurent@604: laurent@577: laurent@566: #------------------------------------------------------------------------------- laurent@566: # Highlights showing functions laurent@566: #------------------------------------------------------------------------------- laurent@566: laurent@566: def AddHighlight(self, infos, highlight_type): laurent@566: row_highlights = self.Highlights.setdefault(infos[0], {}) laurent@566: col_highlights = row_highlights.setdefault(infos[1], []) laurent@566: col_highlights.append(highlight_type) laurent@577: laurent@566: def ClearHighlights(self, highlight_type=None): laurent@566: if highlight_type is None: laurent@566: self.Highlights = {} laurent@566: else: laurent@566: for row, row_highlights in self.Highlights.iteritems(): laurent@566: row_items = row_highlights.items() laurent@566: for col, col_highlights in row_items: laurent@566: if highlight_type in col_highlights: laurent@566: col_highlights.remove(highlight_type) laurent@566: if len(col_highlights) == 0: laurent@566: row_highlights.pop(col) lbessard@27: Laurent@714: laurent@586: laurent@586: class ResourceEditor(EditorPanel): laurent@586: laurent@586: VARIABLE_PANEL_TYPE = "resource" Laurent@714: Laurent@714: def _init_Editor(self, parent): Laurent@714: self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL) Laurent@714: Laurent@714: main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) Laurent@714: main_sizer.AddGrowableCol(0) Laurent@714: main_sizer.AddGrowableRow(0) Laurent@714: main_sizer.AddGrowableRow(1) Laurent@714: Laurent@714: tasks_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) Laurent@714: tasks_sizer.AddGrowableCol(0) Laurent@714: tasks_sizer.AddGrowableRow(1) Laurent@714: main_sizer.AddSizer(tasks_sizer, border=5, Laurent@714: flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) Laurent@714: Laurent@714: tasks_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) Laurent@714: tasks_buttons_sizer.AddGrowableCol(0) Laurent@714: tasks_buttons_sizer.AddGrowableRow(0) Laurent@714: tasks_sizer.AddSizer(tasks_buttons_sizer, flag=wx.GROW) Laurent@714: Laurent@714: tasks_label = wx.StaticText(self.Editor, label=_(u'Tasks:')) Laurent@714: tasks_buttons_sizer.AddWindow(tasks_label, flag=wx.ALIGN_BOTTOM) Laurent@714: Laurent@714: for name, bitmap, help in [ Laurent@714: ("AddTaskButton", "add_element", _("Add task")), Laurent@714: ("DeleteTaskButton", "remove_element", _("Remove task")), Laurent@714: ("UpTaskButton", "up", _("Move task up")), Laurent@714: ("DownTaskButton", "down", _("Move task down"))]: Laurent@714: button = wx.lib.buttons.GenBitmapButton(self.Editor, Laurent@714: bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) Laurent@714: button.SetToolTipString(help) Laurent@714: setattr(self, name, button) Laurent@714: tasks_buttons_sizer.AddWindow(button) Laurent@714: Laurent@714: self.TasksGrid = CustomGrid(self.Editor, style=wx.VSCROLL) Laurent@714: self.TasksGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnTasksGridCellChange) Laurent@714: tasks_sizer.AddWindow(self.TasksGrid, flag=wx.GROW) Laurent@714: Laurent@714: instances_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) Laurent@714: instances_sizer.AddGrowableCol(0) Laurent@714: instances_sizer.AddGrowableRow(1) Laurent@714: main_sizer.AddSizer(instances_sizer, border=5, Laurent@714: flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) Laurent@714: Laurent@714: instances_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) Laurent@714: instances_buttons_sizer.AddGrowableCol(0) Laurent@714: instances_buttons_sizer.AddGrowableRow(0) Laurent@714: instances_sizer.AddSizer(instances_buttons_sizer, flag=wx.GROW) Laurent@714: Laurent@714: instances_label = wx.StaticText(self.Editor, label=_(u'Instances:')) Laurent@714: instances_buttons_sizer.AddWindow(instances_label, flag=wx.ALIGN_BOTTOM) Laurent@714: Laurent@714: for name, bitmap, help in [ Laurent@714: ("AddInstanceButton", "add_element", _("Add instance")), Laurent@714: ("DeleteInstanceButton", "remove_element", _("Remove instance")), Laurent@714: ("UpInstanceButton", "up", _("Move instance up")), Laurent@714: ("DownInstanceButton", "down", _("Move instance down"))]: Laurent@714: button = wx.lib.buttons.GenBitmapButton(self.Editor, Laurent@714: bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) Laurent@714: button.SetToolTipString(help) Laurent@714: setattr(self, name, button) Laurent@714: instances_buttons_sizer.AddWindow(button) Laurent@714: Laurent@714: self.InstancesGrid = CustomGrid(self.Editor, style=wx.VSCROLL) Laurent@714: self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, Laurent@714: self.OnInstancesGridCellChange) Laurent@714: instances_sizer.AddWindow(self.InstancesGrid, flag=wx.GROW) Laurent@714: Laurent@714: self.Editor.SetSizer(main_sizer) Laurent@714: lbessard@121: def __init__(self, parent, tagname, window, controler): laurent@586: EditorPanel.__init__(self, parent, tagname, window, controler) lbessard@27: laurent@566: self.RefreshHighlightsTimer = wx.Timer(self, -1) laurent@566: self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) laurent@566: laurent@560: self.TasksDefaultValue = {"Name" : "", "Triggering" : "", "Single" : "", "Interval" : "", "Priority" : 0} laurent@391: self.TasksTable = ResourceTable(self, [], GetTasksTableColnames()) laurent@560: self.TasksTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT]) laurent@564: self.TasksTable.SetColSizes([200, 100, 100, 150, 100]) lbessard@27: self.TasksGrid.SetTable(self.TasksTable) laurent@577: self.TasksGrid.SetButtons({"Add": self.AddTaskButton, laurent@577: "Delete": self.DeleteTaskButton, laurent@577: "Up": self.UpTaskButton, laurent@577: "Down": self.DownTaskButton}) laurent@577: laurent@577: def _AddTask(new_row): laurent@577: self.TasksTable.InsertRow(new_row, self.TasksDefaultValue.copy()) laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: return new_row laurent@577: setattr(self.TasksGrid, "_AddRow", _AddTask) laurent@577: laurent@577: def _DeleteTask(row): laurent@577: self.TasksTable.RemoveRow(row) laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: setattr(self.TasksGrid, "_DeleteRow", _DeleteTask) laurent@577: laurent@577: def _MoveTask(row, move): laurent@577: new_row = self.TasksTable.MoveRow(row, move) laurent@577: if new_row != row: laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: return new_row laurent@577: setattr(self.TasksGrid, "_MoveRow", _MoveTask) laurent@577: lbessard@27: self.TasksGrid.SetRowLabelSize(0) lbessard@27: self.TasksTable.ResetView(self.TasksGrid) laurent@577: self.TasksGrid.RefreshButtons() laurent@577: lbessard@27: self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""} laurent@391: self.InstancesTable = ResourceTable(self, [], GetInstancesTableColnames()) lbessard@64: self.InstancesTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]) lbessard@27: self.InstancesTable.SetColSizes([200, 150, 150]) lbessard@27: self.InstancesGrid.SetTable(self.InstancesTable) laurent@577: self.InstancesGrid.SetButtons({"Add": self.AddInstanceButton, laurent@577: "Delete": self.DeleteInstanceButton, laurent@577: "Up": self.UpInstanceButton, laurent@577: "Down": self.DownInstanceButton}) laurent@577: laurent@577: def _AddInstance(new_row): laurent@577: self.InstancesTable.InsertRow(new_row, self.InstancesDefaultValue.copy()) laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: return new_row laurent@577: setattr(self.InstancesGrid, "_AddRow", _AddInstance) laurent@577: laurent@577: def _DeleteInstance(row): laurent@577: self.InstancesTable.RemoveRow(row) laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: setattr(self.InstancesGrid, "_DeleteRow", _DeleteInstance) laurent@577: laurent@577: def _MoveInstance(row, move): laurent@577: new_row = max(0, min(row + move, self.InstancesTable.GetNumberRows() - 1)) laurent@577: if new_row != row: laurent@577: if self.InstancesTable.GetValueByName(row, "Task") != self.InstancesTable.GetValueByName(new_row, "Task"): laurent@577: return row laurent@577: self.InstancesTable.MoveRow(row, move) laurent@577: self.RefreshModel() laurent@577: self.RefreshView() laurent@577: return new_row laurent@577: setattr(self.InstancesGrid, "_MoveRow", _MoveInstance) laurent@577: laurent@577: def _RefreshInstanceButtons(): laurent@672: if self: laurent@672: rows = self.InstancesTable.GetNumberRows() laurent@672: row = self.InstancesGrid.GetGridCursorRow() laurent@672: self.DeleteInstanceButton.Enable(rows > 0) laurent@672: self.UpInstanceButton.Enable(row > 0 and laurent@672: self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row - 1, "Task")) laurent@672: self.DownInstanceButton.Enable(0 <= row < rows - 1 and laurent@672: self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row + 1, "Task")) laurent@577: setattr(self.InstancesGrid, "RefreshButtons", _RefreshInstanceButtons) laurent@577: lbessard@27: self.InstancesGrid.SetRowLabelSize(0) lbessard@27: self.InstancesTable.ResetView(self.InstancesGrid) laurent@577: self.InstancesGrid.RefreshButtons() laurent@577: laurent@577: self.TasksGrid.SetFocus() laurent@577: laurent@566: def __del__(self): laurent@566: self.RefreshHighlightsTimer.Stop() laurent@566: lbessard@27: def RefreshTypeList(self): lbessard@27: self.TypeList = "" lbessard@27: blocktypes = self.Controler.GetBlockResource() lbessard@27: for blocktype in blocktypes: lbessard@27: self.TypeList += ",%s"%blocktype lbessard@27: lbessard@27: def RefreshTaskList(self): lbessard@27: self.TaskList = "" lbessard@27: for row in xrange(self.TasksTable.GetNumberRows()): lbessard@27: self.TaskList += ",%s"%self.TasksTable.GetValueByName(row, "Name") lbessard@27: lbessard@27: def RefreshVariableList(self): lbessard@27: self.VariableList = "" lbessard@121: for variable in self.Controler.GetEditedResourceVariables(self.TagName): lbessard@27: self.VariableList += ",%s"%variable lbessard@27: lbessard@27: def RefreshModel(self): lbessard@121: self.Controler.SetEditedResourceInfos(self.TagName, self.TasksTable.GetData(), self.InstancesTable.GetData()) lbessard@56: self.RefreshBuffer() lbessard@56: lbessard@56: # Buffer the last model state lbessard@56: def RefreshBuffer(self): lbessard@56: self.Controler.BufferProject() lbessard@90: self.ParentWindow.RefreshTitle() laurent@494: self.ParentWindow.RefreshFileMenu() lbessard@90: self.ParentWindow.RefreshEditMenu() lbessard@27: laurent@586: def GetBufferState(self): laurent@586: return self.Controler.GetBufferState() laurent@586: laurent@586: def Undo(self): laurent@586: self.Controler.LoadPrevious() laurent@586: self.ParentWindow.CloseTabsWithoutModel() laurent@586: laurent@586: def Redo(self): laurent@586: self.Controler.LoadNext() laurent@586: self.ParentWindow.CloseTabsWithoutModel() laurent@586: laurent@586: def HasNoModel(self): laurent@586: return self.Controler.GetEditedElement(self.TagName) is None laurent@586: laurent@586: def RefreshView(self, variablepanel=True): laurent@586: EditorPanel.RefreshView(self, variablepanel) laurent@586: lbessard@121: tasks, instances = self.Controler.GetEditedResourceInfos(self.TagName) lbessard@27: self.TasksTable.SetData(tasks) lbessard@27: self.InstancesTable.SetData(instances) lbessard@27: self.RefreshTypeList() lbessard@27: self.RefreshTaskList() lbessard@27: self.RefreshVariableList() laurent@560: self.TasksTable.ResetView(self.TasksGrid) lbessard@27: self.InstancesTable.ResetView(self.InstancesGrid) laurent@577: self.TasksGrid.RefreshButtons() laurent@577: self.InstancesGrid.RefreshButtons() laurent@560: lbessard@27: def OnTasksGridCellChange(self, event): lbessard@27: row, col = event.GetRow(), event.GetCol() laurent@588: if self.TasksTable.GetColLabelValue(col) == "Name": laurent@588: tasklist = [name for name in self.TaskList.split(",") if name != ""] lbessard@27: for i in xrange(self.TasksTable.GetNumberRows()): lbessard@27: task = self.TasksTable.GetValueByName(i, "Name") lbessard@27: if task in tasklist: lbessard@27: tasklist.remove(task) lbessard@27: if len(tasklist) > 0: lbessard@27: old_name = tasklist[0] lbessard@27: new_name = self.TasksTable.GetValue(row, col) lbessard@27: for i in xrange(self.InstancesTable.GetNumberRows()): lbessard@27: if self.InstancesTable.GetValueByName(i, "Task") == old_name: lbessard@27: self.InstancesTable.SetValueByName(i, "Task", new_name) lbessard@27: self.RefreshModel() laurent@560: colname = self.TasksTable.GetColLabelValue(col, False) laurent@588: if colname in ["Triggering", "Name"]: laurent@655: wx.CallAfter(self.RefreshView, False) lbessard@27: event.Skip() lbessard@27: lbessard@27: def OnInstancesGridCellChange(self, event): lbessard@27: self.RefreshModel() laurent@684: self.ParentWindow.RefreshPouInstanceVariablesPanel() laurent@577: self.InstancesGrid.RefreshButtons() lbessard@27: event.Skip() lbessard@231: lbessard@231: #------------------------------------------------------------------------------- laurent@566: # Highlights showing functions laurent@566: #------------------------------------------------------------------------------- laurent@573: laurent@573: def OnRefreshHighlightsTimer(self, event): laurent@573: self.RefreshView() laurent@573: event.Skip() laurent@573: laurent@566: def AddHighlight(self, infos, start, end, highlight_type): lbessard@231: if infos[0] == "task": laurent@566: self.TasksTable.AddHighlight(infos[1:], highlight_type) lbessard@231: elif infos[0] == "instance": laurent@566: self.InstancesTable.AddHighlight(infos[1:], highlight_type) laurent@586: self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) laurent@566: laurent@566: def ClearHighlights(self, highlight_type=None): laurent@586: EditorPanel.ClearHighlights(self, highlight_type) laurent@586: laurent@566: self.TasksTable.ClearHighlights(highlight_type) laurent@566: self.InstancesTable.ClearHighlights(highlight_type) laurent@566: self.TasksTable.ResetView(self.TasksGrid) laurent@566: self.InstancesTable.ResetView(self.InstancesGrid)