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 lbessard@64: import wx.grid lbessard@27: laurent@564: from dialogs import DurationEditorDialog laurent@577: from controls import CustomGrid 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: lbessard@121: class ConfigurationEditor(wx.Panel): lbessard@121: lbessard@121: def _init_ctrls(self, prnt): lbessard@121: wx.Panel.__init__(self, id=ID_CONFIGURATIONEDITOR, name='', parent=prnt, lbessard@121: size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) lbessard@121: lbessard@121: def __init__(self, parent, tagname, window, controler): lbessard@121: self._init_ctrls(parent) lbessard@121: lbessard@121: self.ParentWindow = window lbessard@121: self.Controler = controler lbessard@121: self.TagName = tagname lbessard@121: lbessard@121: def SetTagName(self, tagname): lbessard@121: self.TagName = tagname lbessard@121: lbessard@121: def GetTagName(self): lbessard@121: return self.TagName lbessard@121: lbessard@121: def IsViewing(self, tagname): lbessard@121: return self.TagName == tagname lbessard@121: laurent@407: def IsDebugging(self): laurent@407: return False laurent@407: lbessard@121: def SetMode(self, mode): lbessard@121: pass lbessard@121: lbessard@121: def ResetBuffer(self): lbessard@121: pass lbessard@121: lbessard@121: def RefreshView(self): lbessard@121: pass lbessard@121: lbessard@145: def RefreshScaling(self, refresh=True): lbessard@145: pass lbessard@145: laurent@573: def ClearHighlights(self): lbessard@365: pass 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: lbessard@64: class ResourceTable(wx.grid.PyGridTableBase): 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* lbessard@64: wx.grid.PyGridTableBase.__init__(self) lbessard@27: self.data = data lbessard@27: self.colnames = colnames laurent@566: self.Highlights = {} lbessard@27: self.Parent = parent lbessard@27: lbessard@27: self.ColAlignements = [] lbessard@27: self.ColSizes = [] lbessard@27: # XXX lbessard@27: # we need to store the row length and collength to lbessard@27: # see if the table has changed size lbessard@27: self._rows = self.GetNumberRows() lbessard@27: self._cols = self.GetNumberCols() lbessard@27: 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 GetNumberCols(self): lbessard@27: return len(self.colnames) lbessard@27: lbessard@27: def GetNumberRows(self): lbessard@27: return len(self.data) lbessard@27: laurent@391: def GetColLabelValue(self, col, translate=True): lbessard@27: if col < len(self.colnames): laurent@391: if translate: laurent@391: return _(self.colnames[col]) lbessard@27: return self.colnames[col] lbessard@27: laurent@391: def GetRowLabelValues(self, row, translate=True): lbessard@27: return row 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 GetValueByName(self, row, colname): lbessard@27: return self.data[row].get(colname) lbessard@27: 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 SetValueByName(self, row, colname, value): lbessard@27: if colname in self.colnames: lbessard@27: self.data[row][colname] = value lbessard@27: lbessard@27: def ResetView(self, grid): lbessard@27: """ lbessard@64: (wx.grid.Grid) -> Reset the grid view. Call this to lbessard@27: update the grid if rows and columns have been added or deleted lbessard@27: """ lbessard@27: grid.BeginBatch() lbessard@27: for current, new, delmsg, addmsg in [ lbessard@64: (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), lbessard@64: (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED), lbessard@27: ]: lbessard@27: if new < current: lbessard@64: msg = wx.grid.GridTableMessage(self,delmsg,new,current-new) lbessard@27: grid.ProcessTableMessage(msg) lbessard@27: elif new > current: lbessard@64: msg = wx.grid.GridTableMessage(self,addmsg,new-current) lbessard@27: grid.ProcessTableMessage(msg) lbessard@27: self.UpdateValues(grid) lbessard@27: grid.EndBatch() lbessard@27: lbessard@27: self._rows = self.GetNumberRows() lbessard@27: self._cols = self.GetNumberCols() lbessard@27: # update the column rendering scheme lbessard@27: self._updateColAttrs(grid) lbessard@27: lbessard@27: # update the scrollbars and the displayed part of the grid lbessard@27: grid.AdjustScrollbars() lbessard@27: grid.ForceRefresh() lbessard@27: lbessard@27: def UpdateValues(self, grid): lbessard@27: """Update all displayed values""" lbessard@27: # This sends an event to the grid table to update all of the values lbessard@64: msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) lbessard@27: grid.ProcessTableMessage(msg) 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@560: if wx.Platform == '__WXMSW__': laurent@560: grid.SetRowMinimalHeight(row, 20) laurent@560: else: laurent@560: grid.SetRowMinimalHeight(row, 28) laurent@560: grid.AutoSizeRow(row, False) lbessard@27: lbessard@27: def SetData(self, data): lbessard@27: self.data = data lbessard@27: lbessard@27: def GetData(self): lbessard@27: return self.data lbessard@27: lbessard@27: def GetCurrentIndex(self): lbessard@27: return self.CurrentIndex lbessard@27: lbessard@27: def SetCurrentIndex(self, index): lbessard@27: self.CurrentIndex = index lbessard@27: lbessard@27: def AppendRow(self, row_content): lbessard@27: self.data.append(row_content) lbessard@27: laurent@560: def InsertRow(self, index, row_content): laurent@560: self.data.insert(index, row_content) laurent@560: lbessard@27: def RemoveRow(self, row_index): lbessard@27: self.data.pop(row_index) lbessard@27: laurent@560: def MoveRow(self, row_index, move): lbessard@27: new_index = max(0, min(row_index + move, len(self.data) - 1)) lbessard@27: if new_index != row_index: lbessard@27: self.data.insert(new_index, self.data.pop(row_index)) laurent@577: return new_index laurent@577: lbessard@27: def Empty(self): lbessard@27: self.data = [] 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: lbessard@64: [ID_RESOURCEEDITOR, ID_RESOURCEEDITORSTATICTEXT1, lbessard@64: ID_RESOURCEEDITORSTATICTEXT2, ID_RESOURCEEDITORINSTANCESGRID, lbessard@64: ID_RESOURCEEDITORTASKSGRID, ID_RESOURCEEDITORADDINSTANCEBUTTON, lbessard@64: ID_RESOURCEEDITORDELETEINSTANCEBUTTON, ID_RESOURCEEDITORUPINSTANCEBUTTON, lbessard@64: ID_RESOURCEEDITORDOWNINSTANCEBUTTON, ID_RESOURCEEDITORADDTASKBUTTON, lbessard@64: ID_RESOURCEEDITORDELETETASKBUTTON, ID_RESOURCEEDITORUPTASKBUTTON, lbessard@64: ID_RESOURCEEDITORDOWNTASKBUTTON, lbessard@27: ] = [wx.NewId() for _init_ctrls in range(13)] lbessard@27: lbessard@27: class ResourceEditor(wx.Panel): lbessard@27: lbessard@113: if wx.VERSION < (2, 6, 0): lbessard@113: def Bind(self, event, function, id = None): lbessard@113: if id is not None: lbessard@113: event(self, id, function) lbessard@113: else: lbessard@113: event(self, function) lbessard@113: lbessard@27: def _init_coll_InstancesSizer_Growables(self, parent): lbessard@27: parent.AddGrowableCol(0) lbessard@27: parent.AddGrowableRow(1) lbessard@27: lbessard@27: def _init_coll_InstancesSizer_Items(self, parent): lbessard@64: parent.AddSizer(self.InstancesButtonsSizer, 0, border=0, flag=wx.GROW) lbessard@64: parent.AddWindow(self.InstancesGrid, 0, border=0, flag=wx.GROW) lbessard@27: lbessard@27: def _init_coll_InstancesButtonsSizer_Growables(self, parent): lbessard@27: parent.AddGrowableCol(0) lbessard@27: parent.AddGrowableRow(0) lbessard@27: lbessard@27: def _init_coll_InstancesButtonsSizer_Items(self, parent): lbessard@64: parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_BOTTOM) lbessard@27: parent.AddWindow(self.AddInstanceButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.DeleteInstanceButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.UpInstanceButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.DownInstanceButton, 0, border=0, flag=0) lbessard@27: lbessard@27: def _init_coll_TasksSizer_Growables(self, parent): lbessard@27: parent.AddGrowableCol(0) lbessard@27: parent.AddGrowableRow(1) lbessard@27: lbessard@27: def _init_coll_TasksSizer_Items(self, parent): lbessard@64: parent.AddSizer(self.TasksButtonsSizer, 0, border=0, flag=wx.GROW) lbessard@64: parent.AddWindow(self.TasksGrid, 0, border=0, flag=wx.GROW) lbessard@27: lbessard@27: def _init_coll_TasksButtonsSizer_Growables(self, parent): lbessard@27: parent.AddGrowableCol(0) lbessard@27: parent.AddGrowableRow(0) lbessard@27: lbessard@27: def _init_coll_TasksButtonsSizer_Items(self, parent): lbessard@64: parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_BOTTOM) lbessard@27: parent.AddWindow(self.AddTaskButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.DeleteTaskButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.UpTaskButton, 0, border=0, flag=0) lbessard@27: parent.AddWindow(self.DownTaskButton, 0, border=0, flag=0) lbessard@27: lbessard@27: def _init_coll_MainGridSizer_Items(self, parent): lbessard@124: parent.AddSizer(self.TasksSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) lbessard@124: parent.AddSizer(self.InstancesSizer, 0, border=5, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) lbessard@27: lbessard@27: def _init_coll_MainGridSizer_Growables(self, parent): lbessard@27: parent.AddGrowableCol(0) lbessard@27: parent.AddGrowableRow(0) lbessard@27: parent.AddGrowableRow(1) lbessard@27: lbessard@27: def _init_sizers(self): lbessard@27: self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) lbessard@27: self.InstancesSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) lbessard@27: self.InstancesButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) lbessard@27: self.TasksSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) lbessard@27: self.TasksButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) lbessard@27: lbessard@27: self._init_coll_MainGridSizer_Growables(self.MainGridSizer) lbessard@27: self._init_coll_MainGridSizer_Items(self.MainGridSizer) lbessard@27: self._init_coll_InstancesSizer_Growables(self.InstancesSizer) lbessard@27: self._init_coll_InstancesSizer_Items(self.InstancesSizer) lbessard@27: self._init_coll_InstancesButtonsSizer_Growables(self.InstancesButtonsSizer) lbessard@27: self._init_coll_InstancesButtonsSizer_Items(self.InstancesButtonsSizer) lbessard@27: self._init_coll_TasksSizer_Growables(self.TasksSizer) lbessard@27: self._init_coll_TasksSizer_Items(self.TasksSizer) lbessard@27: self._init_coll_TasksButtonsSizer_Growables(self.TasksButtonsSizer) lbessard@27: self._init_coll_TasksButtonsSizer_Items(self.TasksButtonsSizer) lbessard@27: lbessard@27: self.SetSizer(self.MainGridSizer) lbessard@27: lbessard@27: def _init_ctrls(self, prnt): lbessard@64: wx.Panel.__init__(self, id=ID_RESOURCEEDITOR, name='', parent=prnt, lbessard@80: size=wx.Size(0, 0), style=wx.SUNKEN_BORDER) lbessard@27: lbessard@64: self.staticText1 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT1, laurent@391: label=_(u'Tasks:'), name='staticText2', parent=self, pos=wx.Point(0, laurent@391: 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) lbessard@64: laurent@577: self.TasksGrid = CustomGrid(id=ID_RESOURCEEDITORTASKSGRID, lbessard@27: name='TasksGrid', parent=self, pos=wx.Point(0, 0), lbessard@64: size=wx.Size(-1, -1), style=wx.VSCROLL) lbessard@27: self.TasksGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, lbessard@27: 'Sans')) lbessard@27: self.TasksGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, lbessard@27: False, 'Sans')) laurent@577: if wx.VERSION >= (2, 6, 0): lbessard@113: self.TasksGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnTasksGridCellChange) lbessard@113: else: lbessard@113: wx.grid.EVT_GRID_CELL_CHANGE(self.TasksGrid, self.OnTasksGridCellChange) lbessard@113: laurent@391: self.AddTaskButton = wx.Button(id=ID_RESOURCEEDITORADDTASKBUTTON, label=_('Add Task'), lbessard@27: name='AddTaskButton', parent=self, pos=wx.Point(0, 0), laurent@391: size=wx.DefaultSize, style=0) laurent@577: laurent@391: self.DeleteTaskButton = wx.Button(id=ID_RESOURCEEDITORDELETETASKBUTTON, label=_('Delete Task'), lbessard@27: name='DeleteTaskButton', parent=self, pos=wx.Point(0, 0), laurent@391: size=wx.DefaultSize, style=0) laurent@577: lbessard@64: self.UpTaskButton = wx.Button(id=ID_RESOURCEEDITORUPTASKBUTTON, label='^', lbessard@27: name='UpTaskButton', parent=self, pos=wx.Point(0, 0), lbessard@27: size=wx.Size(32, 32), style=0) laurent@577: lbessard@64: self.DownTaskButton = wx.Button(id=ID_RESOURCEEDITORDOWNTASKBUTTON, label='v', lbessard@27: name='DownTaskButton', parent=self, pos=wx.Point(0, 0), lbessard@27: size=wx.Size(32, 32), style=0) laurent@577: lbessard@64: self.staticText2 = wx.StaticText(id=ID_RESOURCEEDITORSTATICTEXT2, laurent@391: label=_(u'Instances:'), name='staticText1', parent=self, laurent@391: pos=wx.Point(0, 0), size=wx.DefaultSize, style=wx.ALIGN_CENTER) lbessard@64: laurent@577: self.InstancesGrid = CustomGrid(id=ID_RESOURCEEDITORINSTANCESGRID, lbessard@27: name='InstancesGrid', parent=self, pos=wx.Point(0, 0), lbessard@64: size=wx.Size(-1, -1), style=wx.VSCROLL) lbessard@27: self.InstancesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, lbessard@27: 'Sans')) lbessard@27: self.InstancesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, lbessard@27: False, 'Sans')) laurent@577: if wx.VERSION >= (2, 6, 0): lbessard@113: self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnInstancesGridCellChange) lbessard@113: else: lbessard@113: wx.grid.EVT_GRID_CELL_CHANGE(self.InstancesGrid, self.OnInstancesGridCellChange) lbessard@113: laurent@391: self.AddInstanceButton = wx.Button(id=ID_RESOURCEEDITORADDINSTANCEBUTTON, label=_('Add Instance'), lbessard@27: name='AddInstanceButton', parent=self, pos=wx.Point(0, 0), laurent@391: size=wx.DefaultSize, style=0) laurent@577: laurent@391: self.DeleteInstanceButton = wx.Button(id=ID_RESOURCEEDITORDELETEINSTANCEBUTTON, label=_('Delete Instance'), lbessard@27: name='DeleteInstanceButton', parent=self, pos=wx.Point(0, 0), laurent@391: size=wx.DefaultSize, style=0) laurent@577: lbessard@64: self.UpInstanceButton = wx.Button(id=ID_RESOURCEEDITORUPINSTANCEBUTTON, label='^', lbessard@27: name='UpInstanceButton', parent=self, pos=wx.Point(0, 0), lbessard@27: size=wx.Size(32, 32), style=0) laurent@577: lbessard@64: self.DownInstanceButton = wx.Button(id=ID_RESOURCEEDITORDOWNINSTANCEBUTTON, label='v', lbessard@27: name='DownInstanceButton', parent=self, pos=wx.Point(0, 0), lbessard@27: size=wx.Size(32, 32), style=0) laurent@577: lbessard@27: self._init_sizers() lbessard@27: lbessard@121: def __init__(self, parent, tagname, window, controler): lbessard@27: self._init_ctrls(parent) lbessard@27: lbessard@90: self.ParentWindow = window lbessard@27: self.Controler = controler lbessard@121: self.TagName = tagname 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@577: rows = self.InstancesTable.GetNumberRows() laurent@577: row = self.InstancesGrid.GetGridCursorRow() laurent@577: self.DeleteInstanceButton.Enable(rows > 0) laurent@577: self.UpInstanceButton.Enable(row > 0 and laurent@577: self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row - 1, "Task")) laurent@577: self.DownInstanceButton.Enable(0 <= row < rows - 1 and laurent@577: 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@121: def SetTagName(self, tagname): lbessard@121: self.TagName = tagname lbessard@121: lbessard@121: def GetTagName(self): lbessard@121: return self.TagName lbessard@121: lbessard@121: def IsViewing(self, tagname): lbessard@121: return self.TagName == tagname lbessard@121: laurent@407: def IsDebugging(self): laurent@407: return False laurent@407: lbessard@27: def SetMode(self, mode): lbessard@27: pass lbessard@27: 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: def ResetBuffer(self): lbessard@56: pass 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@577: def RefreshView(self): 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@145: def RefreshScaling(self, refresh=True): lbessard@145: pass laurent@577: lbessard@27: def OnTasksGridCellChange(self, event): lbessard@27: row, col = event.GetRow(), event.GetCol() lbessard@27: if self.TasksTable.GetColLabelValue(event.GetCol()) == "Name": lbessard@27: tasklist = self.TaskList.split(",") 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: tasklist.remove("") 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@560: if colname == "Triggering": laurent@560: wx.CallAfter(self.RefreshView) lbessard@27: event.Skip() lbessard@27: lbessard@27: def OnInstancesGridCellChange(self, event): lbessard@27: self.RefreshModel() lbessard@239: self.ParentWindow.RefreshInstancesTree() 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@566: laurent@566: def ClearHighlights(self, highlight_type=None): 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) laurent@564: laurent@564: class DurationCellControl(wx.PyControl): laurent@564: laurent@564: def _init_coll_MainSizer_Items(self, parent): laurent@564: parent.AddWindow(self.Duration, 0, border=0, flag=wx.GROW) laurent@564: parent.AddWindow(self.EditButton, 0, border=0, flag=wx.GROW) laurent@564: laurent@564: def _init_coll_MainSizer_Growables(self, parent): laurent@564: parent.AddGrowableCol(0) laurent@564: parent.AddGrowableRow(0) laurent@564: laurent@564: def _init_sizers(self): laurent@564: self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) laurent@564: laurent@564: self._init_coll_MainSizer_Items(self.MainSizer) laurent@564: self._init_coll_MainSizer_Growables(self.MainSizer) laurent@564: laurent@564: self.SetSizer(self.MainSizer) laurent@564: laurent@564: def _init_ctrls(self, prnt): laurent@564: wx.Control.__init__(self, id=-1, laurent@564: name='DurationCellControl', parent=prnt, laurent@564: size=wx.DefaultSize, style=0) laurent@564: laurent@564: # create location text control laurent@564: self.Duration = wx.TextCtrl(id=-1, name='Duration', parent=self, laurent@564: pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_PROCESS_ENTER) laurent@564: self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar) laurent@564: laurent@564: # create browse button laurent@564: self.EditButton = wx.Button(id=-1, label='...', laurent@564: name='EditButton', parent=self, pos=wx.Point(0, 0), laurent@564: size=wx.Size(30, 0), style=0) laurent@564: self.EditButton.Bind(wx.EVT_BUTTON, self.OnEditButtonClick) laurent@564: laurent@564: self.Bind(wx.EVT_SIZE, self.OnSize) laurent@564: laurent@564: self._init_sizers() laurent@564: laurent@564: ''' laurent@564: Custom cell editor control with a text box and a button that launches laurent@564: the DurationEditorDialog. laurent@564: ''' laurent@564: def __init__(self, parent): laurent@564: self._init_ctrls(parent) laurent@564: laurent@564: def SetValue(self, value): laurent@564: self.Duration.SetValue(value) laurent@564: laurent@564: def GetValue(self): laurent@564: return self.Duration.GetValue() laurent@564: laurent@564: def OnSize(self, event): laurent@564: self.Layout() laurent@564: laurent@564: def OnEditButtonClick(self, event): laurent@564: # pop up the Duration Editor dialog laurent@564: dialog = DurationEditorDialog(self) laurent@564: dialog.SetDuration(self.Duration.GetValue()) laurent@564: if dialog.ShowModal() == wx.ID_OK: laurent@564: # set the duration laurent@564: self.Duration.SetValue(dialog.GetDuration()) laurent@564: laurent@564: dialog.Destroy() laurent@564: laurent@564: self.Duration.SetFocus() laurent@564: laurent@564: def OnDurationChar(self, event): laurent@564: keycode = event.GetKeyCode() laurent@564: if keycode == wx.WXK_RETURN or keycode == wx.WXK_TAB: laurent@564: self.Parent.Parent.ProcessEvent(event) laurent@564: self.Parent.Parent.SetFocus() laurent@564: else: laurent@564: event.Skip() laurent@564: laurent@564: def SetInsertionPoint(self, i): laurent@564: self.Duration.SetInsertionPoint(i) laurent@564: laurent@564: def SetFocus(self): laurent@564: self.Duration.SetFocus() laurent@564: laurent@564: class DurationCellEditor(wx.grid.PyGridCellEditor): laurent@564: ''' laurent@564: Grid cell editor that uses DurationCellControl to display an edit button. laurent@564: ''' laurent@564: def __init__(self, table): laurent@564: wx.grid.PyGridCellEditor.__init__(self) laurent@564: self.Table = table laurent@564: laurent@564: def __del__(self): laurent@564: self.CellControl = None laurent@564: laurent@564: def Create(self, parent, id, evt_handler): laurent@564: self.CellControl = DurationCellControl(parent) laurent@564: self.SetControl(self.CellControl) laurent@564: if evt_handler: laurent@564: self.CellControl.PushEventHandler(evt_handler) laurent@564: laurent@564: def BeginEdit(self, row, col, grid): laurent@564: self.CellControl.SetValue(self.Table.GetValueByName(row, 'Interval')) laurent@564: self.CellControl.SetFocus() laurent@564: laurent@564: def EndEdit(self, row, col, grid): laurent@564: duration = self.CellControl.GetValue() laurent@564: old_duration = self.Table.GetValueByName(row, 'Interval') laurent@564: if duration != old_duration: laurent@564: self.Table.SetValueByName(row, 'Interval', duration) laurent@564: return True laurent@564: return False laurent@564: laurent@564: def SetSize(self, rect): laurent@564: self.CellControl.SetDimensions(rect.x + 1, rect.y, laurent@564: rect.width, rect.height, laurent@564: wx.SIZE_ALLOW_MINUS_ONE) laurent@564: laurent@564: def Clone(self): laurent@564: return DurationCellEditor(self.Table) laurent@564: