PLCOpenEditor.py
changeset 418 a06221a0930b
parent 416 897ba122460e
child 423 53aa0c334f2f
equal deleted inserted replaced
417:218142afdb53 418:a06221a0930b
   106 from TextViewer import *
   106 from TextViewer import *
   107 from GraphicViewer import *
   107 from GraphicViewer import *
   108 from RessourceEditor import *
   108 from RessourceEditor import *
   109 from DataTypeEditor import *
   109 from DataTypeEditor import *
   110 from PLCControler import *
   110 from PLCControler import *
   111 from plcopen.structures import LOCATIONDATATYPES
   111 from VariablePanel import VariablePanel
   112 
   112 
   113 # Define PLCOpenEditor controls id
   113 # Define PLCOpenEditor controls id
   114 [ID_PLCOPENEDITOR, ID_PLCOPENEDITORTREENOTEBOOK,
   114 [ID_PLCOPENEDITOR, ID_PLCOPENEDITORTREENOTEBOOK,
   115  ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE, 
   115  ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE, 
   116  ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER, 
   116  ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER, 
  3845     def ClearErrors(self):
  3845     def ClearErrors(self):
  3846         for panel in self.VariablePanelList.values():
  3846         for panel in self.VariablePanelList.values():
  3847             panel.ClearErrors()
  3847             panel.ClearErrors()
  3848 
  3848 
  3849 #-------------------------------------------------------------------------------
  3849 #-------------------------------------------------------------------------------
  3850 #                            Variables Editor Panel
       
  3851 #-------------------------------------------------------------------------------
       
  3852 
       
  3853 def GetVariableTableColnames(location):
       
  3854     _ = lambda x : x
       
  3855     if location:
       
  3856     	return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Retain"), _("Constant")]
       
  3857     return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Retain"), _("Constant")]
       
  3858 
       
  3859 def GetAlternativeOptions():
       
  3860     _ = lambda x : x
       
  3861     return [_("Yes"), _("No")]
       
  3862 ALTERNATIVE_OPTIONS_DICT = dict([(_(option), option) for option in GetAlternativeOptions()])
       
  3863 
       
  3864 def GetFilterChoiceTransfer():
       
  3865     _ = lambda x : x
       
  3866     return {_("All"): _("All"), _("Interface"): _("Interface"), 
       
  3867             _("   Input"): _("Input"), _("   Output"): _("Output"), _("   InOut"): _("InOut"), 
       
  3868             _("   External"): _("External"), _("Variables"): _("Variables"), _("   Local"): _("Local"),
       
  3869             _("   Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")}
       
  3870 VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()])
       
  3871 
       
  3872 class VariableTable(wx.grid.PyGridTableBase):
       
  3873     
       
  3874     """
       
  3875     A custom wx.grid.Grid Table using user supplied data
       
  3876     """
       
  3877     def __init__(self, parent, data, colnames):
       
  3878         # The base class must be initialized *first*
       
  3879         wx.grid.PyGridTableBase.__init__(self)
       
  3880         self.data = data
       
  3881         self.old_value = None
       
  3882         self.colnames = colnames
       
  3883         self.Errors = {}
       
  3884         self.Parent = parent
       
  3885         # XXX
       
  3886         # we need to store the row length and collength to
       
  3887         # see if the table has changed size
       
  3888         self._rows = self.GetNumberRows()
       
  3889         self._cols = self.GetNumberCols()
       
  3890     
       
  3891     def GetNumberCols(self):
       
  3892         return len(self.colnames)
       
  3893         
       
  3894     def GetNumberRows(self):
       
  3895         return len(self.data)
       
  3896 
       
  3897     def GetColLabelValue(self, col, translate=True):
       
  3898         if col < len(self.colnames):
       
  3899             if translate:
       
  3900                 return _(self.colnames[col])
       
  3901             return self.colnames[col]
       
  3902 
       
  3903     def GetRowLabelValues(self, row, translate=True):
       
  3904         return row
       
  3905 
       
  3906     def GetValue(self, row, col):
       
  3907         if row < self.GetNumberRows():
       
  3908             if col == 0:
       
  3909                 return self.data[row]["Number"]
       
  3910             colname = self.GetColLabelValue(col, False)
       
  3911             value = str(self.data[row].get(colname, ""))
       
  3912             if colname in ["Class", "Retain", "Constant"]:
       
  3913                 return _(value)
       
  3914             return value
       
  3915     
       
  3916     def SetValue(self, row, col, value):
       
  3917         if col < len(self.colnames):
       
  3918             colname = self.GetColLabelValue(col, False)
       
  3919             if colname == "Name":
       
  3920                 self.old_value = self.data[row][colname]
       
  3921             elif colname == "Class":
       
  3922                 value = VARIABLE_CLASSES_DICT[value]
       
  3923             elif colname in ["Retain", "Constant"]:
       
  3924                 value = ALTERNATIVE_OPTIONS_DICT[value]
       
  3925             self.data[row][colname] = value
       
  3926     
       
  3927     def GetValueByName(self, row, colname):
       
  3928         if row < self.GetNumberRows():
       
  3929             return self.data[row].get(colname)
       
  3930 
       
  3931     def SetValueByName(self, row, colname, value):
       
  3932         if row < self.GetNumberRows():
       
  3933             self.data[row][colname] = value
       
  3934 
       
  3935     def GetOldValue(self):
       
  3936         return self.old_value
       
  3937     
       
  3938     def ResetView(self, grid):
       
  3939         """
       
  3940         (wx.grid.Grid) -> Reset the grid view.   Call this to
       
  3941         update the grid if rows and columns have been added or deleted
       
  3942         """
       
  3943         grid.BeginBatch()
       
  3944         for current, new, delmsg, addmsg in [
       
  3945             (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
       
  3946             (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
       
  3947         ]:
       
  3948             if new < current:
       
  3949                 msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
       
  3950                 grid.ProcessTableMessage(msg)
       
  3951             elif new > current:
       
  3952                 msg = wx.grid.GridTableMessage(self,addmsg,new-current)
       
  3953                 grid.ProcessTableMessage(msg)
       
  3954                 self.UpdateValues(grid)
       
  3955         grid.EndBatch()
       
  3956 
       
  3957         self._rows = self.GetNumberRows()
       
  3958         self._cols = self.GetNumberCols()
       
  3959         # update the column rendering scheme
       
  3960         self._updateColAttrs(grid)
       
  3961 
       
  3962         # update the scrollbars and the displayed part of the grid
       
  3963         grid.AdjustScrollbars()
       
  3964         grid.ForceRefresh()
       
  3965 
       
  3966     def UpdateValues(self, grid):
       
  3967         """Update all displayed values"""
       
  3968         # This sends an event to the grid table to update all of the values
       
  3969         msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
       
  3970         grid.ProcessTableMessage(msg)
       
  3971 
       
  3972     def _updateColAttrs(self, grid):
       
  3973         """
       
  3974         wx.grid.Grid -> update the column attributes to add the
       
  3975         appropriate renderer given the column name.
       
  3976 
       
  3977         Otherwise default to the default renderer.
       
  3978         """
       
  3979         
       
  3980         for row in range(self.GetNumberRows()):
       
  3981             for col in range(self.GetNumberCols()):
       
  3982                 editor = None
       
  3983                 renderer = None
       
  3984                 colname = self.GetColLabelValue(col, False)
       
  3985                 if col != 0 and self.GetValueByName(row, "Edit"):
       
  3986                     grid.SetReadOnly(row, col, False)
       
  3987                     if colname == "Name":
       
  3988                         if self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
       
  3989                             grid.SetReadOnly(row, col, True)
       
  3990                         else:
       
  3991                             editor = wx.grid.GridCellTextEditor()
       
  3992                             renderer = wx.grid.GridCellStringRenderer()
       
  3993                     elif colname == "Initial Value":
       
  3994                         editor = wx.grid.GridCellTextEditor()
       
  3995                         renderer = wx.grid.GridCellStringRenderer()
       
  3996                     elif colname == "Location":
       
  3997                         if self.GetValueByName(row, "Class") in ["Local", "Global"]:
       
  3998                             editor = wx.grid.GridCellTextEditor()
       
  3999                             renderer = wx.grid.GridCellStringRenderer()
       
  4000                         else:
       
  4001                             grid.SetReadOnly(row, col, True)
       
  4002                     elif colname == "Class":
       
  4003                         if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and self.GetValueByName(row, "Class") in ["Input", "Output", "InOut"]:
       
  4004                             grid.SetReadOnly(row, col, True)
       
  4005                         else:
       
  4006                             editor = wx.grid.GridCellChoiceEditor()
       
  4007                             excluded = []
       
  4008                             if self.Parent.PouIsUsed:
       
  4009                                 excluded.extend(["Input","Output","InOut"])
       
  4010                             if self.Parent.IsFunctionBlockType(self.data[row]["Type"]):
       
  4011                                 excluded.extend(["Local","Temp"])
       
  4012                             editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded]))
       
  4013                     elif colname in ["Retain", "Constant"]:
       
  4014                         editor = wx.grid.GridCellChoiceEditor()
       
  4015                         editor.SetParameters(",".join(map(_, self.Parent.OptionList)))
       
  4016                     elif colname == "Type":
       
  4017                         editor = wx.grid.GridCellTextEditor()
       
  4018                 else:
       
  4019                     grid.SetReadOnly(row, col, True)
       
  4020                 
       
  4021                 grid.SetCellEditor(row, col, editor)
       
  4022                 grid.SetCellRenderer(row, col, renderer)
       
  4023                 
       
  4024                 if row in self.Errors and self.Errors[row][0] == colname.lower():
       
  4025                     grid.SetCellBackgroundColour(row, col, wx.Colour(255, 255, 0))
       
  4026                     grid.SetCellTextColour(row, col, wx.RED)
       
  4027                     grid.MakeCellVisible(row, col)
       
  4028                 else:
       
  4029                     grid.SetCellTextColour(row, col, wx.BLACK)
       
  4030                     grid.SetCellBackgroundColour(row, col, wx.WHITE)
       
  4031     
       
  4032     def SetData(self, data):
       
  4033         self.data = data
       
  4034     
       
  4035     def GetData(self):
       
  4036         return self.data
       
  4037     
       
  4038     def GetCurrentIndex(self):
       
  4039         return self.CurrentIndex
       
  4040     
       
  4041     def SetCurrentIndex(self, index):
       
  4042         self.CurrentIndex = index
       
  4043     
       
  4044     def AppendRow(self, row_content):
       
  4045         self.data.append(row_content)
       
  4046 
       
  4047     def RemoveRow(self, row_index):
       
  4048         self.data.pop(row_index)
       
  4049 
       
  4050     def GetRow(self, row_index):
       
  4051         return self.data[row_index]
       
  4052 
       
  4053     def Empty(self):
       
  4054         self.data = []
       
  4055         self.editors = []
       
  4056 
       
  4057     def AddError(self, infos):
       
  4058         self.Errors[infos[0]] = infos[1:]
       
  4059 
       
  4060     def ClearErrors(self):
       
  4061         self.Errors = {}
       
  4062 
       
  4063 class VariableDropTarget(wx.TextDropTarget):
       
  4064     
       
  4065     def __init__(self, parent):
       
  4066         wx.TextDropTarget.__init__(self)
       
  4067         self.ParentWindow = parent
       
  4068     
       
  4069     def OnDropText(self, x, y, data):
       
  4070         x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
       
  4071         col = self.ParentWindow.VariablesGrid.XToCol(x)
       
  4072         row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
       
  4073         if col != wx.NOT_FOUND and row != wx.NOT_FOUND:
       
  4074             if self.ParentWindow.Table.GetColLabelValue(col, False) != "Location":
       
  4075                 return
       
  4076             message = None
       
  4077             if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
       
  4078                 message = _("Can't affect a location to a function block instance")
       
  4079             elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]:
       
  4080                 message = _("Can affect a location only to local or global variables")
       
  4081             else:
       
  4082                 try:
       
  4083                     values = eval(data)    
       
  4084                 except:
       
  4085                     message = _("Invalid value \"%s\" for location")%data
       
  4086                     values = None
       
  4087                 if not isinstance(values, TupleType):
       
  4088                     message = _("Invalid value \"%s\" for location")%data
       
  4089                     values = None
       
  4090                 if values is not None and values[1] == "location":
       
  4091                     location = values[0]
       
  4092                     variable_type = self.ParentWindow.Table.GetValueByName(row, "Type")
       
  4093                     base_type = self.ParentWindow.Controler.GetBaseType(variable_type)
       
  4094                     message = None
       
  4095                     if location.startswith("%"):
       
  4096                         if base_type != values[2]:
       
  4097                             message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type)
       
  4098                         else:
       
  4099                             self.ParentWindow.Table.SetValue(row, col, location)
       
  4100                             self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
       
  4101                             self.ParentWindow.SaveValues()
       
  4102                     else:
       
  4103                         if location[0].isdigit() and base_type != "BOOL":
       
  4104                             message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location
       
  4105                         elif location[0] not in LOCATIONDATATYPES:
       
  4106                             message = _("Unrecognized data size \"%s\"")%location[0]
       
  4107                         elif base_type not in LOCATIONDATATYPES[location[0]]:
       
  4108                             message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type)
       
  4109                         else:
       
  4110                             dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Select a variable class:"), _("Variable class"), ["Input", "Output", "Memory"], wx.OK|wx.CANCEL)
       
  4111                             if dialog.ShowModal() == wx.ID_OK:
       
  4112                                 selected = dialog.GetSelection()
       
  4113                                 if selected == 0:
       
  4114                                     location = "%I" + location
       
  4115                                 elif selected == 1:
       
  4116                                     location = "%Q" + location
       
  4117                                 else:
       
  4118                                     location = "%M" + location
       
  4119                                 self.ParentWindow.Table.SetValue(row, col, location)
       
  4120                                 self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
       
  4121                                 self.ParentWindow.SaveValues()
       
  4122                             dialog.Destroy()
       
  4123             if message is not None:
       
  4124                 wx.CallAfter(self.ShowMessage, message)
       
  4125             
       
  4126     def ShowMessage(self, message):
       
  4127         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
       
  4128         message.ShowModal()
       
  4129         message.Destroy()
       
  4130 
       
  4131 [ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, 
       
  4132  ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE, 
       
  4133  ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, 
       
  4134  ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, 
       
  4135  ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1, 
       
  4136  ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3,
       
  4137 ] = [wx.NewId() for _init_ctrls in range(12)]
       
  4138 
       
  4139 class VariablePanel(wx.Panel):
       
  4140     
       
  4141     if wx.VERSION < (2, 6, 0):
       
  4142         def Bind(self, event, function, id = None):
       
  4143             if id is not None:
       
  4144                 event(self, id, function)
       
  4145             else:
       
  4146                 event(self, function)
       
  4147     
       
  4148     def _init_coll_MainSizer_Items(self, parent):
       
  4149         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
       
  4150         parent.AddWindow(self.ControlPanel, 0, border=5, flag=wx.GROW|wx.ALL)
       
  4151     
       
  4152     def _init_coll_MainSizer_Growables(self, parent):
       
  4153         parent.AddGrowableCol(0)
       
  4154         parent.AddGrowableRow(0)
       
  4155     
       
  4156     def _init_coll_ControlPanelSizer_Items(self, parent):
       
  4157         parent.AddSizer(self.ChoicePanelSizer, 0, border=0, flag=wx.GROW)
       
  4158         parent.AddSizer(self.ButtonPanelSizer, 0, border=0, flag=wx.ALIGN_CENTER)
       
  4159 
       
  4160     def _init_coll_ControlPanelSizer_Growables(self, parent):
       
  4161         parent.AddGrowableCol(0)
       
  4162         parent.AddGrowableRow(0)
       
  4163         parent.AddGrowableRow(1)
       
  4164 
       
  4165     def _init_coll_ChoicePanelSizer_Items(self, parent):
       
  4166         parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_BOTTOM)
       
  4167         parent.AddWindow(self.ReturnType, 0, border=0, flag=0)
       
  4168         parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_BOTTOM)
       
  4169         parent.AddWindow(self.ClassFilter, 0, border=0, flag=0)
       
  4170 
       
  4171     def _init_coll_ButtonPanelSizer_Items(self, parent):
       
  4172         parent.AddWindow(self.UpButton, 0, border=0, flag=0)
       
  4173         parent.AddWindow(self.AddButton, 0, border=0, flag=0)
       
  4174         parent.AddWindow(self.DownButton, 0, border=0, flag=0)
       
  4175         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
       
  4176         
       
  4177     def _init_coll_ButtonPanelSizer_Growables(self, parent):
       
  4178         parent.AddGrowableCol(0)
       
  4179         parent.AddGrowableCol(1)
       
  4180         parent.AddGrowableCol(2)
       
  4181         parent.AddGrowableCol(3)
       
  4182         parent.AddGrowableRow(0)
       
  4183 
       
  4184     def _init_sizers(self):
       
  4185         self.MainSizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=0)
       
  4186         self.ControlPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
       
  4187         self.ChoicePanelSizer = wx.GridSizer(cols=1, hgap=5, rows=4, vgap=5)
       
  4188         self.ButtonPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
       
  4189         
       
  4190         self._init_coll_MainSizer_Items(self.MainSizer)
       
  4191         self._init_coll_MainSizer_Growables(self.MainSizer)
       
  4192         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
       
  4193         self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer)
       
  4194         self._init_coll_ChoicePanelSizer_Items(self.ChoicePanelSizer)
       
  4195         self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
       
  4196         self._init_coll_ButtonPanelSizer_Growables(self.ButtonPanelSizer)
       
  4197         
       
  4198         self.SetSizer(self.MainSizer)
       
  4199         self.ControlPanel.SetSizer(self.ControlPanelSizer)
       
  4200 
       
  4201     def _init_ctrls(self, prnt):
       
  4202         wx.Panel.__init__(self, id=ID_VARIABLEEDITORPANEL,
       
  4203               name='VariableEditorPanel', parent=prnt, pos=wx.Point(0, 0),
       
  4204               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
  4205 
       
  4206         self.VariablesGrid = wx.grid.Grid(id=ID_VARIABLEEDITORPANELVARIABLESGRID,
       
  4207               name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
       
  4208               size=wx.Size(0, 0), style=wx.VSCROLL)
       
  4209         self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
       
  4210               'Sans'))
       
  4211         self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
       
  4212               False, 'Sans'))
       
  4213         self.VariablesGrid.SetSelectionBackground(wx.WHITE)
       
  4214         self.VariablesGrid.SetSelectionForeground(wx.BLACK)
       
  4215         if wx.VERSION >= (2, 6, 0):
       
  4216             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
       
  4217             self.VariablesGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnVariablesGridSelectCell)
       
  4218             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
       
  4219             self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
       
  4220             #self.VariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnChar)
       
  4221         else:
       
  4222             wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
       
  4223             wx.grid.EVT_GRID_SELECT_CELL(self.VariablesGrid, self.OnVariablesGridSelectCell)
       
  4224             wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
       
  4225             wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
       
  4226             #wx.EVT_KEY_DOWN(self.VariablesGrid, self.OnChar)
       
  4227         self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
       
  4228         
       
  4229         self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
       
  4230               name='ControlPanel', parent=self, pos=wx.Point(0, 0),
       
  4231               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
  4232         self.ControlPanel.SetScrollRate(0, 10)
       
  4233         
       
  4234         self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1,
       
  4235               label=_('Return Type:'), name='staticText1', parent=self.ControlPanel,
       
  4236               pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0)
       
  4237 
       
  4238         self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE,
       
  4239               name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4240               size=wx.Size(145, 28), style=wx.CB_READONLY)
       
  4241         self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE)
       
  4242 
       
  4243         self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2,
       
  4244               label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel,
       
  4245               pos=wx.Point(0, 0), size=wx.Size(145, 17), style=0)
       
  4246 
       
  4247         self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER,
       
  4248               name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4249               size=wx.Size(145, 28), style=wx.CB_READONLY)
       
  4250         self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, id=ID_VARIABLEEDITORPANELCLASSFILTER)
       
  4251 
       
  4252         self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label=_('Add'),
       
  4253               name='AddButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4254               size=wx.DefaultSize, style=0)
       
  4255         self.Bind(wx.EVT_BUTTON, self.OnAddButton, id=ID_VARIABLEEDITORPANELADDBUTTON)
       
  4256 
       
  4257         self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label=_('Delete'),
       
  4258               name='DeleteButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4259               size=wx.DefaultSize, style=0)
       
  4260         self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_VARIABLEEDITORPANELDELETEBUTTON)
       
  4261 
       
  4262         self.UpButton = wx.Button(id=ID_VARIABLEEDITORPANELUPBUTTON, label='^',
       
  4263               name='UpButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4264               size=wx.Size(32, 32), style=0)
       
  4265         self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_VARIABLEEDITORPANELUPBUTTON)
       
  4266 
       
  4267         self.DownButton = wx.Button(id=ID_VARIABLEEDITORPANELDOWNBUTTON, label='v',
       
  4268               name='DownButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
  4269               size=wx.Size(32, 32), style=0)
       
  4270         self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_VARIABLEEDITORPANELDOWNBUTTON)
       
  4271 
       
  4272         self._init_sizers()
       
  4273 
       
  4274     def __init__(self, parent, window, controler, element_type):
       
  4275         self._init_ctrls(parent)
       
  4276         self.ParentWindow = window
       
  4277         self.Controler = controler
       
  4278         self.ElementType = element_type
       
  4279         
       
  4280         self.Filter = "All"
       
  4281         self.FilterChoices = []
       
  4282         self.FilterChoiceTransfer = GetFilterChoiceTransfer()
       
  4283         
       
  4284         if element_type in ["config", "resource"]:
       
  4285             self.DefaultTypes = {"All" : "Global"}
       
  4286             self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True}
       
  4287         else:
       
  4288             self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
       
  4289             self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True}
       
  4290         if element_type in ["config", "resource"] or element_type in ["program", "transition", "action"]:
       
  4291             self.Table = VariableTable(self, [], GetVariableTableColnames(True))
       
  4292             if element_type not in ["config", "resource"]:
       
  4293                 self.FilterChoices = ["All", "Interface", "   Input", "   Output", "   InOut", "   External", "Variables", "   Local", "   Temp"]#,"Access"]
       
  4294             else:
       
  4295                 self.FilterChoices = ["All", "Global"]#,"Access"]
       
  4296             self.ColSizes = [40, 80, 70, 80, 80, 80, 60, 70]
       
  4297             self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
       
  4298         else:
       
  4299             self.Table = VariableTable(self, [], GetVariableTableColnames(False))
       
  4300             if element_type == "function":
       
  4301                 self.FilterChoices = ["All", "Interface", "   Input", "   Output", "   InOut", "Variables", "   Local", "   Temp"]
       
  4302             else:
       
  4303                 self.FilterChoices = ["All", "Interface", "   Input", "   Output", "   InOut", "   External", "Variables", "   Local", "   Temp"]
       
  4304             self.ColSizes = [40, 120, 70, 80, 120, 60, 70]
       
  4305             self.ColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_CENTER, wx.ALIGN_CENTER]
       
  4306         for choice in self.FilterChoices:
       
  4307             self.ClassFilter.Append(_(choice))
       
  4308         reverse_transfer = {}
       
  4309         for filter, choice in self.FilterChoiceTransfer.items():
       
  4310             reverse_transfer[choice] = filter
       
  4311         self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter]))
       
  4312         self.RefreshTypeList()
       
  4313 
       
  4314         self.OptionList = GetAlternativeOptions()
       
  4315         
       
  4316         if element_type == "function":
       
  4317             for base_type in self.Controler.GetBaseTypes():
       
  4318                 self.ReturnType.Append(base_type)
       
  4319             self.ReturnType.Enable(True)
       
  4320         else:
       
  4321             self.ReturnType.Enable(False)
       
  4322             self.staticText1.Hide()
       
  4323             self.ReturnType.Hide()
       
  4324             
       
  4325         self.VariablesGrid.SetTable(self.Table)
       
  4326         self.VariablesGrid.SetRowLabelSize(0)
       
  4327         for col in range(self.Table.GetNumberCols()):
       
  4328             attr = wx.grid.GridCellAttr()
       
  4329             attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
       
  4330             self.VariablesGrid.SetColAttr(col, attr)
       
  4331             self.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col])
       
  4332             self.VariablesGrid.AutoSizeColumn(col, False)
       
  4333     
       
  4334     def SetTagName(self, tagname):
       
  4335         self.TagName = tagname
       
  4336     
       
  4337     def IsFunctionBlockType(self, name):
       
  4338         bodytype = self.Controler.GetEditedElementBodyType(self.TagName, self.ParentWindow.Debug)
       
  4339         pouname, poutype = self.Controler.GetEditedElementType(self.TagName, self.ParentWindow.Debug)
       
  4340         if poutype != "function" and bodytype in ["ST", "IL"]:
       
  4341             return False
       
  4342         else:
       
  4343             return name in self.Controler.GetFunctionBlockTypes(self.TagName, self.ParentWindow.Debug)
       
  4344     
       
  4345     def RefreshView(self):
       
  4346         self.PouNames = self.Controler.GetProjectPouNames(self.ParentWindow.Debug)
       
  4347         
       
  4348         words = self.TagName.split("::")
       
  4349         if self.ElementType == "config":
       
  4350             self.PouIsUsed = False
       
  4351             returnType = None
       
  4352             self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.ParentWindow.Debug)
       
  4353         elif self.ElementType == "resource":
       
  4354             self.PouIsUsed = False
       
  4355             returnType = None
       
  4356             self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2], self.ParentWindow.Debug)
       
  4357         else:
       
  4358             self.PouIsUsed = self.Controler.PouIsUsed(words[1], self.ParentWindow.Debug)
       
  4359             returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.ParentWindow.Debug)
       
  4360             self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.ParentWindow.Debug)
       
  4361         
       
  4362         if returnType and self.ReturnType.IsEnabled():
       
  4363             self.ReturnType.SetStringSelection(returnType)
       
  4364         
       
  4365         self.RefreshValues()
       
  4366         self.RefreshButtons()
       
  4367     
       
  4368     def OnReturnTypeChanged(self, event):
       
  4369         words = self.TagName.split("::")
       
  4370         self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
       
  4371         self.Controler.BufferProject()
       
  4372         self.ParentWindow.RefreshEditor(variablepanel = False)
       
  4373         self.ParentWindow.RefreshTitle()
       
  4374         self.ParentWindow.RefreshEditMenu()
       
  4375         self.ParentWindow.RefreshInstancesTree()
       
  4376         self.ParentWindow.RefreshLibraryTree()
       
  4377         event.Skip()
       
  4378     
       
  4379     def OnClassFilter(self, event):
       
  4380         self.Filter = self.FilterChoiceTransfer[self.ClassFilter.GetStringSelection()]
       
  4381         self.RefreshTypeList()
       
  4382         self.RefreshValues()
       
  4383         self.RefreshButtons()
       
  4384         event.Skip()
       
  4385 
       
  4386     def RefreshTypeList(self):
       
  4387         if self.Filter == "All":
       
  4388             self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]]
       
  4389         elif self.Filter == "Interface":
       
  4390             self.ClassList = ["Input","Output","InOut","External"]
       
  4391         elif self.Filter == "Variables":
       
  4392             self.ClassList = ["Local","Temp"]
       
  4393         else:
       
  4394             self.ClassList = [self.Filter]
       
  4395 
       
  4396     def RefreshButtons(self):
       
  4397         if getattr(self, "Table", None):
       
  4398             table_length = len(self.Table.data)
       
  4399             row_class = None
       
  4400             row_edit = True
       
  4401             if table_length > 0:
       
  4402                 row = self.VariablesGrid.GetGridCursorRow()
       
  4403                 row_edit = self.Table.GetValueByName(row, "Edit")
       
  4404                 if self.PouIsUsed:
       
  4405                     row_class = self.Table.GetValueByName(row, "Class")
       
  4406             self.AddButton.Enable(not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"])
       
  4407             self.DeleteButton.Enable(table_length > 0 and row_edit and row_class not in ["Input", "Output", "InOut"])
       
  4408             self.UpButton.Enable(table_length > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
       
  4409             self.DownButton.Enable(table_length > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
       
  4410 
       
  4411     def OnAddButton(self, event):
       
  4412         new_row = self.DefaultValue.copy()
       
  4413         if self.Filter in self.DefaultTypes:
       
  4414             new_row["Class"] = self.DefaultTypes[self.Filter]
       
  4415         else:
       
  4416             new_row["Class"] = self.Filter
       
  4417         if self.Filter == "All" and len(self.Values) > 0:
       
  4418             row_index = self.VariablesGrid.GetGridCursorRow() + 1
       
  4419             self.Values.insert(row_index, new_row)
       
  4420         else:
       
  4421             row_index = -1
       
  4422             self.Values.append(new_row)
       
  4423         self.SaveValues()
       
  4424         self.RefreshValues(row_index)
       
  4425         self.RefreshButtons()
       
  4426         event.Skip()
       
  4427 
       
  4428     def OnDeleteButton(self, event):
       
  4429         row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
       
  4430         self.Values.remove(row)
       
  4431         self.SaveValues()
       
  4432         self.RefreshValues()
       
  4433         self.RefreshButtons()
       
  4434         event.Skip()
       
  4435 
       
  4436     def OnUpButton(self, event):
       
  4437         self.MoveValue(self.VariablesGrid.GetGridCursorRow(), -1)
       
  4438         self.RefreshButtons()
       
  4439         event.Skip()
       
  4440 
       
  4441     def OnDownButton(self, event):
       
  4442         self.MoveValue(self.VariablesGrid.GetGridCursorRow(), 1)
       
  4443         self.RefreshButtons()
       
  4444         event.Skip()
       
  4445 
       
  4446     def OnVariablesGridCellChange(self, event):
       
  4447         row, col = event.GetRow(), event.GetCol()
       
  4448         colname = self.Table.GetColLabelValue(col)
       
  4449         value = self.Table.GetValue(row, col)
       
  4450         if colname == "Name" and value != "":
       
  4451             if not TestIdentifier(value):
       
  4452                 message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
  4453                 message.ShowModal()
       
  4454                 message.Destroy()
       
  4455                 event.Veto()
       
  4456             elif value.upper() in IEC_KEYWORDS:
       
  4457                 message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
  4458                 message.ShowModal()
       
  4459                 message.Destroy()
       
  4460                 event.Veto()
       
  4461             elif value.upper() in self.PouNames:
       
  4462                 message = wx.MessageDialog(self, _("A pou with \"%s\" as name exists!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
  4463                 message.ShowModal()
       
  4464                 message.Destroy()
       
  4465                 event.Veto()
       
  4466             elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]:
       
  4467                 message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
  4468                 message.ShowModal()
       
  4469                 message.Destroy()
       
  4470                 event.Veto()
       
  4471             else:
       
  4472                 self.SaveValues(False)
       
  4473                 old_value = self.Table.GetOldValue()
       
  4474                 if old_value != "":
       
  4475                     self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
       
  4476                 self.Controler.BufferProject()
       
  4477                 self.ParentWindow.RefreshEditor(variablepanel = False)
       
  4478                 self.ParentWindow.RefreshTitle()
       
  4479                 self.ParentWindow.RefreshEditMenu()
       
  4480                 self.ParentWindow.RefreshInstancesTree()
       
  4481                 self.ParentWindow.RefreshLibraryTree()
       
  4482                 event.Skip()
       
  4483         else:
       
  4484             self.SaveValues()
       
  4485             if colname == "Class":
       
  4486                 self.Table.ResetView(self.VariablesGrid)
       
  4487             event.Skip()
       
  4488     
       
  4489     def OnVariablesGridEditorShown(self, event):
       
  4490         row, col = event.GetRow(), event.GetCol() 
       
  4491         classtype = self.Table.GetValueByName(row, "Class")
       
  4492         if self.Table.GetColLabelValue(col) == "Type":
       
  4493             type_menu = wx.Menu(title='')
       
  4494             base_menu = wx.Menu(title='')
       
  4495             for base_type in self.Controler.GetBaseTypes():
       
  4496                 new_id = wx.NewId()
       
  4497                 AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
       
  4498                 self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
       
  4499             type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu)
       
  4500             datatype_menu = wx.Menu(title='')
       
  4501             for datatype in self.Controler.GetDataTypes(basetypes = False, debug = self.ParentWindow.Debug):
       
  4502                 new_id = wx.NewId()
       
  4503                 AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
       
  4504                 self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
       
  4505             type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu)
       
  4506             functionblock_menu = wx.Menu(title='')
       
  4507             bodytype = self.Controler.GetEditedElementBodyType(self.TagName, self.ParentWindow.Debug)
       
  4508             pouname, poutype = self.Controler.GetEditedElementType(self.TagName, self.ParentWindow.Debug)
       
  4509             if classtype in ["Input","Output","InOut","External","Global"] or poutype != "function" and bodytype in ["ST", "IL"]:
       
  4510                 for functionblock_type in self.Controler.GetFunctionBlockTypes(self.TagName, self.ParentWindow.Debug):
       
  4511                     new_id = wx.NewId()
       
  4512                     AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
       
  4513                     self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
       
  4514                 type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
       
  4515             rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
       
  4516             self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize())
       
  4517             event.Veto()
       
  4518         else:
       
  4519             event.Skip()
       
  4520     
       
  4521     def GetVariableTypeFunction(self, base_type):
       
  4522         def VariableTypeFunction(event):
       
  4523             row = self.VariablesGrid.GetGridCursorRow()
       
  4524             self.Table.SetValueByName(row, "Type", base_type)
       
  4525             self.Table.ResetView(self.VariablesGrid)
       
  4526             self.SaveValues(False)
       
  4527             self.ParentWindow.RefreshEditor(variablepanel = False)
       
  4528             self.Controler.BufferProject()
       
  4529             self.ParentWindow.RefreshTitle()
       
  4530             self.ParentWindow.RefreshEditMenu()
       
  4531             self.ParentWindow.RefreshInstancesTree()
       
  4532             self.ParentWindow.RefreshLibraryTree()
       
  4533             event.Skip()
       
  4534         return VariableTypeFunction
       
  4535     
       
  4536     def OnVariablesGridCellLeftClick(self, event):
       
  4537         row = event.GetRow()
       
  4538         if event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit"):
       
  4539             row = event.GetRow()
       
  4540             var_name = self.Table.GetValueByName(row, "Name")
       
  4541             var_class = self.Table.GetValueByName(row, "Class")
       
  4542             var_type = self.Table.GetValueByName(row, "Type")
       
  4543             data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName)))
       
  4544             dragSource = wx.DropSource(self.VariablesGrid)
       
  4545             dragSource.SetData(data)
       
  4546             dragSource.DoDragDrop()
       
  4547         event.Skip()
       
  4548     
       
  4549     def OnVariablesGridSelectCell(self, event):
       
  4550         wx.CallAfter(self.RefreshButtons)
       
  4551         event.Skip()
       
  4552 
       
  4553     def OnChar(self, event):
       
  4554         keycode = event.GetKeyCode()
       
  4555         if keycode == wx.WXK_DELETE:
       
  4556             row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
       
  4557             self.Values.remove(row)
       
  4558             self.SaveValues()
       
  4559             self.RefreshValues()
       
  4560             self.RefreshButtons()
       
  4561         event.Skip()
       
  4562 
       
  4563     def MoveValue(self, value_index, move):
       
  4564         new_index = max(0, min(value_index + move, len(self.Values) - 1))
       
  4565         if new_index != value_index:
       
  4566             self.Values.insert(new_index, self.Values.pop(value_index))
       
  4567             self.SaveValues()
       
  4568             self.RefreshValues()
       
  4569             self.VariablesGrid.SetGridCursor(new_index, self.VariablesGrid.GetGridCursorCol())
       
  4570         
       
  4571     def RefreshValues(self, select=0):
       
  4572         if len(self.Table.data) > 0:
       
  4573             self.VariablesGrid.SetGridCursor(0, 1)
       
  4574         data = []
       
  4575         for num, variable in enumerate(self.Values):
       
  4576             if variable["Class"] in self.ClassList:
       
  4577                 variable["Number"] = num + 1
       
  4578                 data.append(variable)
       
  4579         self.Table.SetData(data)
       
  4580         if len(self.Table.data) > 0:
       
  4581             if select == -1:
       
  4582                 select = len(self.Table.data) - 1
       
  4583             self.VariablesGrid.SetGridCursor(select, 1)
       
  4584             self.VariablesGrid.MakeCellVisible(select, 1)
       
  4585         self.Table.ResetView(self.VariablesGrid)
       
  4586 
       
  4587     def SaveValues(self, buffer = True):
       
  4588         words = self.TagName.split("::")
       
  4589         if self.ElementType == "config":
       
  4590             self.Controler.SetConfigurationGlobalVars(words[1], self.Values)
       
  4591         elif self.ElementType == "resource":
       
  4592             self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values)
       
  4593         else:
       
  4594             if self.ReturnType.IsEnabled():
       
  4595                 self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
       
  4596             self.Controler.SetPouInterfaceVars(words[1], self.Values)
       
  4597         if buffer:
       
  4598             self.Controler.BufferProject()
       
  4599             self.ParentWindow.RefreshTitle()
       
  4600             self.ParentWindow.RefreshEditMenu()
       
  4601             self.ParentWindow.RefreshInstancesTree()
       
  4602             self.ParentWindow.RefreshLibraryTree()
       
  4603 
       
  4604     def AddVariableError(self, infos):
       
  4605         if isinstance(infos[0], TupleType):
       
  4606             for i in xrange(*infos[0]):
       
  4607                 self.Table.AddError((i,) + infos[1:])
       
  4608         else:
       
  4609             self.Table.AddError(infos)
       
  4610         self.Table.ResetView(self.VariablesGrid)
       
  4611 
       
  4612     def ClearErrors(self):
       
  4613         self.Table.ClearErrors()
       
  4614         self.Table.ResetView(self.VariablesGrid)
       
  4615 
       
  4616 #-------------------------------------------------------------------------------
       
  4617 #                            Debug Variables Panel
  3850 #                            Debug Variables Panel
  4618 #-------------------------------------------------------------------------------
  3851 #-------------------------------------------------------------------------------
  4619 
  3852 
  4620 def GetDebugVariablesTableColnames():
  3853 def GetDebugVariablesTableColnames():
  4621     _ = lambda x : x
  3854     _ = lambda x : x