--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/editors/ResourceEditor.py Fri Sep 07 16:45:55 2012 +0200
@@ -0,0 +1,465 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#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
+import wx.lib.buttons
+import wx.grid
+
+from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD
+from controls import CustomGrid, CustomTable, DurationCellEditor
+from EditorPanel import EditorPanel
+from util.BitmapLibrary import GetBitmap
+
+#-------------------------------------------------------------------------------
+# Configuration Editor class
+#-------------------------------------------------------------------------------
+
+[ID_CONFIGURATIONEDITOR,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+class ConfigurationEditor(EditorPanel):
+
+ ID = ID_CONFIGURATIONEDITOR
+ VARIABLE_PANEL_TYPE = "config"
+
+ def GetBufferState(self):
+ return self.Controler.GetBufferState()
+
+ def Undo(self):
+ self.Controler.LoadPrevious()
+ self.ParentWindow.CloseTabsWithoutModel()
+
+ def Redo(self):
+ self.Controler.LoadNext()
+ self.ParentWindow.CloseTabsWithoutModel()
+
+ def HasNoModel(self):
+ return self.Controler.GetEditedElement(self.TagName) is None
+
+
+#-------------------------------------------------------------------------------
+# Resource Editor class
+#-------------------------------------------------------------------------------
+
+def GetTasksTableColnames():
+ _ = lambda x : x
+ return [_("Name"), _("Triggering"), _("Single"), _("Interval"), _("Priority")]
+
+def GetTaskTriggeringOptions():
+ _ = lambda x : x
+ return [_("Interrupt"), _("Cyclic")]
+TASKTRIGGERINGOPTIONS_DICT = dict([(_(option), option) for option in GetTaskTriggeringOptions()])
+
+def GetInstancesTableColnames():
+ _ = lambda x : x
+ return [_("Name"), _("Type"), _("Task")]
+
+class ResourceTable(CustomTable):
+
+ """
+ A custom wx.grid.Grid Table using user supplied data
+ """
+ def __init__(self, parent, data, colnames):
+ # The base class must be initialized *first*
+ CustomTable.__init__(self, parent, data, colnames)
+ self.ColAlignements = []
+ self.ColSizes = []
+
+ def GetColAlignements(self):
+ return self.ColAlignements
+
+ def SetColAlignements(self, list):
+ self.ColAlignements = list
+
+ def GetColSizes(self):
+ return self.ColSizes
+
+ def SetColSizes(self, list):
+ self.ColSizes = list
+
+ def GetValue(self, row, col):
+ if row < self.GetNumberRows():
+ colname = self.GetColLabelValue(col, False)
+ value = str(self.data[row].get(colname, ""))
+ if colname == "Triggering":
+ return _(value)
+ return value
+
+ def SetValue(self, row, col, value):
+ if col < len(self.colnames):
+ colname = self.GetColLabelValue(col, False)
+ if colname == "Triggering":
+ value = TASKTRIGGERINGOPTIONS_DICT[value]
+ self.data[row][colname] = value
+
+ 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 col in range(self.GetNumberCols()):
+ attr = wx.grid.GridCellAttr()
+ attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
+ grid.SetColAttr(col, attr)
+ grid.SetColSize(col, self.ColSizes[col])
+
+ for row in range(self.GetNumberRows()):
+ row_highlights = self.Highlights.get(row, {})
+ for col in range(self.GetNumberCols()):
+ editor = None
+ renderer = None
+ colname = self.GetColLabelValue(col, False)
+ grid.SetReadOnly(row, col, False)
+ if colname == "Name":
+ editor = wx.grid.GridCellTextEditor()
+ renderer = wx.grid.GridCellStringRenderer()
+ elif colname == "Interval":
+ editor = DurationCellEditor(self)
+ renderer = wx.grid.GridCellStringRenderer()
+ if self.GetValueByName(row, "Triggering") != "Cyclic":
+ grid.SetReadOnly(row, col, True)
+ elif colname == "Single":
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(self.Parent.VariableList)
+ if self.GetValueByName(row, "Triggering") != "Interrupt":
+ grid.SetReadOnly(row, col, True)
+ elif colname == "Triggering":
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(",".join([""] + map(_, GetTaskTriggeringOptions())))
+ elif colname == "Type":
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(self.Parent.TypeList)
+ elif colname == "Priority":
+ editor = wx.grid.GridCellNumberEditor()
+ editor.SetParameters("0,65535")
+ elif colname == "Task":
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(self.Parent.TaskList)
+
+ grid.SetCellEditor(row, col, editor)
+ grid.SetCellRenderer(row, col, renderer)
+
+ highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
+ grid.SetCellBackgroundColour(row, col, highlight_colours[0])
+ grid.SetCellTextColour(row, col, highlight_colours[1])
+ self.ResizeRow(grid, row)
+
+
+#-------------------------------------------------------------------------------
+# Highlights showing functions
+#-------------------------------------------------------------------------------
+
+ def AddHighlight(self, infos, highlight_type):
+ row_highlights = self.Highlights.setdefault(infos[0], {})
+ col_highlights = row_highlights.setdefault(infos[1], [])
+ col_highlights.append(highlight_type)
+
+ def ClearHighlights(self, highlight_type=None):
+ if highlight_type is None:
+ self.Highlights = {}
+ else:
+ for row, row_highlights in self.Highlights.iteritems():
+ row_items = row_highlights.items()
+ for col, col_highlights in row_items:
+ if highlight_type in col_highlights:
+ col_highlights.remove(highlight_type)
+ if len(col_highlights) == 0:
+ row_highlights.pop(col)
+
+
+
+class ResourceEditor(EditorPanel):
+
+ VARIABLE_PANEL_TYPE = "resource"
+
+ def _init_Editor(self, parent):
+ self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL)
+
+ main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+ main_sizer.AddGrowableCol(0)
+ main_sizer.AddGrowableRow(0)
+ main_sizer.AddGrowableRow(1)
+
+ tasks_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+ tasks_sizer.AddGrowableCol(0)
+ tasks_sizer.AddGrowableRow(1)
+ main_sizer.AddSizer(tasks_sizer, border=5,
+ flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+
+ tasks_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
+ tasks_buttons_sizer.AddGrowableCol(0)
+ tasks_buttons_sizer.AddGrowableRow(0)
+ tasks_sizer.AddSizer(tasks_buttons_sizer, flag=wx.GROW)
+
+ tasks_label = wx.StaticText(self.Editor, label=_(u'Tasks:'))
+ tasks_buttons_sizer.AddWindow(tasks_label, flag=wx.ALIGN_BOTTOM)
+
+ for name, bitmap, help in [
+ ("AddTaskButton", "add_element", _("Add task")),
+ ("DeleteTaskButton", "remove_element", _("Remove task")),
+ ("UpTaskButton", "up", _("Move task up")),
+ ("DownTaskButton", "down", _("Move task down"))]:
+ button = wx.lib.buttons.GenBitmapButton(self.Editor,
+ bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button.SetToolTipString(help)
+ setattr(self, name, button)
+ tasks_buttons_sizer.AddWindow(button)
+
+ self.TasksGrid = CustomGrid(self.Editor, style=wx.VSCROLL)
+ self.TasksGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnTasksGridCellChange)
+ tasks_sizer.AddWindow(self.TasksGrid, flag=wx.GROW)
+
+ instances_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+ instances_sizer.AddGrowableCol(0)
+ instances_sizer.AddGrowableRow(1)
+ main_sizer.AddSizer(instances_sizer, border=5,
+ flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+
+ instances_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
+ instances_buttons_sizer.AddGrowableCol(0)
+ instances_buttons_sizer.AddGrowableRow(0)
+ instances_sizer.AddSizer(instances_buttons_sizer, flag=wx.GROW)
+
+ instances_label = wx.StaticText(self.Editor, label=_(u'Instances:'))
+ instances_buttons_sizer.AddWindow(instances_label, flag=wx.ALIGN_BOTTOM)
+
+ for name, bitmap, help in [
+ ("AddInstanceButton", "add_element", _("Add instance")),
+ ("DeleteInstanceButton", "remove_element", _("Remove instance")),
+ ("UpInstanceButton", "up", _("Move instance up")),
+ ("DownInstanceButton", "down", _("Move instance down"))]:
+ button = wx.lib.buttons.GenBitmapButton(self.Editor,
+ bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button.SetToolTipString(help)
+ setattr(self, name, button)
+ instances_buttons_sizer.AddWindow(button)
+
+ self.InstancesGrid = CustomGrid(self.Editor, style=wx.VSCROLL)
+ self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
+ self.OnInstancesGridCellChange)
+ instances_sizer.AddWindow(self.InstancesGrid, flag=wx.GROW)
+
+ self.Editor.SetSizer(main_sizer)
+
+ def __init__(self, parent, tagname, window, controler):
+ EditorPanel.__init__(self, parent, tagname, window, controler)
+
+ self.RefreshHighlightsTimer = wx.Timer(self, -1)
+ self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)
+
+ self.TasksDefaultValue = {"Name" : "", "Triggering" : "", "Single" : "", "Interval" : "", "Priority" : 0}
+ self.TasksTable = ResourceTable(self, [], GetTasksTableColnames())
+ self.TasksTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT])
+ self.TasksTable.SetColSizes([200, 100, 100, 150, 100])
+ self.TasksGrid.SetTable(self.TasksTable)
+ self.TasksGrid.SetButtons({"Add": self.AddTaskButton,
+ "Delete": self.DeleteTaskButton,
+ "Up": self.UpTaskButton,
+ "Down": self.DownTaskButton})
+
+ def _AddTask(new_row):
+ self.TasksTable.InsertRow(new_row, self.TasksDefaultValue.copy())
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.TasksGrid, "_AddRow", _AddTask)
+
+ def _DeleteTask(row):
+ self.TasksTable.RemoveRow(row)
+ self.RefreshModel()
+ self.RefreshView()
+ setattr(self.TasksGrid, "_DeleteRow", _DeleteTask)
+
+ def _MoveTask(row, move):
+ new_row = self.TasksTable.MoveRow(row, move)
+ if new_row != row:
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.TasksGrid, "_MoveRow", _MoveTask)
+
+ self.TasksGrid.SetRowLabelSize(0)
+ self.TasksTable.ResetView(self.TasksGrid)
+ self.TasksGrid.RefreshButtons()
+
+ self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""}
+ self.InstancesTable = ResourceTable(self, [], GetInstancesTableColnames())
+ self.InstancesTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT])
+ self.InstancesTable.SetColSizes([200, 150, 150])
+ self.InstancesGrid.SetTable(self.InstancesTable)
+ self.InstancesGrid.SetButtons({"Add": self.AddInstanceButton,
+ "Delete": self.DeleteInstanceButton,
+ "Up": self.UpInstanceButton,
+ "Down": self.DownInstanceButton})
+
+ def _AddInstance(new_row):
+ self.InstancesTable.InsertRow(new_row, self.InstancesDefaultValue.copy())
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.InstancesGrid, "_AddRow", _AddInstance)
+
+ def _DeleteInstance(row):
+ self.InstancesTable.RemoveRow(row)
+ self.RefreshModel()
+ self.RefreshView()
+ setattr(self.InstancesGrid, "_DeleteRow", _DeleteInstance)
+
+ def _MoveInstance(row, move):
+ new_row = max(0, min(row + move, self.InstancesTable.GetNumberRows() - 1))
+ if new_row != row:
+ if self.InstancesTable.GetValueByName(row, "Task") != self.InstancesTable.GetValueByName(new_row, "Task"):
+ return row
+ self.InstancesTable.MoveRow(row, move)
+ self.RefreshModel()
+ self.RefreshView()
+ return new_row
+ setattr(self.InstancesGrid, "_MoveRow", _MoveInstance)
+
+ def _RefreshInstanceButtons():
+ if self:
+ rows = self.InstancesTable.GetNumberRows()
+ row = self.InstancesGrid.GetGridCursorRow()
+ self.DeleteInstanceButton.Enable(rows > 0)
+ self.UpInstanceButton.Enable(row > 0 and
+ self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row - 1, "Task"))
+ self.DownInstanceButton.Enable(0 <= row < rows - 1 and
+ self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row + 1, "Task"))
+ setattr(self.InstancesGrid, "RefreshButtons", _RefreshInstanceButtons)
+
+ self.InstancesGrid.SetRowLabelSize(0)
+ self.InstancesTable.ResetView(self.InstancesGrid)
+ self.InstancesGrid.RefreshButtons()
+
+ self.TasksGrid.SetFocus()
+
+ def __del__(self):
+ self.RefreshHighlightsTimer.Stop()
+
+ def RefreshTypeList(self):
+ self.TypeList = ""
+ blocktypes = self.Controler.GetBlockResource()
+ for blocktype in blocktypes:
+ self.TypeList += ",%s"%blocktype
+
+ def RefreshTaskList(self):
+ self.TaskList = ""
+ for row in xrange(self.TasksTable.GetNumberRows()):
+ self.TaskList += ",%s"%self.TasksTable.GetValueByName(row, "Name")
+
+ def RefreshVariableList(self):
+ self.VariableList = ""
+ for variable in self.Controler.GetEditedResourceVariables(self.TagName):
+ self.VariableList += ",%s"%variable
+
+ def RefreshModel(self):
+ self.Controler.SetEditedResourceInfos(self.TagName, self.TasksTable.GetData(), self.InstancesTable.GetData())
+ self.RefreshBuffer()
+
+ # Buffer the last model state
+ def RefreshBuffer(self):
+ self.Controler.BufferProject()
+ self.ParentWindow.RefreshTitle()
+ self.ParentWindow.RefreshFileMenu()
+ self.ParentWindow.RefreshEditMenu()
+
+ def GetBufferState(self):
+ return self.Controler.GetBufferState()
+
+ def Undo(self):
+ self.Controler.LoadPrevious()
+ self.ParentWindow.CloseTabsWithoutModel()
+
+ def Redo(self):
+ self.Controler.LoadNext()
+ self.ParentWindow.CloseTabsWithoutModel()
+
+ def HasNoModel(self):
+ return self.Controler.GetEditedElement(self.TagName) is None
+
+ def RefreshView(self, variablepanel=True):
+ EditorPanel.RefreshView(self, variablepanel)
+
+ tasks, instances = self.Controler.GetEditedResourceInfos(self.TagName)
+ self.TasksTable.SetData(tasks)
+ self.InstancesTable.SetData(instances)
+ self.RefreshTypeList()
+ self.RefreshTaskList()
+ self.RefreshVariableList()
+ self.TasksTable.ResetView(self.TasksGrid)
+ self.InstancesTable.ResetView(self.InstancesGrid)
+ self.TasksGrid.RefreshButtons()
+ self.InstancesGrid.RefreshButtons()
+
+ def OnTasksGridCellChange(self, event):
+ row, col = event.GetRow(), event.GetCol()
+ if self.TasksTable.GetColLabelValue(col) == "Name":
+ tasklist = [name for name in self.TaskList.split(",") if name != ""]
+ for i in xrange(self.TasksTable.GetNumberRows()):
+ task = self.TasksTable.GetValueByName(i, "Name")
+ if task in tasklist:
+ tasklist.remove(task)
+ if len(tasklist) > 0:
+ old_name = tasklist[0]
+ new_name = self.TasksTable.GetValue(row, col)
+ for i in xrange(self.InstancesTable.GetNumberRows()):
+ if self.InstancesTable.GetValueByName(i, "Task") == old_name:
+ self.InstancesTable.SetValueByName(i, "Task", new_name)
+ self.RefreshModel()
+ colname = self.TasksTable.GetColLabelValue(col, False)
+ if colname in ["Triggering", "Name"]:
+ wx.CallAfter(self.RefreshView, False)
+ event.Skip()
+
+ def OnInstancesGridCellChange(self, event):
+ self.RefreshModel()
+ self.ParentWindow.RefreshPouInstanceVariablesPanel()
+ self.InstancesGrid.RefreshButtons()
+ event.Skip()
+
+#-------------------------------------------------------------------------------
+# Highlights showing functions
+#-------------------------------------------------------------------------------
+
+ def OnRefreshHighlightsTimer(self, event):
+ self.RefreshView()
+ event.Skip()
+
+ def AddHighlight(self, infos, start, end, highlight_type):
+ if infos[0] == "task":
+ self.TasksTable.AddHighlight(infos[1:], highlight_type)
+ elif infos[0] == "instance":
+ self.InstancesTable.AddHighlight(infos[1:], highlight_type)
+ self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
+
+ def ClearHighlights(self, highlight_type=None):
+ EditorPanel.ClearHighlights(self, highlight_type)
+
+ self.TasksTable.ClearHighlights(highlight_type)
+ self.InstancesTable.ClearHighlights(highlight_type)
+ self.TasksTable.ResetView(self.TasksGrid)
+ self.InstancesTable.ResetView(self.InstancesGrid)