controls/VariablePanel.py
changeset 625 b7062a7018ec
parent 623 e747685e4241
child 627 99ab0b74865f
equal deleted inserted replaced
624:efedc9d06a59 625:b7062a7018ec
    27 import re
    27 import re
    28 
    28 
    29 from types import TupleType, StringType, UnicodeType
    29 from types import TupleType, StringType, UnicodeType
    30 
    30 
    31 from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS
    31 from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS
    32 from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD
    32 from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD, ERROR_HIGHLIGHT
    33 from dialogs.ArrayTypeDialog import ArrayTypeDialog
    33 from dialogs.ArrayTypeDialog import ArrayTypeDialog
    34 from CustomGrid import CustomGrid
    34 from CustomGrid import CustomGrid
    35 from CustomTable import CustomTable
    35 from CustomTable import CustomTable
    36 from LocationCellEditor import LocationCellEditor
    36 from LocationCellEditor import LocationCellEditor
    37 
    37 
    84                        "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
    84                        "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
    85                        "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""),
    85                        "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""),
    86                        "External": lambda x: {"Constant": "Constant"}.get(x, "")
    86                        "External": lambda x: {"Constant": "Constant"}.get(x, "")
    87                       }
    87                       }
    88 
    88 
    89 LOCATION_MODEL = re.compile("((?:%[IQM](?:\*|(?:[XBWLD]?[0-9](?:\.[0-9])*)))?)$")
    89 LOCATION_MODEL = re.compile("((?:%[IQM](?:\*|(?:[XBWLD]?[0-9]+(?:\.[0-9]+)*)))?)$")
    90 
    90 
    91 class VariableTable(CustomTable):
    91 class VariableTable(CustomTable):
    92     
    92     
    93     """
    93     """
    94     A custom wx.grid.Grid Table using user supplied data
    94     A custom wx.grid.Grid Table using user supplied data
   196                         grid.SetReadOnly(row, col, True)
   196                         grid.SetReadOnly(row, col, True)
   197                 
   197                 
   198                 grid.SetCellEditor(row, col, editor)
   198                 grid.SetCellEditor(row, col, editor)
   199                 grid.SetCellRenderer(row, col, renderer)
   199                 grid.SetCellRenderer(row, col, renderer)
   200                 
   200                 
   201                 highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
   201                 if colname == "Location" and LOCATION_MODEL.match(self.GetValueByName(row, "Location")) is None:
       
   202                     highlight_colours = ERROR_HIGHLIGHT
       
   203                 else:
       
   204                     highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
   202                 grid.SetCellBackgroundColour(row, col, highlight_colours[0])
   205                 grid.SetCellBackgroundColour(row, col, highlight_colours[0])
   203                 grid.SetCellTextColour(row, col, highlight_colours[1])
   206                 grid.SetCellTextColour(row, col, highlight_colours[1])
   204             self.ResizeRow(grid, row)
   207             self.ResizeRow(grid, row)
   205                     
   208                     
   206 
   209 
   304         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   307         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   305         message.ShowModal()
   308         message.ShowModal()
   306         message.Destroy()
   309         message.Destroy()
   307 
   310 
   308 [ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, 
   311 [ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, 
   309  ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE, 
   312  ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPELABEL, 
       
   313  ID_VARIABLEEDITORPANELRETURNTYPE, ID_VARIABLEEDITORPANELDESCRIPTIONLABEL, 
       
   314  ID_VARIABLEEDITORPANELDESCRIPTION, ID_VARIABLEEDITORPANELCLASSFILTERLABEL, 
   310  ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, 
   315  ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, 
   311  ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, 
   316  ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, 
   312  ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1, 
   317  ID_VARIABLEEDITORPANELDOWNBUTTON, 
   313  ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3,
   318 ] = [wx.NewId() for _init_ctrls in range(13)]
   314 ] = [wx.NewId() for _init_ctrls in range(12)]
       
   315 
   319 
   316 class VariablePanel(wx.Panel):
   320 class VariablePanel(wx.Panel):
   317     
   321     
   318     if wx.VERSION < (2, 6, 0):
   322     if wx.VERSION < (2, 6, 0):
   319         def Bind(self, event, function, id = None):
   323         def Bind(self, event, function, id = None):
   329     def _init_coll_MainSizer_Growables(self, parent):
   333     def _init_coll_MainSizer_Growables(self, parent):
   330         parent.AddGrowableCol(0)
   334         parent.AddGrowableCol(0)
   331         parent.AddGrowableRow(1)
   335         parent.AddGrowableRow(1)
   332     
   336     
   333     def _init_coll_ControlPanelSizer_Items(self, parent):
   337     def _init_coll_ControlPanelSizer_Items(self, parent):
   334         parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
   338         parent.AddWindow(self.ReturnTypeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
   335         parent.AddWindow(self.ReturnType, 0, border=0, flag=0)
   339         parent.AddWindow(self.ReturnType, 0, border=0, flag=0)
   336         parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
   340         parent.AddWindow(self.DescriptionLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   341         parent.AddWindow(self.Description, 0, border=0, flag=0)
       
   342         parent.AddWindow(self.ClassFilterLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
   337         parent.AddWindow(self.ClassFilter, 0, border=0, flag=0)
   343         parent.AddWindow(self.ClassFilter, 0, border=0, flag=0)
   338         parent.AddWindow(self.AddButton, 0, border=0, flag=0)
   344         parent.AddWindow(self.AddButton, 0, border=0, flag=0)
   339         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
   345         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
   340         parent.AddWindow(self.UpButton, 0, border=0, flag=0)
   346         parent.AddWindow(self.UpButton, 0, border=0, flag=0)
   341         parent.AddWindow(self.DownButton, 0, border=0, flag=0)
   347         parent.AddWindow(self.DownButton, 0, border=0, flag=0)
   344         parent.AddGrowableCol(3)
   350         parent.AddGrowableCol(3)
   345         parent.AddGrowableRow(0)
   351         parent.AddGrowableRow(0)
   346 
   352 
   347     def _init_sizers(self):
   353     def _init_sizers(self):
   348         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
   354         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
   349         self.ControlPanelSizer = wx.FlexGridSizer(cols=8, hgap=5, rows=1, vgap=5)
   355         self.ControlPanelSizer = wx.FlexGridSizer(cols=10, hgap=5, rows=1, vgap=5)
   350         
   356         
   351         self._init_coll_MainSizer_Items(self.MainSizer)
   357         self._init_coll_MainSizer_Items(self.MainSizer)
   352         self._init_coll_MainSizer_Growables(self.MainSizer)
   358         self._init_coll_MainSizer_Growables(self.MainSizer)
   353         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
   359         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
   354         self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer)
   360         self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer)
   377         self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
   383         self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
   378               name='ControlPanel', parent=self, pos=wx.Point(0, 0),
   384               name='ControlPanel', parent=self, pos=wx.Point(0, 0),
   379               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
   385               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
   380         self.ControlPanel.SetScrollRate(10, 0)
   386         self.ControlPanel.SetScrollRate(10, 0)
   381         
   387         
   382         self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1,
   388         self.ReturnTypeLabel = wx.StaticText(id=ID_VARIABLEEDITORPANELRETURNTYPELABEL,
   383               label=_('Return Type:'), name='staticText1', parent=self.ControlPanel,
   389               label=_('Return Type:'), name='ReturnTypeLabel', parent=self.ControlPanel,
   384               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   390               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   385 
   391 
   386         self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE,
   392         self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE,
   387               name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0),
   393               name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0),
   388               size=wx.Size(145, 28), style=wx.CB_READONLY)
   394               size=wx.Size(145, 28), style=wx.CB_READONLY)
   389         self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE)
   395         self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE)
   390 
   396 
   391         self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2,
   397         self.DescriptionLabel = wx.StaticText(id=ID_VARIABLEEDITORPANELDESCRIPTIONLABEL,
   392               label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel,
   398               label=_('Description:'), name='DescriptionLabel', parent=self.ControlPanel,
       
   399               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   400 
       
   401         self.Description = wx.TextCtrl(id=ID_VARIABLEEDITORPANELDESCRIPTION,
       
   402               name='Description', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   403               size=wx.Size(250, 28), style=wx.TE_PROCESS_ENTER)
       
   404         self.Bind(wx.EVT_TEXT_ENTER, self.OnDescriptionChanged, id=ID_VARIABLEEDITORPANELDESCRIPTION)
       
   405         self.Description.Bind(wx.EVT_KILL_FOCUS, self.OnDescriptionChanged)
       
   406         
       
   407         self.ClassFilterLabel = wx.StaticText(id=ID_VARIABLEEDITORPANELCLASSFILTERLABEL,
       
   408               label=_('Class Filter:'), name='ClassFilterLabel', parent=self.ControlPanel,
   393               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   409               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   394 
   410 
   395         self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER,
   411         self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER,
   396               name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0),
   412               name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0),
   397               size=wx.Size(145, 28), style=wx.CB_READONLY)
   413               size=wx.Size(145, 28), style=wx.CB_READONLY)
   575         else:
   591         else:
   576             return name in self.Controler.GetFunctionBlockTypes(self.TagName)
   592             return name in self.Controler.GetFunctionBlockTypes(self.TagName)
   577     
   593     
   578     def RefreshView(self):
   594     def RefreshView(self):
   579         self.PouNames = self.Controler.GetProjectPouNames(self.Debug)
   595         self.PouNames = self.Controler.GetProjectPouNames(self.Debug)
       
   596         returnType = None
       
   597         description = None
   580         
   598         
   581         words = self.TagName.split("::")
   599         words = self.TagName.split("::")
   582         if self.ElementType == "config":
   600         if self.ElementType == "config":
   583             self.PouIsUsed = False
   601             self.PouIsUsed = False
   584             returnType = None
       
   585             self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.Debug)
   602             self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.Debug)
   586         elif self.ElementType == "resource":
   603         elif self.ElementType == "resource":
   587             self.PouIsUsed = False
   604             self.PouIsUsed = False
   588             returnType = None
       
   589             self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2], self.Debug)
   605             self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2], self.Debug)
   590         else:
   606         else:
   591             if self.ElementType == "function":
   607             if self.ElementType == "function":
   592                 self.ReturnType.Clear()
   608                 self.ReturnType.Clear()
   593                 for base_type in self.Controler.GetDataTypes(self.TagName, True, debug=self.Debug):
   609                 for base_type in self.Controler.GetDataTypes(self.TagName, True, debug=self.Debug):
   594                     self.ReturnType.Append(base_type)
   610                     self.ReturnType.Append(base_type)
   595                 returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName)
   611                 returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName)
   596             else:
   612             description = self.Controler.GetPouDescription(words[1])
   597                 returnType = None
       
   598             self.PouIsUsed = self.Controler.PouIsUsed(words[1])
   613             self.PouIsUsed = self.Controler.PouIsUsed(words[1])
   599             self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
   614             self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
   600         
   615         
   601         if returnType is not None:
   616         if returnType is not None:
   602             self.ReturnType.SetStringSelection(returnType)
   617             self.ReturnType.SetStringSelection(returnType)
   603             self.ReturnType.Enable(self.Debug)
   618             self.ReturnType.Enable(not self.Debug)
   604             self.staticText1.Show()
   619             self.ReturnTypeLabel.Show()
   605             self.ReturnType.Show()
   620             self.ReturnType.Show()
   606         else:
   621         else:
   607             self.ReturnType.Enable(False)
   622             self.ReturnType.Enable(False)
   608             self.staticText1.Hide()
   623             self.ReturnTypeLabel.Hide()
   609             self.ReturnType.Hide()
   624             self.ReturnType.Hide()
       
   625         
       
   626         if description is not None:
       
   627             self.Description.SetValue(description)
       
   628             self.Description.Enable(not self.Debug)
       
   629             self.DescriptionLabel.Show()
       
   630             self.Description.Show()
       
   631         else:
       
   632             self.Description.Enable(False)
       
   633             self.DescriptionLabel.Hide()
       
   634             self.Description.Hide()
   610         
   635         
   611         self.RefreshValues()
   636         self.RefreshValues()
   612         self.VariablesGrid.RefreshButtons()
   637         self.VariablesGrid.RefreshButtons()
   613     
   638     
   614     def OnReturnTypeChanged(self, event):
   639     def OnReturnTypeChanged(self, event):
   615         words = self.TagName.split("::")
   640         words = self.TagName.split("::")
   616         self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
   641         self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
   617         self.Controler.BufferProject()
   642         self.Controler.BufferProject()
   618         self.ParentWindow.RefreshView(variablepanel = False)
   643         self.ParentWindow.RefreshView(variablepanel = False)
   619         self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
   644         self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
       
   645         event.Skip()
       
   646     
       
   647     def OnDescriptionChanged(self, event):
       
   648         words = self.TagName.split("::")
       
   649         old_description = self.Controler.GetPouDescription(words[1])
       
   650         new_description = self.Description.GetValue()
       
   651         if new_description != old_description:
       
   652             self.Controler.SetPouDescription(words[1], new_description)
       
   653             self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
   620         event.Skip()
   654         event.Skip()
   621     
   655     
   622     def OnClassFilter(self, event):
   656     def OnClassFilter(self, event):
   623         self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]]
   657         self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]]
   624         self.RefreshTypeList()
   658         self.RefreshTypeList()
   658                     self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
   692                     self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
   659                 self.Controler.BufferProject()
   693                 self.Controler.BufferProject()
   660                 self.ParentWindow.RefreshView(variablepanel = False)
   694                 self.ParentWindow.RefreshView(variablepanel = False)
   661                 self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
   695                 self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
   662                 event.Skip()
   696                 event.Skip()
   663         elif colname == "Location" and LOCATION_MODEL.match(value) is None:
       
   664             message =  _("\"%s\" is not a valid location!") % value
       
   665         else:
   697         else:
   666             self.SaveValues()
   698             self.SaveValues()
   667             if colname == "Class":
   699             if colname == "Class":
   668                 self.ParentWindow.RefreshView(variablepanel = False)
   700                 self.ParentWindow.RefreshView(variablepanel = False)
       
   701             elif colname == "Location":
       
   702                 wx.CallAfter(self.ParentWindow.RefreshView)
   669             
   703             
   670         if message is not None:
   704         if message is not None:
   671             dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
   705             dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
   672             dialog.ShowModal()
   706             dialog.ShowModal()
   673             dialog.Destroy()
   707             dialog.Destroy()