Laurent@814: # -*- coding: utf-8 -*-
Laurent@814: 
andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for
andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
andrej@1571: #
andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
andrej@1696: # Copyright (C) 2017: Andrey Skvortsov <andrej.skvortzov@gmail.com>
andrej@1571: #
andrej@1571: # See COPYING file for copyrights details.
andrej@1571: #
andrej@1571: # This program is free software; you can redistribute it and/or
andrej@1571: # modify it under the terms of the GNU General Public License
andrej@1571: # as published by the Free Software Foundation; either version 2
andrej@1571: # of the License, or (at your option) any later version.
andrej@1571: #
andrej@1571: # This program is distributed in the hope that it will be useful,
andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of
andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
andrej@1571: # GNU General Public License for more details.
andrej@1571: #
andrej@1571: # You should have received a copy of the GNU General Public License
andrej@1571: # along with this program; if not, write to the Free Software
andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Laurent@814: 
andrej@1881: 
andrej@1881: from __future__ import absolute_import
Laurent@814: import wx
Laurent@814: import wx.grid
Laurent@814: import wx.lib.buttons
Laurent@814: 
Laurent@814: from controls import CustomGrid, CustomTable
Edouard@1957: from plcopen.BlockInstanceCollector import _ActionInfos
Laurent@814: from util.BitmapLibrary import GetBitmap
andrej@1762: from util.TranslationCatalogs import NoTranslate
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: #                                  Helpers
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: 
andrej@1736: 
Laurent@814: def GetActionTableColnames():
andrej@1762:     _ = NoTranslate
Laurent@814:     return [_("Qualifier"), _("Duration"), _("Type"), _("Value"), _("Indicator")]
Laurent@814: 
andrej@1736: 
Laurent@814: def GetTypeList():
andrej@1762:     _ = NoTranslate
Laurent@814:     return [_("Action"), _("Variable"), _("Inline")]
Laurent@814: 
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: #                               Action Table
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: 
andrej@1736: 
Laurent@814: class ActionTable(CustomTable):
andrej@1730: 
Laurent@814:     def GetValue(self, row, col):
Laurent@814:         if row < self.GetNumberRows():
Laurent@814:             colname = self.GetColLabelValue(col, False)
Laurent@1339:             value = getattr(self.data[row], colname.lower())
Laurent@814:             if colname == "Type":
Laurent@1339:                 return _(value)
Laurent@1339:             return value
andrej@1730: 
Laurent@814:     def SetValue(self, row, col, value):
Laurent@814:         if col < len(self.colnames):
Laurent@814:             colname = self.GetColLabelValue(col, False)
Laurent@814:             if colname == "Type":
Laurent@814:                 value = self.Parent.TranslateType[value]
Laurent@1339:             elif colname == "Qualifier" and not self.Parent.DurationList[value]:
Laurent@1339:                 self.data[row].duration = ""
Laurent@1339:             setattr(self.data[row], colname.lower(), value)
andrej@1730: 
Laurent@814:     def _updateColAttrs(self, grid):
Laurent@814:         """
Laurent@814:         wx.Grid -> update the column attributes to add the
Laurent@814:         appropriate renderer given the column name.
Laurent@814: 
Laurent@814:         Otherwise default to the default renderer.
Laurent@814:         """
andrej@1730: 
Laurent@814:         for row in range(self.GetNumberRows()):
Laurent@814:             for col in range(self.GetNumberCols()):
Laurent@814:                 editor = None
Laurent@814:                 renderer = None
Laurent@814:                 readonly = False
Laurent@814:                 colname = self.GetColLabelValue(col, False)
Laurent@814:                 if colname == "Qualifier":
Laurent@814:                     editor = wx.grid.GridCellChoiceEditor()
Laurent@814:                     editor.SetParameters(self.Parent.QualifierList)
Laurent@814:                 if colname == "Duration":
Laurent@814:                     editor = wx.grid.GridCellTextEditor()
Laurent@814:                     renderer = wx.grid.GridCellStringRenderer()
Laurent@1339:                     readonly = not self.Parent.DurationList[self.data[row].qualifier]
Laurent@814:                 elif colname == "Type":
Laurent@814:                     editor = wx.grid.GridCellChoiceEditor()
Laurent@814:                     editor.SetParameters(self.Parent.TypeList)
Laurent@814:                 elif colname == "Value":
Laurent@1339:                     value_type = self.data[row].type
Laurent@1339:                     if value_type == "Action":
Laurent@814:                         editor = wx.grid.GridCellChoiceEditor()
Laurent@814:                         editor.SetParameters(self.Parent.ActionList)
Laurent@1339:                     elif value_type == "Variable":
Laurent@814:                         editor = wx.grid.GridCellChoiceEditor()
Laurent@814:                         editor.SetParameters(self.Parent.VariableList)
Laurent@1339:                     elif value_type == "Inline":
Laurent@814:                         editor = wx.grid.GridCellTextEditor()
Laurent@814:                         renderer = wx.grid.GridCellStringRenderer()
Laurent@814:                 elif colname == "Indicator":
Laurent@814:                     editor = wx.grid.GridCellChoiceEditor()
Laurent@814:                     editor.SetParameters(self.Parent.VariableList)
andrej@1730: 
Laurent@814:                 grid.SetCellEditor(row, col, editor)
Laurent@814:                 grid.SetCellRenderer(row, col, renderer)
Laurent@814:                 grid.SetReadOnly(row, col, readonly)
andrej@1730: 
Laurent@814:                 grid.SetCellBackgroundColour(row, col, wx.WHITE)
Laurent@814:             self.ResizeRow(grid, row)
Laurent@814: 
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: #                            Action Block Dialog
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: 
andrej@1736: 
Laurent@814: class ActionBlockDialog(wx.Dialog):
andrej@1730: 
Laurent@814:     def __init__(self, parent):
andrej@1696:         wx.Dialog.__init__(self, parent, title=_('Edit action block properties'))
andrej@1730: 
Laurent@814:         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
Laurent@814:         main_sizer.AddGrowableCol(0)
Laurent@814:         main_sizer.AddGrowableRow(1)
andrej@1730: 
Laurent@814:         top_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
Laurent@814:         top_sizer.AddGrowableCol(0)
Laurent@814:         top_sizer.AddGrowableRow(0)
Laurent@814:         main_sizer.AddSizer(top_sizer, border=20,
andrej@1768:                             flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
andrej@1730: 
Laurent@814:         actions_label = wx.StaticText(self, label=_('Actions:'))
Laurent@814:         top_sizer.AddWindow(actions_label, flag=wx.ALIGN_BOTTOM)
andrej@1730: 
Laurent@814:         for name, bitmap, help in [
Laurent@814:                 ("AddButton", "add_element", _("Add action")),
Laurent@814:                 ("DeleteButton", "remove_element", _("Remove action")),
Laurent@814:                 ("UpButton", "up", _("Move action up")),
Laurent@814:                 ("DownButton", "down", _("Move action down"))]:
andrej@1768:             button = wx.lib.buttons.GenBitmapButton(
andrej@1768:                 self, bitmap=GetBitmap(bitmap),
andrej@1768:                 size=wx.Size(28, 28), style=wx.NO_BORDER)
Laurent@814:             button.SetToolTipString(help)
Laurent@814:             setattr(self, name, button)
Laurent@814:             top_sizer.AddWindow(button)
andrej@1730: 
andrej@1696:         self.ActionsGrid = CustomGrid(self, size=wx.Size(-1, 250), style=wx.VSCROLL)
Laurent@814:         self.ActionsGrid.DisableDragGridSize()
Laurent@814:         self.ActionsGrid.EnableScrolling(False, True)
andrej@1730:         self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
Laurent@814:                               self.OnActionsGridCellChange)
Laurent@814:         main_sizer.AddSizer(self.ActionsGrid, border=20,
andrej@1768:                             flag=wx.GROW | wx.LEFT | wx.RIGHT)
andrej@1745: 
andrej@1745:         button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
Laurent@814:         self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
andrej@1730:         main_sizer.AddSizer(button_sizer, border=20,
andrej@1768:                             flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
andrej@1730: 
Laurent@814:         self.SetSizer(main_sizer)
andrej@1730: 
Laurent@814:         self.Table = ActionTable(self, [], GetActionTableColnames())
andrej@1730:         typelist = GetTypeList()
andrej@1740:         self.TypeList = ",".join(map(_, typelist))
Laurent@814:         self.TranslateType = dict([(_(value), value) for value in typelist])
andrej@1696:         self.ColSizes = [60, 90, 130, 200, 50]
Laurent@814:         self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
andrej@1730: 
Laurent@814:         self.ActionsGrid.SetTable(self.Table)
Laurent@1339:         self.ActionsGrid.SetDefaultValue(_ActionInfos("N", "Action", "", "", ""))
Laurent@814:         self.ActionsGrid.SetButtons({"Add": self.AddButton,
Laurent@814:                                      "Delete": self.DeleteButton,
Laurent@814:                                      "Up": self.UpButton,
Laurent@814:                                      "Down": self.DownButton})
Laurent@814:         self.ActionsGrid.SetRowLabelSize(0)
andrej@1730: 
Laurent@814:         for col in range(self.Table.GetNumberCols()):
Laurent@814:             attr = wx.grid.GridCellAttr()
Laurent@814:             attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
Laurent@814:             self.ActionsGrid.SetColAttr(col, attr)
Laurent@814:             self.ActionsGrid.SetColMinimalWidth(col, self.ColSizes[col])
Laurent@814:             self.ActionsGrid.AutoSizeColumn(col, False)
andrej@1730: 
Laurent@814:         self.Table.ResetView(self.ActionsGrid)
Laurent@814:         self.ActionsGrid.SetFocus()
Laurent@814:         self.ActionsGrid.RefreshButtons()
andrej@1696:         self.Fit()
andrej@1730: 
Laurent@814:     def OnOK(self, event):
Laurent@814:         self.ActionsGrid.CloseEditControl()
Laurent@814:         self.EndModal(wx.ID_OK)
Laurent@814: 
Laurent@814:     def OnActionsGridCellChange(self, event):
Laurent@814:         wx.CallAfter(self.Table.ResetView, self.ActionsGrid)
Laurent@814:         event.Skip()
andrej@1730: 
Laurent@814:     def SetQualifierList(self, list):
Laurent@1339:         self.QualifierList = ",".join(list)
Laurent@814:         self.DurationList = list
Laurent@814: 
Laurent@814:     def SetVariableList(self, list):
Laurent@1347:         self.VariableList = "," + ",".join([variable.Name for variable in list])
andrej@1730: 
Laurent@814:     def SetActionList(self, list):
Laurent@814:         self.ActionList = "," + ",".join(list)
Laurent@814: 
Laurent@814:     def SetValues(self, actions):
Laurent@814:         for action in actions:
Laurent@1340:             row = action.copy()
Laurent@1340:             if row.type == "reference" and row.value in self.ActionList:
Laurent@1340:                 row.type = "Action"
Laurent@1340:             elif row.type == "reference" and row.value in self.VariableList:
Laurent@1340:                 row.type = "Variable"
Laurent@814:             else:
Laurent@1340:                 row.type = "Inline"
Laurent@1340:             self.Table.AppendRow(row)
Laurent@814:         self.Table.ResetView(self.ActionsGrid)
Laurent@814:         if len(actions) > 0:
Laurent@814:             self.ActionsGrid.SetGridCursor(0, 0)
Laurent@814:         self.ActionsGrid.RefreshButtons()
andrej@1730: 
Laurent@814:     def GetValues(self):
Laurent@1339:         actions = self.Table.GetData()
Laurent@1339:         for action in actions:
Laurent@1339:             if action.type in ["Action", "Variable"]:
Laurent@1339:                 action.type = "reference"
Laurent@814:             else:
Laurent@1339:                 action.type = "inline"
Laurent@1339:         return actions