Beremiz.py
changeset 717 1c23952dbde1
parent 716 180e4a7d945c
child 718 5d4dc150b956
equal deleted inserted replaced
716:180e4a7d945c 717:1c23952dbde1
   144 
   144 
   145 import wx.lib.buttons, wx.lib.statbmp
   145 import wx.lib.buttons, wx.lib.statbmp
   146 import TextCtrlAutoComplete, cPickle
   146 import TextCtrlAutoComplete, cPickle
   147 from BrowseValuesLibraryDialog import BrowseValuesLibraryDialog
   147 from BrowseValuesLibraryDialog import BrowseValuesLibraryDialog
   148 import types, time, re, platform, time, traceback, commands
   148 import types, time, re, platform, time, traceback, commands
   149 from plugger import PluginsRoot, MiniTextControler, MATIEC_ERROR_MODEL
   149 from ConfigTree import ConfigTreeRoot, MiniTextControler, MATIEC_ERROR_MODEL
   150 from wxPopen import ProcessLogger
   150 from wxPopen import ProcessLogger
   151 
   151 
   152 from docutils import *
   152 from docutils import *
   153 from PLCOpenEditor import IDEFrame, AppendMenu, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES, USE_AUI
   153 from PLCOpenEditor import IDEFrame, AppendMenu, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES, USE_AUI
   154 from PLCOpenEditor import EditorPanel, Viewer, TextViewer, GraphicViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor
   154 from PLCOpenEditor import EditorPanel, Viewer, TextViewer, GraphicViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor
   155 from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
   155 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
   156 
   156 
   157 SCROLLBAR_UNIT = 10
   157 SCROLLBAR_UNIT = 10
   158 WINDOW_COLOUR = wx.Colour(240,240,240)
   158 WINDOW_COLOUR = wx.Colour(240,240,240)
   159 TITLE_COLOUR = wx.Colour(200,200,220)
   159 TITLE_COLOUR = wx.Colour(200,200,220)
   160 CHANGED_TITLE_COLOUR = wx.Colour(220,200,220)
   160 CHANGED_TITLE_COLOUR = wx.Colour(220,200,220)
   376  ID_BEREMIZINSPECTOR] = [wx.NewId() for _init_ctrls in range(5)]
   376  ID_BEREMIZINSPECTOR] = [wx.NewId() for _init_ctrls in range(5)]
   377 
   377 
   378 [ID_FILEMENURECENTPROJECTS,
   378 [ID_FILEMENURECENTPROJECTS,
   379 ] = [wx.NewId() for _init_ctrls in range(1)]
   379 ] = [wx.NewId() for _init_ctrls in range(1)]
   380 
   380 
   381 PLUGINMENU_POSITION = 3
   381 CONFNODEMENU_POSITION = 3
   382 
   382 
   383 class Beremiz(IDEFrame):
   383 class Beremiz(IDEFrame):
   384 	
   384 	
   385     def _init_coll_MenuBar_Menus(self, parent):
   385     def _init_coll_MenuBar_Menus(self, parent):
   386         IDEFrame._init_coll_MenuBar_Menus(self, parent)
   386         IDEFrame._init_coll_MenuBar_Menus(self, parent)
   387         
   387         
   388         parent.Insert(pos=PLUGINMENU_POSITION, 
   388         parent.Insert(pos=CONFNODEMENU_POSITION, 
   389                       menu=self.PluginMenu, title=_(u'&Plugin'))
   389                       menu=self.ConfNodeMenu, title=_(u'&ConfNode'))
   390     
   390     
   391     def _init_utils(self):
   391     def _init_utils(self):
   392         self.PluginMenu = wx.Menu(title='')
   392         self.ConfNodeMenu = wx.Menu(title='')
   393         self.RecentProjectsMenu = wx.Menu(title='')
   393         self.RecentProjectsMenu = wx.Menu(title='')
   394         
   394         
   395         IDEFrame._init_utils(self)
   395         IDEFrame._init_utils(self)
   396         
   396         
   397     def _init_coll_FileMenu_Items(self, parent):
   397     def _init_coll_FileMenu_Items(self, parent):
   449         self.Bind(wx.EVT_MENU, self.OnBeremizMenu, id=wx.ID_HELP)
   449         self.Bind(wx.EVT_MENU, self.OnBeremizMenu, id=wx.ID_HELP)
   450         self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
   450         self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
   451     
   451     
   452     def _init_coll_PLCConfigMainSizer_Items(self, parent):
   452     def _init_coll_PLCConfigMainSizer_Items(self, parent):
   453         parent.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
   453         parent.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
   454         parent.AddSizer(self.PluginTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT)
   454         parent.AddSizer(self.ConfNodeTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT)
   455         
   455         
   456     def _init_coll_PLCConfigMainSizer_Growables(self, parent):
   456     def _init_coll_PLCConfigMainSizer_Growables(self, parent):
   457         parent.AddGrowableCol(0)
   457         parent.AddGrowableCol(0)
   458         parent.AddGrowableRow(1)
   458         parent.AddGrowableRow(1)
   459     
   459     
   460     def _init_coll_PluginTreeSizer_Growables(self, parent):
   460     def _init_coll_ConfNodeTreeSizer_Growables(self, parent):
   461         parent.AddGrowableCol(0)
   461         parent.AddGrowableCol(0)
   462         parent.AddGrowableCol(1)
   462         parent.AddGrowableCol(1)
   463         
   463         
   464     def _init_beremiz_sizers(self):
   464     def _init_beremiz_sizers(self):
   465         self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
   465         self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
   466         self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL)
   466         self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL)
   467         #self.PluginTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2)
   467         #self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2)
   468         self.PluginTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2)
   468         self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2)
   469         
   469         
   470         self._init_coll_PLCConfigMainSizer_Items(self.PLCConfigMainSizer)
   470         self._init_coll_PLCConfigMainSizer_Items(self.PLCConfigMainSizer)
   471         self._init_coll_PLCConfigMainSizer_Growables(self.PLCConfigMainSizer)
   471         self._init_coll_PLCConfigMainSizer_Growables(self.PLCConfigMainSizer)
   472         self._init_coll_PluginTreeSizer_Growables(self.PluginTreeSizer)
   472         self._init_coll_ConfNodeTreeSizer_Growables(self.ConfNodeTreeSizer)
   473         
   473         
   474         self.PLCConfig.SetSizer(self.PLCConfigMainSizer)
   474         self.PLCConfig.SetSizer(self.PLCConfigMainSizer)
   475         
   475         
   476     def _init_ctrls(self, prnt):
   476     def _init_ctrls(self, prnt):
   477         IDEFrame._init_ctrls(self, prnt)
   477         IDEFrame._init_ctrls(self, prnt)
   483                                 ("Transfer", wx.WXK_F6),
   483                                 ("Transfer", wx.WXK_F6),
   484                                 ("Connect",  wx.WXK_F7),
   484                                 ("Connect",  wx.WXK_F7),
   485                                 ("Build",    wx.WXK_F11)]:
   485                                 ("Build",    wx.WXK_F11)]:
   486             def OnMethodGen(obj,meth):
   486             def OnMethodGen(obj,meth):
   487                 def OnMethod(evt):
   487                 def OnMethod(evt):
   488                     if obj.PluginRoot is not None:
   488                     if obj.CTR is not None:
   489                        obj.PluginRoot.CallMethod('_'+meth)
   489                        obj.CTR.CallMethod('_'+meth)
   490                     wx.CallAfter(self.RefreshAll)
   490                     wx.CallAfter(self.RefreshAll)
   491                 return OnMethod
   491                 return OnMethod
   492             newid = wx.NewId()
   492             newid = wx.NewId()
   493             self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
   493             self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
   494             accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
   494             accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
   514         if USE_AUI:
   514         if USE_AUI:
   515             self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT)
   515             self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT)
   516         
   516         
   517         self._init_beremiz_sizers()
   517         self._init_beremiz_sizers()
   518 
   518 
   519     def __init__(self, parent, projectOpen=None, buildpath=None, plugin_root=None, debug=True):
   519     def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
   520         IDEFrame.__init__(self, parent, debug)
   520         IDEFrame.__init__(self, parent, debug)
   521         self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
   521         self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
   522         
   522         
   523         self.local_runtime = None
   523         self.local_runtime = None
   524         self.runtime_port = None
   524         self.runtime_port = None
   528         # Variable allowing disabling of PLCConfig scroll when Popup shown 
   528         # Variable allowing disabling of PLCConfig scroll when Popup shown 
   529         self.ScrollingEnabled = True
   529         self.ScrollingEnabled = True
   530         
   530         
   531         self.LastPanelSelected = None
   531         self.LastPanelSelected = None
   532         
   532         
   533         self.PluginInfos = {}
   533         self.ConfNodeInfos = {}
   534         
   534         
   535         # Define Tree item icon list
   535         # Define Tree item icon list
   536         self.LocationImageList = wx.ImageList(16, 16)
   536         self.LocationImageList = wx.ImageList(16, 16)
   537         self.LocationImageDict = {}
   537         self.LocationImageDict = {}
   538         
   538         
   539         # Icons for location items
   539         # Icons for location items
   540         for imgname, itemtype in [
   540         for imgname, itemtype in [
   541             ("CONFIGURATION", LOCATION_PLUGIN),
   541             ("CONFIGURATION", LOCATION_CONFNODE),
   542             ("RESOURCE",      LOCATION_MODULE),
   542             ("RESOURCE",      LOCATION_MODULE),
   543             ("PROGRAM",       LOCATION_GROUP),
   543             ("PROGRAM",       LOCATION_GROUP),
   544             ("VAR_INPUT",     LOCATION_VAR_INPUT),
   544             ("VAR_INPUT",     LOCATION_VAR_INPUT),
   545             ("VAR_OUTPUT",    LOCATION_VAR_OUTPUT),
   545             ("VAR_OUTPUT",    LOCATION_VAR_OUTPUT),
   546             ("VAR_LOCAL",     LOCATION_VAR_MEMORY)]:
   546             ("VAR_LOCAL",     LOCATION_VAR_MEMORY)]:
   553             projectOpen = str(self.Config.Read("currenteditedproject"))
   553             projectOpen = str(self.Config.Read("currenteditedproject"))
   554             if projectOpen == "":
   554             if projectOpen == "":
   555                 projectOpen = None
   555                 projectOpen = None
   556         
   556         
   557         if projectOpen is not None and os.path.isdir(projectOpen):
   557         if projectOpen is not None and os.path.isdir(projectOpen):
   558             self.PluginRoot = PluginsRoot(self, self.Log)
   558             self.CTR = ConfigTreeRoot(self, self.Log)
   559             self.Controler = self.PluginRoot
   559             self.Controler = self.CTR
   560             result = self.PluginRoot.LoadProject(projectOpen, buildpath)
   560             result = self.CTR.LoadProject(projectOpen, buildpath)
   561             if not result:
   561             if not result:
   562                 self.LibraryPanel.SetControler(self.Controler)
   562                 self.LibraryPanel.SetControler(self.Controler)
   563                 self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
   563                 self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
   564                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
   564                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
   565                 self.RefreshAll()
   565                 self.RefreshAll()
   566             else:
   566             else:
   567                 self.ResetView()
   567                 self.ResetView()
   568                 self.ShowErrorMessage(result)
   568                 self.ShowErrorMessage(result)
   569         else:
   569         else:
   570             self.PluginRoot = plugin_root
   570             self.CTR = ctr
   571             self.Controler = plugin_root
   571             self.Controler = ctr
   572             if plugin_root is not None:
   572             if ctr is not None:
   573                 self.LibraryPanel.SetControler(self.Controler)
   573                 self.LibraryPanel.SetControler(self.Controler)
   574                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
   574                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
   575                 self.RefreshAll()
   575                 self.RefreshAll()
   576         if self.EnableDebug:
   576         if self.EnableDebug:
   577             self.DebugVariablePanel.SetDataProducer(self.PluginRoot)
   577             self.DebugVariablePanel.SetDataProducer(self.CTR)
   578         
   578         
   579         self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
   579         self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
   580         
   580         
   581         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
   581         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
   582         self.RefreshPluginMenu()
   582         self.RefreshConfNodeMenu()
   583         self.LogConsole.SetFocus()
   583         self.LogConsole.SetFocus()
   584 
   584 
   585     def RiseLogConsole(self):
   585     def RiseLogConsole(self):
   586         self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
   586         self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
   587         
   587         
   588     def RefreshTitle(self):
   588     def RefreshTitle(self):
   589         name = _("Beremiz")
   589         name = _("Beremiz")
   590         if self.PluginRoot is not None:
   590         if self.CTR is not None:
   591             projectname = self.PluginRoot.GetProjectName()
   591             projectname = self.CTR.GetProjectName()
   592             if self.PluginRoot.ProjectTestModified():
   592             if self.CTR.ProjectTestModified():
   593                 projectname = "~%s~" % projectname
   593                 projectname = "~%s~" % projectname
   594             self.SetTitle("%s - %s" % (name, projectname))
   594             self.SetTitle("%s - %s" % (name, projectname))
   595         else:
   595         else:
   596             self.SetTitle(name)
   596             self.SetTitle(name)
   597 
   597 
   638     def OnLogConsoleDClick(self, event):
   638     def OnLogConsoleDClick(self, event):
   639         wx.CallAfter(self.SearchLineForError)
   639         wx.CallAfter(self.SearchLineForError)
   640         event.Skip()
   640         event.Skip()
   641 
   641 
   642     def SearchLineForError(self):
   642     def SearchLineForError(self):
   643         if self.PluginRoot is not None:
   643         if self.CTR is not None:
   644             text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint())
   644             text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint())
   645             line = self.LogConsole.GetLineText(len(text.splitlines()) - 1)
   645             line = self.LogConsole.GetLineText(len(text.splitlines()) - 1)
   646             result = MATIEC_ERROR_MODEL.match(line)
   646             result = MATIEC_ERROR_MODEL.match(line)
   647             if result is not None:
   647             if result is not None:
   648                 first_line, first_column, last_line, last_column, error = result.groups()
   648                 first_line, first_column, last_line, last_column, error = result.groups()
   649                 infos = self.PluginRoot.ShowError(self.Log,
   649                 infos = self.CTR.ShowError(self.Log,
   650                                                   (int(first_line), int(first_column)), 
   650                                                   (int(first_line), int(first_column)), 
   651                                                   (int(last_line), int(last_column)))
   651                                                   (int(last_line), int(last_column)))
   652 	
   652 	
   653     ## Function displaying an Error dialog in PLCOpenEditor.
   653     ## Function displaying an Error dialog in PLCOpenEditor.
   654     #  @return False if closing cancelled.
   654     #  @return False if closing cancelled.
   655     def CheckSaveBeforeClosing(self, title=_("Close Project")):
   655     def CheckSaveBeforeClosing(self, title=_("Close Project")):
   656         if self.PluginRoot.ProjectTestModified():
   656         if self.CTR.ProjectTestModified():
   657             dialog = wx.MessageDialog(self,
   657             dialog = wx.MessageDialog(self,
   658                                       _("There are changes, do you want to save?"),
   658                                       _("There are changes, do you want to save?"),
   659                                       title,
   659                                       title,
   660                                       wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
   660                                       wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
   661             answer = dialog.ShowModal()
   661             answer = dialog.ShowModal()
   662             dialog.Destroy()
   662             dialog.Destroy()
   663             if answer == wx.ID_YES:
   663             if answer == wx.ID_YES:
   664                 self.PluginRoot.SaveProject()
   664                 self.CTR.SaveProject()
   665             elif answer == wx.ID_CANCEL:
   665             elif answer == wx.ID_CANCEL:
   666                 return False
   666                 return False
   667         return True
   667         return True
   668     
   668     
   669     def GetTabInfos(self, tab):
   669     def GetTabInfos(self, tab):
   672                                  TextViewer, 
   672                                  TextViewer, 
   673                                  GraphicViewer, 
   673                                  GraphicViewer, 
   674                                  ResourceEditor, 
   674                                  ResourceEditor, 
   675                                  ConfigurationEditor, 
   675                                  ConfigurationEditor, 
   676                                  DataTypeEditor))):
   676                                  DataTypeEditor))):
   677             return ("plugin", tab.Controler.PlugFullName())
   677             return ("confnode", tab.Controler.PlugFullName())
   678         elif (isinstance(tab, TextViewer) and 
   678         elif (isinstance(tab, TextViewer) and 
   679               (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))):
   679               (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))):
   680             return ("plugin", None, tab.GetInstancePath())
   680             return ("confnode", None, tab.GetInstancePath())
   681         else:
   681         else:
   682             return IDEFrame.GetTabInfos(self, tab)
   682             return IDEFrame.GetTabInfos(self, tab)
   683     
   683     
   684     def LoadTab(self, notebook, page_infos):
   684     def LoadTab(self, notebook, page_infos):
   685         if page_infos[0] == "plugin":
   685         if page_infos[0] == "confnode":
   686             if page_infos[1] is None:
   686             if page_infos[1] is None:
   687                 plugin = self.PluginRoot
   687                 confnode = self.CTR
   688             else:
   688             else:
   689                 plugin = self.PluginRoot.GetChildByName(page_infos[1])
   689                 confnode = self.CTR.GetChildByName(page_infos[1])
   690             return notebook.GetPageIndex(plugin._OpenView(*page_infos[2:]))
   690             return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:]))
   691         else:
   691         else:
   692             return IDEFrame.LoadTab(self, notebook, page_infos)
   692             return IDEFrame.LoadTab(self, notebook, page_infos)
   693     
   693     
   694     def OnCloseFrame(self, event):
   694     def OnCloseFrame(self, event):
   695         if self.PluginRoot is None or self.CheckSaveBeforeClosing(_("Close Application")):
   695         if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")):
   696             if self.PluginRoot is not None:
   696             if self.CTR is not None:
   697                 self.PluginRoot.KillDebugThread()
   697                 self.CTR.KillDebugThread()
   698             self.KillLocalRuntime()
   698             self.KillLocalRuntime()
   699             
   699             
   700             self.SaveLastState()
   700             self.SaveLastState()
   701             
   701             
   702             if self.PluginRoot is not None:
   702             if self.CTR is not None:
   703                 project_path = os.path.realpath(self.PluginRoot.GetProjectPath())
   703                 project_path = os.path.realpath(self.CTR.GetProjectPath())
   704             else:
   704             else:
   705                 project_path = ""
   705                 project_path = ""
   706             self.Config.Write("currenteditedproject", project_path)    
   706             self.Config.Write("currenteditedproject", project_path)    
   707             self.Config.Flush()
   707             self.Config.Flush()
   708             
   708             
   730     
   730     
   731     def RefreshFileMenu(self):
   731     def RefreshFileMenu(self):
   732         self.RefreshRecentProjectsMenu()
   732         self.RefreshRecentProjectsMenu()
   733         
   733         
   734         MenuToolBar = self.Panes["MenuToolBar"]
   734         MenuToolBar = self.Panes["MenuToolBar"]
   735         if self.PluginRoot is not None:
   735         if self.CTR is not None:
   736             selected = self.TabsOpened.GetSelection()
   736             selected = self.TabsOpened.GetSelection()
   737             if selected >= 0:
   737             if selected >= 0:
   738                 graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
   738                 graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
   739             else:
   739             else:
   740                 graphic_viewer = False
   740                 graphic_viewer = False
   752                 self.FileMenu.Enable(wx.ID_CLOSE, False)
   752                 self.FileMenu.Enable(wx.ID_CLOSE, False)
   753                 self.FileMenu.Enable(wx.ID_PREVIEW, False)
   753                 self.FileMenu.Enable(wx.ID_PREVIEW, False)
   754                 self.FileMenu.Enable(wx.ID_PRINT, False)
   754                 self.FileMenu.Enable(wx.ID_PRINT, False)
   755                 MenuToolBar.EnableTool(wx.ID_PRINT, False)
   755                 MenuToolBar.EnableTool(wx.ID_PRINT, False)
   756             self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
   756             self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
   757             project_modified = self.PluginRoot.ProjectTestModified()
   757             project_modified = self.CTR.ProjectTestModified()
   758             self.FileMenu.Enable(wx.ID_SAVE, project_modified)
   758             self.FileMenu.Enable(wx.ID_SAVE, project_modified)
   759             MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
   759             MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
   760             self.FileMenu.Enable(wx.ID_SAVEAS, True)
   760             self.FileMenu.Enable(wx.ID_SAVEAS, True)
   761             MenuToolBar.EnableTool(wx.ID_SAVEAS, True)
   761             MenuToolBar.EnableTool(wx.ID_SAVEAS, True)
   762             self.FileMenu.Enable(wx.ID_PROPERTIES, True)
   762             self.FileMenu.Enable(wx.ID_PROPERTIES, True)
   787                        kind=wx.ITEM_NORMAL, text="%d: %s" % (idx + 1, projectpath))
   787                        kind=wx.ITEM_NORMAL, text="%d: %s" % (idx + 1, projectpath))
   788             self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id)
   788             self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id)
   789     
   789     
   790     def GenerateOpenRecentProjectFunction(self, projectpath):
   790     def GenerateOpenRecentProjectFunction(self, projectpath):
   791         def OpenRecentProject(event):
   791         def OpenRecentProject(event):
   792             if self.PluginRoot is not None and not self.CheckSaveBeforeClosing():
   792             if self.CTR is not None and not self.CheckSaveBeforeClosing():
   793                 return
   793                 return
   794             
   794             
   795             self.OpenProject(projectpath)
   795             self.OpenProject(projectpath)
   796         return OpenRecentProject
   796         return OpenRecentProject
   797     
   797     
   808                 text, id, help, callback = infos
   808                 text, id, help, callback = infos
   809                 AppendMenu(menu, help='', id=id, kind=kind, text=text)
   809                 AppendMenu(menu, help='', id=id, kind=kind, text=text)
   810                 if callback is not None:
   810                 if callback is not None:
   811                     self.Bind(wx.EVT_MENU, callback, id=id)
   811                     self.Bind(wx.EVT_MENU, callback, id=id)
   812     
   812     
   813     def RefreshPluginMenu(self):
   813     def RefreshConfNodeMenu(self):
   814         if self.PluginRoot is not None:
   814         if self.CTR is not None:
   815             selected = self.TabsOpened.GetSelection()
   815             selected = self.TabsOpened.GetSelection()
   816             if selected >= 0:
   816             if selected >= 0:
   817                 panel = self.TabsOpened.GetPage(selected)
   817                 panel = self.TabsOpened.GetPage(selected)
   818             else:
   818             else:
   819                 panel = None
   819                 panel = None
   820             if panel != self.LastPanelSelected:
   820             if panel != self.LastPanelSelected:
   821                 for i in xrange(self.PluginMenu.GetMenuItemCount()):
   821                 for i in xrange(self.ConfNodeMenu.GetMenuItemCount()):
   822                     item = self.PluginMenu.FindItemByPosition(0)
   822                     item = self.ConfNodeMenu.FindItemByPosition(0)
   823                     self.PluginMenu.Delete(item.GetId())
   823                     self.ConfNodeMenu.Delete(item.GetId())
   824                 self.LastPanelSelected = panel
   824                 self.LastPanelSelected = panel
   825                 if panel is not None:
   825                 if panel is not None:
   826                     items = panel.GetPluginMenuItems()
   826                     items = panel.GetConfNodeMenuItems()
   827                 else:
   827                 else:
   828                     items = []
   828                     items = []
   829                 self.MenuBar.EnableTop(PLUGINMENU_POSITION, len(items) > 0)
   829                 self.MenuBar.EnableTop(CONFNODEMENU_POSITION, len(items) > 0)
   830                 self.GenerateMenuRecursive(items, self.PluginMenu)
   830                 self.GenerateMenuRecursive(items, self.ConfNodeMenu)
   831             if panel is not None:
   831             if panel is not None:
   832                 panel.RefreshPluginMenu(self.PluginMenu)
   832                 panel.RefreshConfNodeMenu(self.ConfNodeMenu)
   833         else:
   833         else:
   834             self.MenuBar.EnableTop(PLUGINMENU_POSITION, False)
   834             self.MenuBar.EnableTop(CONFNODEMENU_POSITION, False)
   835         self.MenuBar.UpdateMenus()
   835         self.MenuBar.UpdateMenus()
   836     
   836     
   837     def RefreshScrollBars(self):
   837     def RefreshScrollBars(self):
   838         xstart, ystart = self.PLCConfig.GetViewStart()
   838         xstart, ystart = self.PLCConfig.GetViewStart()
   839         window_size = self.PLCConfig.GetClientSize()
   839         window_size = self.PLCConfig.GetClientSize()
   848 
   848 
   849     def RefreshPLCParams(self):
   849     def RefreshPLCParams(self):
   850         self.Freeze()
   850         self.Freeze()
   851         self.ClearSizer(self.PLCParamsSizer)
   851         self.ClearSizer(self.PLCParamsSizer)
   852         
   852         
   853         if self.PluginRoot is not None:    
   853         if self.CTR is not None:    
   854             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   854             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   855             if self.PluginRoot.PlugTestModified():
   855             if self.CTR.PlugTestModified():
   856                 bkgdclr = CHANGED_TITLE_COLOUR
   856                 bkgdclr = CHANGED_TITLE_COLOUR
   857             else:
   857             else:
   858                 bkgdclr = TITLE_COLOUR
   858                 bkgdclr = TITLE_COLOUR
   859                 
   859                 
   860             if self.PluginRoot not in self.PluginInfos:
   860             if self.CTR not in self.ConfNodeInfos:
   861                 self.PluginInfos[self.PluginRoot] = {"right_visible" : False}
   861                 self.ConfNodeInfos[self.CTR] = {"right_visible" : False}
   862             
   862             
   863             plcwindow.SetBackgroundColour(TITLE_COLOUR)
   863             plcwindow.SetBackgroundColour(TITLE_COLOUR)
   864             plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
   864             plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
   865             self.PLCParamsSizer.AddWindow(plcwindow, 0, border=0, flag=wx.GROW)
   865             self.PLCParamsSizer.AddWindow(plcwindow, 0, border=0, flag=wx.GROW)
   866             
   866             
   867             plcwindowsizer = wx.BoxSizer(wx.HORIZONTAL)
   867             plcwindowsizer = wx.BoxSizer(wx.HORIZONTAL)
   868             plcwindow.SetSizer(plcwindowsizer)
   868             plcwindow.SetSizer(plcwindowsizer)
   869             
   869             
   870             st = wx.StaticText(plcwindow, -1)
   870             st = wx.StaticText(plcwindow, -1)
   871             st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
   871             st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
   872             st.SetLabel(self.PluginRoot.GetProjectName())
   872             st.SetLabel(self.CTR.GetProjectName())
   873             plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER)
   873             plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER)
   874             
   874             
   875             addbutton_id = wx.NewId()
   875             addbutton_id = wx.NewId()
   876             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
   876             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
   877                   name='AddPluginButton', parent=plcwindow, pos=wx.Point(0, 0),
   877                   name='AddConfNodeButton', parent=plcwindow, pos=wx.Point(0, 0),
   878                   size=wx.Size(16, 16), style=wx.NO_BORDER)
   878                   size=wx.Size(16, 16), style=wx.NO_BORDER)
   879             addbutton.SetToolTipString(_("Add a sub plugin"))
   879             addbutton.SetToolTipString(_("Add a sub confnode"))
   880             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddPluginMenu(self.PluginRoot), id=addbutton_id)
   880             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(self.CTR), id=addbutton_id)
   881             plcwindowsizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
   881             plcwindowsizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
   882     
   882     
   883             plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
   883             plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
   884             plcwindowsizer.AddSizer(plcwindowmainsizer, 0, border=5, flag=wx.ALL)
   884             plcwindowsizer.AddSizer(plcwindowmainsizer, 0, border=5, flag=wx.ALL)
   885             
   885             
   886             plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL)
   886             plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL)
   887             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
   887             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
   888             
   888             
   889             msizer = self.GenerateMethodButtonSizer(self.PluginRoot, plcwindow, not self.PluginInfos[self.PluginRoot]["right_visible"])
   889             msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"])
   890             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
   890             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
   891             
   891             
   892             paramswindow = wx.Panel(plcwindow, -1, size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
   892             paramswindow = wx.Panel(plcwindow, -1, size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
   893             paramswindow.SetBackgroundColour(TITLE_COLOUR)
   893             paramswindow.SetBackgroundColour(TITLE_COLOUR)
   894             paramswindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
   894             paramswindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
   895             plcwindowbuttonsizer.AddWindow(paramswindow, 0, border=0, flag=0)
   895             plcwindowbuttonsizer.AddWindow(paramswindow, 0, border=0, flag=0)
   896             
   896             
   897             psizer = wx.BoxSizer(wx.HORIZONTAL)
   897             psizer = wx.BoxSizer(wx.HORIZONTAL)
   898             paramswindow.SetSizer(psizer)
   898             paramswindow.SetSizer(psizer)
   899             
   899             
   900             plugin_infos = self.PluginRoot.GetParamsAttributes()
   900             confnode_infos = self.CTR.GetParamsAttributes()
   901             self.RefreshSizerElement(paramswindow, psizer, self.PluginRoot, plugin_infos, None, False)
   901             self.RefreshSizerElement(paramswindow, psizer, self.CTR, confnode_infos, None, False)
   902             
   902             
   903             if not self.PluginInfos[self.PluginRoot]["right_visible"]:
   903             if not self.ConfNodeInfos[self.CTR]["right_visible"]:
   904                 paramswindow.Hide()
   904                 paramswindow.Hide()
   905             
   905             
   906             minimizebutton_id = wx.NewId()
   906             minimizebutton_id = wx.NewId()
   907             minimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=minimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
   907             minimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=minimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
   908                   name='MinimizeButton', parent=plcwindow, pos=wx.Point(0, 0),
   908                   name='MinimizeButton', parent=plcwindow, pos=wx.Point(0, 0),
   909                   size=wx.Size(24, 24), style=wx.NO_BORDER)
   909                   size=wx.Size(24, 24), style=wx.NO_BORDER)
   910             make_genbitmaptogglebutton_flat(minimizebutton)
   910             make_genbitmaptogglebutton_flat(minimizebutton)
   911             minimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
   911             minimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
   912             minimizebutton.SetToggle(self.PluginInfos[self.PluginRoot]["right_visible"])
   912             minimizebutton.SetToggle(self.ConfNodeInfos[self.CTR]["right_visible"])
   913             plcwindowbuttonsizer.AddWindow(minimizebutton, 0, border=5, flag=wx.ALL)
   913             plcwindowbuttonsizer.AddWindow(minimizebutton, 0, border=5, flag=wx.ALL)
   914             
   914             
   915             def togglewindow(event):
   915             def togglewindow(event):
   916                 if minimizebutton.GetToggle():
   916                 if minimizebutton.GetToggle():
   917                     paramswindow.Show()
   917                     paramswindow.Show()
   918                     msizer.SetCols(1)
   918                     msizer.SetCols(1)
   919                 else:
   919                 else:
   920                     paramswindow.Hide()
   920                     paramswindow.Hide()
   921                     msizer.SetCols(len(self.PluginRoot.PluginMethods))
   921                     msizer.SetCols(len(self.CTR.ConfNodeMethods))
   922                 self.PluginInfos[self.PluginRoot]["right_visible"] = minimizebutton.GetToggle()
   922                 self.ConfNodeInfos[self.CTR]["right_visible"] = minimizebutton.GetToggle()
   923                 self.PLCConfigMainSizer.Layout()
   923                 self.PLCConfigMainSizer.Layout()
   924                 self.RefreshScrollBars()
   924                 self.RefreshScrollBars()
   925                 event.Skip()
   925                 event.Skip()
   926             minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id)
   926             minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id)
   927         
   927         
   928             self.PluginInfos[self.PluginRoot]["main"] = plcwindow
   928             self.ConfNodeInfos[self.CTR]["main"] = plcwindow
   929             self.PluginInfos[self.PluginRoot]["params"] = paramswindow
   929             self.ConfNodeInfos[self.CTR]["params"] = paramswindow
   930             
   930             
   931         self.PLCConfigMainSizer.Layout()
   931         self.PLCConfigMainSizer.Layout()
   932         self.RefreshScrollBars()
   932         self.RefreshScrollBars()
   933         self.Thaw()
   933         self.Thaw()
   934 
   934 
   935     def GenerateEnableButton(self, parent, sizer, plugin):
   935     def GenerateEnableButton(self, parent, sizer, confnode):
   936         enabled = plugin.PlugEnabled()
   936         enabled = confnode.PlugEnabled()
   937         if enabled is not None:
   937         if enabled is not None:
   938             enablebutton_id = wx.NewId()
   938             enablebutton_id = wx.NewId()
   939             enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')),
   939             enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')),
   940                   name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
   940                   name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
   941             enablebutton.SetToolTipString(_("Enable/Disable this plugin"))
   941             enablebutton.SetToolTipString(_("Enable/Disable this confnode"))
   942             make_genbitmaptogglebutton_flat(enablebutton)
   942             make_genbitmaptogglebutton_flat(enablebutton)
   943             enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png')))
   943             enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png')))
   944             enablebutton.SetToggle(enabled)
   944             enablebutton.SetToggle(enabled)
   945             def toggleenablebutton(event):
   945             def toggleenablebutton(event):
   946                 res = self.SetPluginParamsAttribute(plugin, "BaseParams.Enabled", enablebutton.GetToggle())
   946                 res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.Enabled", enablebutton.GetToggle())
   947                 enablebutton.SetToggle(res)
   947                 enablebutton.SetToggle(res)
   948                 event.Skip()
   948                 event.Skip()
   949             enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
   949             enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
   950             sizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   950             sizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   951         else:
   951         else:
   952             sizer.AddSpacer(wx.Size(16, 16))
   952             sizer.AddSpacer(wx.Size(16, 16))
   953     
   953     
   954     def GenerateMethodButtonSizer(self, plugin, parent, horizontal = True):
   954     def GenerateMethodButtonSizer(self, confnode, parent, horizontal = True):
   955         normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
   955         normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
   956         mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
   956         mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
   957         if horizontal:
   957         if horizontal:
   958             msizer = wx.FlexGridSizer(cols=len(plugin.PluginMethods))
   958             msizer = wx.FlexGridSizer(cols=len(confnode.ConfNodeMethods))
   959         else:
   959         else:
   960             msizer = wx.FlexGridSizer(cols=1)
   960             msizer = wx.FlexGridSizer(cols=1)
   961         for plugin_method in plugin.PluginMethods:
   961         for confnode_method in confnode.ConfNodeMethods:
   962             if "method" in plugin_method and plugin_method.get("shown",True):
   962             if "method" in confnode_method and confnode_method.get("shown",True):
   963                 id = wx.NewId()
   963                 id = wx.NewId()
   964                 label = plugin_method["name"]
   964                 label = confnode_method["name"]
   965                 button = GenBitmapTextButton(id=id, parent=parent,
   965                 button = GenBitmapTextButton(id=id, parent=parent,
   966                     bitmap=wx.Bitmap(Bpath( "%s.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=label, 
   966                     bitmap=wx.Bitmap(Bpath( "%s.png"%confnode_method.get("bitmap", os.path.join("images", "Unknown")))), label=label, 
   967                     name=label, pos=wx.DefaultPosition, style=wx.NO_BORDER)
   967                     name=label, pos=wx.DefaultPosition, style=wx.NO_BORDER)
   968                 button.SetFont(normal_bt_font)
   968                 button.SetFont(normal_bt_font)
   969                 button.SetToolTipString(plugin_method["tooltip"])
   969                 button.SetToolTipString(confnode_method["tooltip"])
   970                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(plugin, plugin_method["method"]), id=id)
   970                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode, confnode_method["method"]), id=id)
   971                 # a fancy underline on mouseover
   971                 # a fancy underline on mouseover
   972                 def setFontStyle(b, s):
   972                 def setFontStyle(b, s):
   973                     def fn(event):
   973                     def fn(event):
   974                         b.SetFont(s)
   974                         b.SetFont(s)
   975                         b.Refresh()
   975                         b.Refresh()
   976                         event.Skip()
   976                         event.Skip()
   977                     return fn
   977                     return fn
   978                 button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font))
   978                 button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font))
   979                 button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font))
   979                 button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font))
   980                 #hack to force size to mini
   980                 #hack to force size to mini
   981                 if not plugin_method.get("enabled",True):
   981                 if not confnode_method.get("enabled",True):
   982                     button.Disable()
   982                     button.Disable()
   983                 msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER)
   983                 msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER)
   984         return msizer
   984         return msizer
   985 
   985 
   986     def GenerateParamsPanel(self, plugin, bkgdclr, top_offset=0):
   986     def GenerateParamsPanel(self, confnode, bkgdclr, top_offset=0):
   987         rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   987         rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   988         rightwindow.SetBackgroundColour(bkgdclr)
   988         rightwindow.SetBackgroundColour(bkgdclr)
   989         
   989         
   990         rightwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
   990         rightwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
   991         rightwindow.SetSizer(rightwindowmainsizer)
   991         rightwindow.SetSizer(rightwindowmainsizer)
   993         rightwindowsizer = wx.FlexGridSizer(cols=2, rows=1)
   993         rightwindowsizer = wx.FlexGridSizer(cols=2, rows=1)
   994         rightwindowsizer.AddGrowableCol(1)
   994         rightwindowsizer.AddGrowableCol(1)
   995         rightwindowsizer.AddGrowableRow(0)
   995         rightwindowsizer.AddGrowableRow(0)
   996         rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=0, flag=wx.GROW)
   996         rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=0, flag=wx.GROW)
   997         
   997         
   998         msizer = self.GenerateMethodButtonSizer(plugin, rightwindow, not self.PluginInfos[plugin]["right_visible"])
   998         msizer = self.GenerateMethodButtonSizer(confnode, rightwindow, not self.ConfNodeInfos[confnode]["right_visible"])
   999         rightwindowsizer.AddSizer(msizer, 0, border=top_offset, flag=wx.TOP|wx.GROW)
   999         rightwindowsizer.AddSizer(msizer, 0, border=top_offset, flag=wx.TOP|wx.GROW)
  1000         
  1000         
  1001         rightparamssizer = wx.BoxSizer(wx.HORIZONTAL)
  1001         rightparamssizer = wx.BoxSizer(wx.HORIZONTAL)
  1002         rightwindowsizer.AddSizer(rightparamssizer, 0, border=0, flag=wx.ALIGN_RIGHT)
  1002         rightwindowsizer.AddSizer(rightparamssizer, 0, border=0, flag=wx.ALIGN_RIGHT)
  1003         
  1003         
  1004         paramswindow = wx.Panel(rightwindow, -1, size=wx.Size(-1, -1))
  1004         paramswindow = wx.Panel(rightwindow, -1, size=wx.Size(-1, -1))
  1005         paramswindow.SetBackgroundColour(bkgdclr)
  1005         paramswindow.SetBackgroundColour(bkgdclr)
  1006         
  1006         
  1007         psizer = wx.BoxSizer(wx.VERTICAL)
  1007         psizer = wx.BoxSizer(wx.VERTICAL)
  1008         paramswindow.SetSizer(psizer)
  1008         paramswindow.SetSizer(psizer)
  1009         self.PluginInfos[plugin]["params"] = paramswindow
  1009         self.ConfNodeInfos[confnode]["params"] = paramswindow
  1010         
  1010         
  1011         rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL)
  1011         rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL)
  1012         
  1012         
  1013         plugin_infos = plugin.GetParamsAttributes()
  1013         confnode_infos = confnode.GetParamsAttributes()
  1014         if len(plugin_infos) > 0:
  1014         if len(confnode_infos) > 0:
  1015             self.RefreshSizerElement(paramswindow, psizer, plugin, plugin_infos, None, False)
  1015             self.RefreshSizerElement(paramswindow, psizer, confnode, confnode_infos, None, False)
  1016             
  1016             
  1017             if not self.PluginInfos[plugin]["right_visible"]:
  1017             if not self.ConfNodeInfos[confnode]["right_visible"]:
  1018                 paramswindow.Hide()
  1018                 paramswindow.Hide()
  1019             
  1019             
  1020             rightminimizebutton_id = wx.NewId()
  1020             rightminimizebutton_id = wx.NewId()
  1021             rightminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=rightminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
  1021             rightminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=rightminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
  1022                   name='MinimizeButton', parent=rightwindow, pos=wx.Point(0, 0),
  1022                   name='MinimizeButton', parent=rightwindow, pos=wx.Point(0, 0),
  1023                   size=wx.Size(24, 24), style=wx.NO_BORDER)
  1023                   size=wx.Size(24, 24), style=wx.NO_BORDER)
  1024             make_genbitmaptogglebutton_flat(rightminimizebutton)
  1024             make_genbitmaptogglebutton_flat(rightminimizebutton)
  1025             rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
  1025             rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
  1026             rightminimizebutton.SetToggle(self.PluginInfos[plugin]["right_visible"])
  1026             rightminimizebutton.SetToggle(self.ConfNodeInfos[confnode]["right_visible"])
  1027             rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL)
  1027             rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL)
  1028                         
  1028                         
  1029             def togglerightwindow(event):
  1029             def togglerightwindow(event):
  1030                 if rightminimizebutton.GetToggle():
  1030                 if rightminimizebutton.GetToggle():
  1031                     rightparamssizer.Show(0)
  1031                     rightparamssizer.Show(0)
  1032                     msizer.SetCols(1)
  1032                     msizer.SetCols(1)
  1033                 else:
  1033                 else:
  1034                     rightparamssizer.Hide(0)
  1034                     rightparamssizer.Hide(0)
  1035                     msizer.SetCols(len(plugin.PluginMethods))
  1035                     msizer.SetCols(len(confnode.ConfNodeMethods))
  1036                 self.PluginInfos[plugin]["right_visible"] = rightminimizebutton.GetToggle()
  1036                 self.ConfNodeInfos[confnode]["right_visible"] = rightminimizebutton.GetToggle()
  1037                 self.PLCConfigMainSizer.Layout()
  1037                 self.PLCConfigMainSizer.Layout()
  1038                 self.RefreshScrollBars()
  1038                 self.RefreshScrollBars()
  1039                 event.Skip()
  1039                 event.Skip()
  1040             rightminimizebutton.Bind(wx.EVT_BUTTON, togglerightwindow, id=rightminimizebutton_id)
  1040             rightminimizebutton.Bind(wx.EVT_BUTTON, togglerightwindow, id=rightminimizebutton_id)
  1041         
  1041         
  1042         return rightwindow
  1042         return rightwindow
  1043     
  1043     
  1044 
  1044 
  1045     def RefreshPluginTree(self):
  1045     def RefreshConfNodeTree(self):
  1046         self.Freeze()
  1046         self.Freeze()
  1047         self.ClearSizer(self.PluginTreeSizer)
  1047         self.ClearSizer(self.ConfNodeTreeSizer)
  1048         if self.PluginRoot is not None:
  1048         if self.CTR is not None:
  1049             for child in self.PluginRoot.IECSortedChilds():
  1049             for child in self.CTR.IECSortedChilds():
  1050                 self.GenerateTreeBranch(child)
  1050                 self.GenerateTreeBranch(child)
  1051                 if not self.PluginInfos[child]["expanded"]:
  1051                 if not self.ConfNodeInfos[child]["expanded"]:
  1052                     self.CollapsePlugin(child)
  1052                     self.CollapseConfNode(child)
  1053         self.PLCConfigMainSizer.Layout()
  1053         self.PLCConfigMainSizer.Layout()
  1054         self.RefreshScrollBars()
  1054         self.RefreshScrollBars()
  1055         self.Thaw()
  1055         self.Thaw()
  1056 
  1056 
  1057     def SetPluginParamsAttribute(self, plugin, *args, **kwargs):
  1057     def SetConfNodeParamsAttribute(self, confnode, *args, **kwargs):
  1058         res, StructChanged = plugin.SetParamsAttribute(*args, **kwargs)
  1058         res, StructChanged = confnode.SetParamsAttribute(*args, **kwargs)
  1059         if StructChanged:
  1059         if StructChanged:
  1060             wx.CallAfter(self.RefreshPluginTree)
  1060             wx.CallAfter(self.RefreshConfNodeTree)
  1061         else:
  1061         else:
  1062             if plugin == self.PluginRoot:
  1062             if confnode == self.CTR:
  1063                 bkgdclr = CHANGED_TITLE_COLOUR
  1063                 bkgdclr = CHANGED_TITLE_COLOUR
  1064                 items = ["main", "params"]
  1064                 items = ["main", "params"]
  1065             else:
  1065             else:
  1066                 bkgdclr = CHANGED_WINDOW_COLOUR
  1066                 bkgdclr = CHANGED_WINDOW_COLOUR
  1067                 items = ["left", "right", "params"]
  1067                 items = ["left", "right", "params"]
  1068             for i in items:
  1068             for i in items:
  1069                 self.PluginInfos[plugin][i].SetBackgroundColour(bkgdclr)
  1069                 self.ConfNodeInfos[confnode][i].SetBackgroundColour(bkgdclr)
  1070                 self.PluginInfos[plugin][i].Refresh()
  1070                 self.ConfNodeInfos[confnode][i].Refresh()
  1071         self._Refresh(TITLE, FILEMENU)
  1071         self._Refresh(TITLE, FILEMENU)
  1072         return res
  1072         return res
  1073 
  1073 
  1074     def ExpandPlugin(self, plugin, force = False):
  1074     def ExpandConfNode(self, confnode, force = False):
  1075         for child in self.PluginInfos[plugin]["children"]:
  1075         for child in self.ConfNodeInfos[confnode]["children"]:
  1076             self.PluginInfos[child]["left"].Show()
  1076             self.ConfNodeInfos[child]["left"].Show()
  1077             self.PluginInfos[child]["right"].Show()
  1077             self.ConfNodeInfos[child]["right"].Show()
  1078             if force or self.PluginInfos[child]["expanded"]:
  1078             if force or self.ConfNodeInfos[child]["expanded"]:
  1079                 self.ExpandPlugin(child, force)
  1079                 self.ExpandConfNode(child, force)
  1080                 if force:
  1080                 if force:
  1081                     self.PluginInfos[child]["expanded"] = True
  1081                     self.ConfNodeInfos[child]["expanded"] = True
  1082         locations_infos = self.PluginInfos[plugin].get("locations_infos", None)
  1082         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
  1083         if locations_infos is not None:
  1083         if locations_infos is not None:
  1084             if force or locations_infos["root"]["expanded"]:
  1084             if force or locations_infos["root"]["expanded"]:
  1085                 self.ExpandLocation(locations_infos, "root", force)
  1085                 self.ExpandLocation(locations_infos, "root", force)
  1086                 if force:
  1086                 if force:
  1087                     locations_infos["root"]["expanded"] = True
  1087                     locations_infos["root"]["expanded"] = True
  1088     
  1088     
  1089     def CollapsePlugin(self, plugin, force = False):
  1089     def CollapseConfNode(self, confnode, force = False):
  1090         for child in self.PluginInfos[plugin]["children"]:
  1090         for child in self.ConfNodeInfos[confnode]["children"]:
  1091             self.PluginInfos[child]["left"].Hide()
  1091             self.ConfNodeInfos[child]["left"].Hide()
  1092             self.PluginInfos[child]["right"].Hide()
  1092             self.ConfNodeInfos[child]["right"].Hide()
  1093             self.CollapsePlugin(child, force)
  1093             self.CollapseConfNode(child, force)
  1094             if force:
  1094             if force:
  1095                 self.PluginInfos[child]["expanded"] = False
  1095                 self.ConfNodeInfos[child]["expanded"] = False
  1096         locations_infos = self.PluginInfos[plugin].get("locations_infos", None)
  1096         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
  1097         if locations_infos is not None:
  1097         if locations_infos is not None:
  1098             self.CollapseLocation(locations_infos, "root", force)
  1098             self.CollapseLocation(locations_infos, "root", force)
  1099             if force:
  1099             if force:
  1100                 locations_infos["root"]["expanded"] = False
  1100                 locations_infos["root"]["expanded"] = False
  1101 
  1101 
  1127                 for child in locations_infos[group]["children"]:
  1127                 for child in locations_infos[group]["children"]:
  1128                     self.CollapseLocation(locations_infos, child, force, False)
  1128                     self.CollapseLocation(locations_infos, child, force, False)
  1129         if locations_infos["root"]["left"] is not None and refresh_size:
  1129         if locations_infos["root"]["left"] is not None and refresh_size:
  1130             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
  1130             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
  1131     
  1131     
  1132     def GenerateTreeBranch(self, plugin):
  1132     def GenerateTreeBranch(self, confnode):
  1133         leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
  1133         leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
  1134         if plugin.PlugTestModified():
  1134         if confnode.PlugTestModified():
  1135             bkgdclr=CHANGED_WINDOW_COLOUR
  1135             bkgdclr=CHANGED_WINDOW_COLOUR
  1136         else:
  1136         else:
  1137             bkgdclr=WINDOW_COLOUR
  1137             bkgdclr=WINDOW_COLOUR
  1138 
  1138 
  1139         leftwindow.SetBackgroundColour(bkgdclr)
  1139         leftwindow.SetBackgroundColour(bkgdclr)
  1140         
  1140         
  1141         if not self.PluginInfos.has_key(plugin):
  1141         if not self.ConfNodeInfos.has_key(confnode):
  1142             self.PluginInfos[plugin] = {"expanded" : False, "right_visible" : False}
  1142             self.ConfNodeInfos[confnode] = {"expanded" : False, "right_visible" : False}
  1143             
  1143             
  1144         self.PluginInfos[plugin]["children"] = plugin.IECSortedChilds()
  1144         self.ConfNodeInfos[confnode]["children"] = confnode.IECSortedChilds()
  1145         plugin_locations = []
  1145         confnode_locations = []
  1146         if len(self.PluginInfos[plugin]["children"]) == 0:
  1146         if len(self.ConfNodeInfos[confnode]["children"]) == 0:
  1147             plugin_locations = plugin.GetVariableLocationTree()["children"]
  1147             confnode_locations = confnode.GetVariableLocationTree()["children"]
  1148             if not self.PluginInfos[plugin].has_key("locations_infos"):
  1148             if not self.ConfNodeInfos[confnode].has_key("locations_infos"):
  1149                 self.PluginInfos[plugin]["locations_infos"] = {"root": {"expanded" : False}}
  1149                 self.ConfNodeInfos[confnode]["locations_infos"] = {"root": {"expanded" : False}}
  1150             
  1150             
  1151             self.PluginInfos[plugin]["locations_infos"]["root"]["left"] = None
  1151             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["left"] = None
  1152             self.PluginInfos[plugin]["locations_infos"]["root"]["right"] = None
  1152             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["right"] = None
  1153             self.PluginInfos[plugin]["locations_infos"]["root"]["children"] = []
  1153             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["children"] = []
  1154         
  1154         
  1155         self.PluginTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW)
  1155         self.ConfNodeTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW)
  1156         
  1156         
  1157         leftwindowsizer = wx.FlexGridSizer(cols=1, rows=2)
  1157         leftwindowsizer = wx.FlexGridSizer(cols=1, rows=2)
  1158         leftwindowsizer.AddGrowableCol(0)
  1158         leftwindowsizer.AddGrowableCol(0)
  1159         leftwindow.SetSizer(leftwindowsizer)
  1159         leftwindow.SetSizer(leftwindowsizer)
  1160         
  1160         
  1169         leftbuttonsizer.AddSizer(leftsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1169         leftbuttonsizer.AddSizer(leftsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1170 
  1170 
  1171         rolesizer = wx.BoxSizer(wx.HORIZONTAL)
  1171         rolesizer = wx.BoxSizer(wx.HORIZONTAL)
  1172         leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
  1172         leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
  1173         
  1173         
  1174         #self.GenerateEnableButton(leftwindow, rolesizer, plugin)
  1174         #self.GenerateEnableButton(leftwindow, rolesizer, confnode)
  1175 
  1175 
  1176         roletext = wx.StaticText(leftwindow, -1)
  1176         roletext = wx.StaticText(leftwindow, -1)
  1177         roletext.SetLabel(plugin.PlugHelp)
  1177         roletext.SetLabel(confnode.PlugHelp)
  1178         rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT)
  1178         rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT)
  1179         
  1179         
  1180         plugin_IECChannel = plugin.BaseParams.getIEC_Channel()
  1180         confnode_IECChannel = confnode.BaseParams.getIEC_Channel()
  1181         
  1181         
  1182         iecsizer = wx.BoxSizer(wx.HORIZONTAL)
  1182         iecsizer = wx.BoxSizer(wx.HORIZONTAL)
  1183         leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1183         leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1184 
  1184 
  1185         st = wx.StaticText(leftwindow, -1)
  1185         st = wx.StaticText(leftwindow, -1)
  1186         st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1186         st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1187         st.SetLabel(plugin.GetFullIEC_Channel())
  1187         st.SetLabel(confnode.GetFullIEC_Channel())
  1188         iecsizer.AddWindow(st, 0, border=0, flag=0)
  1188         iecsizer.AddWindow(st, 0, border=0, flag=0)
  1189 
  1189 
  1190         updownsizer = wx.BoxSizer(wx.VERTICAL)
  1190         updownsizer = wx.BoxSizer(wx.VERTICAL)
  1191         iecsizer.AddSizer(updownsizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
  1191         iecsizer.AddSizer(updownsizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
  1192 
  1192 
  1193         if plugin_IECChannel > 0:
  1193         if confnode_IECChannel > 0:
  1194             ieccdownbutton_id = wx.NewId()
  1194             ieccdownbutton_id = wx.NewId()
  1195             ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCDown.png')),
  1195             ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCDown.png')),
  1196                   name='IECCDownButton', parent=leftwindow, pos=wx.Point(0, 0),
  1196                   name='IECCDownButton', parent=leftwindow, pos=wx.Point(0, 0),
  1197                   size=wx.Size(16, 16), style=wx.NO_BORDER)
  1197                   size=wx.Size(16, 16), style=wx.NO_BORDER)
  1198             ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel - 1), id=ieccdownbutton_id)
  1198             ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel - 1), id=ieccdownbutton_id)
  1199             updownsizer.AddWindow(ieccdownbutton, 0, border=0, flag=wx.ALIGN_LEFT)
  1199             updownsizer.AddWindow(ieccdownbutton, 0, border=0, flag=wx.ALIGN_LEFT)
  1200 
  1200 
  1201         ieccupbutton_id = wx.NewId()
  1201         ieccupbutton_id = wx.NewId()
  1202         ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCUp.png')),
  1202         ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCUp.png')),
  1203               name='IECCUpButton', parent=leftwindow, pos=wx.Point(0, 0),
  1203               name='IECCUpButton', parent=leftwindow, pos=wx.Point(0, 0),
  1204               size=wx.Size(16, 16), style=wx.NO_BORDER)
  1204               size=wx.Size(16, 16), style=wx.NO_BORDER)
  1205         ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel + 1), id=ieccupbutton_id)
  1205         ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel + 1), id=ieccupbutton_id)
  1206         updownsizer.AddWindow(ieccupbutton, 0, border=0, flag=wx.ALIGN_LEFT)
  1206         updownsizer.AddWindow(ieccupbutton, 0, border=0, flag=wx.ALIGN_LEFT)
  1207 
  1207 
  1208         adddeletesizer = wx.BoxSizer(wx.VERTICAL)
  1208         adddeletesizer = wx.BoxSizer(wx.VERTICAL)
  1209         iecsizer.AddSizer(adddeletesizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
  1209         iecsizer.AddSizer(adddeletesizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
  1210 
  1210 
  1211         deletebutton_id = wx.NewId()
  1211         deletebutton_id = wx.NewId()
  1212         deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Delete.png')),
  1212         deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Delete.png')),
  1213               name='DeletePluginButton', parent=leftwindow, pos=wx.Point(0, 0),
  1213               name='DeleteConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0),
  1214               size=wx.Size(16, 16), style=wx.NO_BORDER)
  1214               size=wx.Size(16, 16), style=wx.NO_BORDER)
  1215         deletebutton.SetToolTipString(_("Delete this plugin"))
  1215         deletebutton.SetToolTipString(_("Delete this confnode"))
  1216         deletebutton.Bind(wx.EVT_BUTTON, self.GetDeleteButtonFunction(plugin), id=deletebutton_id)
  1216         deletebutton.Bind(wx.EVT_BUTTON, self.GetDeleteButtonFunction(confnode), id=deletebutton_id)
  1217         adddeletesizer.AddWindow(deletebutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
  1217         adddeletesizer.AddWindow(deletebutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
  1218 
  1218 
  1219         if len(plugin.PlugChildsTypes) > 0:
  1219         if len(confnode.PlugChildsTypes) > 0:
  1220             addbutton_id = wx.NewId()
  1220             addbutton_id = wx.NewId()
  1221             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
  1221             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
  1222                   name='AddPluginButton', parent=leftwindow, pos=wx.Point(0, 0),
  1222                   name='AddConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0),
  1223                   size=wx.Size(16, 16), style=wx.NO_BORDER)
  1223                   size=wx.Size(16, 16), style=wx.NO_BORDER)
  1224             addbutton.SetToolTipString(_("Add a sub plugin"))
  1224             addbutton.SetToolTipString(_("Add a sub confnode"))
  1225             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddPluginMenu(plugin), id=addbutton_id)
  1225             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(confnode), id=addbutton_id)
  1226             adddeletesizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
  1226             adddeletesizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
  1227         
  1227         
  1228         expandbutton_id = wx.NewId()
  1228         expandbutton_id = wx.NewId()
  1229         expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'plus.png')),
  1229         expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'plus.png')),
  1230               name='ExpandButton', parent=leftwindow, pos=wx.Point(0, 0),
  1230               name='ExpandButton', parent=leftwindow, pos=wx.Point(0, 0),
  1232         expandbutton.labelDelta = 0
  1232         expandbutton.labelDelta = 0
  1233         expandbutton.SetBezelWidth(0)
  1233         expandbutton.SetBezelWidth(0)
  1234         expandbutton.SetUseFocusIndicator(False)
  1234         expandbutton.SetUseFocusIndicator(False)
  1235         expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png')))
  1235         expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png')))
  1236             
  1236             
  1237         if len(self.PluginInfos[plugin]["children"]) > 0:
  1237         if len(self.ConfNodeInfos[confnode]["children"]) > 0:
  1238             expandbutton.SetToggle(self.PluginInfos[plugin]["expanded"])
  1238             expandbutton.SetToggle(self.ConfNodeInfos[confnode]["expanded"])
  1239             def togglebutton(event):
  1239             def togglebutton(event):
  1240                 if expandbutton.GetToggle():
  1240                 if expandbutton.GetToggle():
  1241                     self.ExpandPlugin(plugin)
  1241                     self.ExpandConfNode(confnode)
  1242                 else:
  1242                 else:
  1243                     self.CollapsePlugin(plugin)
  1243                     self.CollapseConfNode(confnode)
  1244                 self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle()
  1244                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
  1245                 self.PLCConfigMainSizer.Layout()
  1245                 self.PLCConfigMainSizer.Layout()
  1246                 self.RefreshScrollBars()
  1246                 self.RefreshScrollBars()
  1247                 event.Skip()
  1247                 event.Skip()
  1248             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
  1248             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
  1249         elif len(plugin_locations) > 0:
  1249         elif len(confnode_locations) > 0:
  1250             locations_infos = self.PluginInfos[plugin]["locations_infos"]
  1250             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
  1251             expandbutton.SetToggle(locations_infos["root"]["expanded"])
  1251             expandbutton.SetToggle(locations_infos["root"]["expanded"])
  1252             def togglebutton(event):
  1252             def togglebutton(event):
  1253                 if expandbutton.GetToggle():
  1253                 if expandbutton.GetToggle():
  1254                     self.ExpandLocation(locations_infos, "root")
  1254                     self.ExpandLocation(locations_infos, "root")
  1255                 else:
  1255                 else:
  1256                     self.CollapseLocation(locations_infos, "root")
  1256                     self.CollapseLocation(locations_infos, "root")
  1257                 self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle()
  1257                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
  1258                 locations_infos["root"]["expanded"] = expandbutton.GetToggle()
  1258                 locations_infos["root"]["expanded"] = expandbutton.GetToggle()
  1259                 self.PLCConfigMainSizer.Layout()
  1259                 self.PLCConfigMainSizer.Layout()
  1260                 self.RefreshScrollBars()
  1260                 self.RefreshScrollBars()
  1261                 event.Skip()
  1261                 event.Skip()
  1262             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
  1262             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
  1265         iecsizer.AddWindow(expandbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1265         iecsizer.AddWindow(expandbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1266         
  1266         
  1267         tc_id = wx.NewId()
  1267         tc_id = wx.NewId()
  1268         tc = wx.TextCtrl(leftwindow, tc_id, size=wx.Size(150, 25), style=wx.NO_BORDER)
  1268         tc = wx.TextCtrl(leftwindow, tc_id, size=wx.Size(150, 25), style=wx.NO_BORDER)
  1269         tc.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1269         tc.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1270         tc.ChangeValue(plugin.MandatoryParams[1].getName())
  1270         tc.ChangeValue(confnode.MandatoryParams[1].getName())
  1271         tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, plugin, "BaseParams.Name"), id=tc_id)
  1271         tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, confnode, "BaseParams.Name"), id=tc_id)
  1272         iecsizer.AddWindow(tc, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1272         iecsizer.AddWindow(tc, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1273         
  1273         
  1274         rightwindow = self.GenerateParamsPanel(plugin, bkgdclr, 8)
  1274         rightwindow = self.GenerateParamsPanel(confnode, bkgdclr, 8)
  1275         self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1275         self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1276         
  1276         
  1277         self.PluginInfos[plugin]["left"] = leftwindow
  1277         self.ConfNodeInfos[confnode]["left"] = leftwindow
  1278         self.PluginInfos[plugin]["right"] = rightwindow
  1278         self.ConfNodeInfos[confnode]["right"] = rightwindow
  1279         for child in self.PluginInfos[plugin]["children"]:
  1279         for child in self.ConfNodeInfos[confnode]["children"]:
  1280             self.GenerateTreeBranch(child)
  1280             self.GenerateTreeBranch(child)
  1281             if not self.PluginInfos[child]["expanded"]:
  1281             if not self.ConfNodeInfos[child]["expanded"]:
  1282                 self.CollapsePlugin(child)
  1282                 self.CollapseConfNode(child)
  1283         
  1283         
  1284         if len(plugin_locations) > 0:
  1284         if len(confnode_locations) > 0:
  1285             locations_infos = self.PluginInfos[plugin]["locations_infos"]
  1285             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
  1286             treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, 
  1286             treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, 
  1287                                    style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT)
  1287                                    style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT)
  1288             treectrl.SetImageList(self.LocationImageList)
  1288             treectrl.SetImageList(self.LocationImageList)
  1289             treectrl.Bind(wx.EVT_TREE_BEGIN_DRAG, self.GenerateLocationBeginDragFunction(locations_infos))
  1289             treectrl.Bind(wx.EVT_TREE_BEGIN_DRAG, self.GenerateLocationBeginDragFunction(locations_infos))
  1290             treectrl.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.GenerateLocationExpandCollapseFunction(locations_infos, True))
  1290             treectrl.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.GenerateLocationExpandCollapseFunction(locations_infos, True))
  1291             treectrl.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.GenerateLocationExpandCollapseFunction(locations_infos, False))
  1291             treectrl.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.GenerateLocationExpandCollapseFunction(locations_infos, False))
  1292             treectrl.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelTreeCtrl)
  1292             treectrl.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelTreeCtrl)
  1293             
  1293             
  1294             treectrl.AddRoot("")
  1294             treectrl.AddRoot("")
  1295             self.PluginTreeSizer.AddWindow(treectrl, 0, border=0, flag=0)
  1295             self.ConfNodeTreeSizer.AddWindow(treectrl, 0, border=0, flag=0)
  1296             
  1296             
  1297             rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
  1297             rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
  1298             rightwindow.SetBackgroundColour(wx.WHITE)
  1298             rightwindow.SetBackgroundColour(wx.WHITE)
  1299             self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1299             self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1300             
  1300             
  1301             locations_infos["root"]["left"] = treectrl
  1301             locations_infos["root"]["left"] = treectrl
  1302             locations_infos["root"]["right"] = rightwindow
  1302             locations_infos["root"]["right"] = rightwindow
  1303             for location in plugin_locations:
  1303             for location in confnode_locations:
  1304                 locations_infos["root"]["children"].append("root.%s" % location["name"])
  1304                 locations_infos["root"]["children"].append("root.%s" % location["name"])
  1305                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
  1305                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
  1306             if locations_infos["root"]["expanded"]:
  1306             if locations_infos["root"]["expanded"]:
  1307                 self.PluginTreeSizer.Layout()
  1307                 self.ConfNodeTreeSizer.Layout()
  1308                 self.ExpandLocation(locations_infos, "root")
  1308                 self.ExpandLocation(locations_infos, "root")
  1309             else:
  1309             else:
  1310                 self.RefreshTreeCtrlSize(treectrl)
  1310                 self.RefreshTreeCtrlSize(treectrl)
  1311     
  1311     
  1312     def GenerateLocationTreeBranch(self, treectrl, root, locations_infos, parent, location):
  1312     def GenerateLocationTreeBranch(self, treectrl, root, locations_infos, parent, location):
  1397             event.Skip()
  1397             event.Skip()
  1398         return OnLocationExpandedFunction
  1398         return OnLocationExpandedFunction
  1399     
  1399     
  1400     def RefreshAll(self):
  1400     def RefreshAll(self):
  1401         self.RefreshPLCParams()
  1401         self.RefreshPLCParams()
  1402         self.RefreshPluginTree()
  1402         self.RefreshConfNodeTree()
  1403         
  1403         
  1404     def GetItemChannelChangedFunction(self, plugin, value):
  1404     def GetItemChannelChangedFunction(self, confnode, value):
  1405         def OnPluginTreeItemChannelChanged(event):
  1405         def OnConfNodeTreeItemChannelChanged(event):
  1406             res = self.SetPluginParamsAttribute(plugin, "BaseParams.IEC_Channel", value)
  1406             res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.IEC_Channel", value)
  1407             event.Skip()
  1407             event.Skip()
  1408         return OnPluginTreeItemChannelChanged
  1408         return OnConfNodeTreeItemChannelChanged
  1409     
  1409     
  1410     def _GetAddPluginFunction(self, name, plugin):
  1410     def _GetAddConfNodeFunction(self, name, confnode):
  1411         def OnPluginMenu(event):
  1411         def OnConfNodeMenu(event):
  1412             wx.CallAfter(self.AddPlugin, name, plugin)
  1412             wx.CallAfter(self.AddConfNode, name, confnode)
  1413         return OnPluginMenu
  1413         return OnConfNodeMenu
  1414     
  1414     
  1415     def Gen_AddPluginMenu(self, plugin):
  1415     def Gen_AddConfNodeMenu(self, confnode):
  1416         def AddPluginMenu(event):
  1416         def AddConfNodeMenu(event):
  1417             main_menu = wx.Menu(title='')
  1417             main_menu = wx.Menu(title='')
  1418             if len(plugin.PlugChildsTypes) > 0:
  1418             if len(confnode.PlugChildsTypes) > 0:
  1419                 for name, XSDClass, help in plugin.PlugChildsTypes:
  1419                 for name, XSDClass, help in confnode.PlugChildsTypes:
  1420                     new_id = wx.NewId()
  1420                     new_id = wx.NewId()
  1421                     main_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Append ")+help)
  1421                     main_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Append ")+help)
  1422                     self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name, plugin), id=new_id)
  1422                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
  1423             self.PopupMenuXY(main_menu)
  1423             self.PopupMenuXY(main_menu)
  1424             main_menu.Destroy()
  1424             main_menu.Destroy()
  1425         return AddPluginMenu
  1425         return AddConfNodeMenu
  1426     
  1426     
  1427     def GetButtonCallBackFunction(self, plugin, method):
  1427     def GetButtonCallBackFunction(self, confnode, method):
  1428         """ Generate the callbackfunc for a given plugin method"""
  1428         """ Generate the callbackfunc for a given confnode method"""
  1429         def OnButtonClick(event):
  1429         def OnButtonClick(event):
  1430             # Disable button to prevent re-entrant call 
  1430             # Disable button to prevent re-entrant call 
  1431             event.GetEventObject().Disable()
  1431             event.GetEventObject().Disable()
  1432             # Call
  1432             # Call
  1433             getattr(plugin,method)()
  1433             getattr(confnode,method)()
  1434             # Re-enable button 
  1434             # Re-enable button 
  1435             event.GetEventObject().Enable()
  1435             event.GetEventObject().Enable()
  1436             # Trigger refresh on Idle
  1436             # Trigger refresh on Idle
  1437             wx.CallAfter(self.RefreshAll)
  1437             wx.CallAfter(self.RefreshAll)
  1438             event.Skip()
  1438             event.Skip()
  1439         return OnButtonClick
  1439         return OnButtonClick
  1440     
  1440     
  1441     def GetChoiceCallBackFunction(self, choicectrl, plugin, path):
  1441     def GetChoiceCallBackFunction(self, choicectrl, confnode, path):
  1442         def OnChoiceChanged(event):
  1442         def OnChoiceChanged(event):
  1443             res = self.SetPluginParamsAttribute(plugin, path, choicectrl.GetStringSelection())
  1443             res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection())
  1444             choicectrl.SetStringSelection(res)
  1444             choicectrl.SetStringSelection(res)
  1445             event.Skip()
  1445             event.Skip()
  1446         return OnChoiceChanged
  1446         return OnChoiceChanged
  1447     
  1447     
  1448     def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, plugin, path):
  1448     def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, confnode, path):
  1449         def OnChoiceContentChanged(event):
  1449         def OnChoiceContentChanged(event):
  1450             res = self.SetPluginParamsAttribute(plugin, path, choicectrl.GetStringSelection())
  1450             res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection())
  1451             if wx.VERSION < (2, 8, 0):
  1451             if wx.VERSION < (2, 8, 0):
  1452                 self.ParamsPanel.Freeze()
  1452                 self.ParamsPanel.Freeze()
  1453                 choicectrl.SetStringSelection(res)
  1453                 choicectrl.SetStringSelection(res)
  1454                 infos = self.PluginRoot.GetParamsAttributes(path)
  1454                 infos = self.CTR.GetParamsAttributes(path)
  1455                 staticbox = staticboxsizer.GetStaticBox()
  1455                 staticbox = staticboxsizer.GetStaticBox()
  1456                 staticbox.SetLabel("%(name)s - %(value)s"%infos)
  1456                 staticbox.SetLabel("%(name)s - %(value)s"%infos)
  1457                 self.RefreshSizerElement(self.ParamsPanel, staticboxsizer, infos["children"], "%s.%s"%(path, infos["name"]), selected=selected)
  1457                 self.RefreshSizerElement(self.ParamsPanel, staticboxsizer, infos["children"], "%s.%s"%(path, infos["name"]), selected=selected)
  1458                 self.ParamsPanelMainSizer.Layout()
  1458                 self.ParamsPanelMainSizer.Layout()
  1459                 self.ParamsPanel.Thaw()
  1459                 self.ParamsPanel.Thaw()
  1461             else:
  1461             else:
  1462                 wx.CallAfter(self.RefreshAll)
  1462                 wx.CallAfter(self.RefreshAll)
  1463             event.Skip()
  1463             event.Skip()
  1464         return OnChoiceContentChanged
  1464         return OnChoiceContentChanged
  1465     
  1465     
  1466     def GetTextCtrlCallBackFunction(self, textctrl, plugin, path):
  1466     def GetTextCtrlCallBackFunction(self, textctrl, confnode, path):
  1467         def OnTextCtrlChanged(event):
  1467         def OnTextCtrlChanged(event):
  1468             res = self.SetPluginParamsAttribute(plugin, path, textctrl.GetValue())
  1468             res = self.SetConfNodeParamsAttribute(confnode, path, textctrl.GetValue())
  1469             if res != textctrl.GetValue():
  1469             if res != textctrl.GetValue():
  1470                 textctrl.ChangeValue(res)
  1470                 textctrl.ChangeValue(res)
  1471             event.Skip()
  1471             event.Skip()
  1472         return OnTextCtrlChanged
  1472         return OnTextCtrlChanged
  1473     
  1473     
  1474     def GetCheckBoxCallBackFunction(self, chkbx, plugin, path):
  1474     def GetCheckBoxCallBackFunction(self, chkbx, confnode, path):
  1475         def OnCheckBoxChanged(event):
  1475         def OnCheckBoxChanged(event):
  1476             res = self.SetPluginParamsAttribute(plugin, path, chkbx.IsChecked())
  1476             res = self.SetConfNodeParamsAttribute(confnode, path, chkbx.IsChecked())
  1477             chkbx.SetValue(res)
  1477             chkbx.SetValue(res)
  1478             event.Skip()
  1478             event.Skip()
  1479         return OnCheckBoxChanged
  1479         return OnCheckBoxChanged
  1480     
  1480     
  1481     def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, plugin, path):
  1481     def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, confnode, path):
  1482         infos = [value_infos]
  1482         infos = [value_infos]
  1483         def OnBrowseButton(event):
  1483         def OnBrowseButton(event):
  1484             dialog = BrowseValuesLibraryDialog(self, name, library, infos[0])
  1484             dialog = BrowseValuesLibraryDialog(self, name, library, infos[0])
  1485             if dialog.ShowModal() == wx.ID_OK:
  1485             if dialog.ShowModal() == wx.ID_OK:
  1486                 value, value_infos = self.SetPluginParamsAttribute(plugin, path, dialog.GetValueInfos())
  1486                 value, value_infos = self.SetConfNodeParamsAttribute(confnode, path, dialog.GetValueInfos())
  1487                 textctrl.ChangeValue(value)
  1487                 textctrl.ChangeValue(value)
  1488                 infos[0] = value_infos
  1488                 infos[0] = value_infos
  1489             dialog.Destroy()
  1489             dialog.Destroy()
  1490             event.Skip()
  1490             event.Skip()
  1491         return OnBrowseButton
  1491         return OnBrowseButton
  1500                     staticboxes.append(item_sizer.GetStaticBox())
  1500                     staticboxes.append(item_sizer.GetStaticBox())
  1501         sizer.Clear(True)
  1501         sizer.Clear(True)
  1502         for staticbox in staticboxes:
  1502         for staticbox in staticboxes:
  1503             staticbox.Destroy()
  1503             staticbox.Destroy()
  1504                 
  1504                 
  1505     def RefreshSizerElement(self, parent, sizer, plugin, elements, path, clean = True):
  1505     def RefreshSizerElement(self, parent, sizer, confnode, elements, path, clean = True):
  1506         if clean:
  1506         if clean:
  1507             if wx.VERSION < (2, 8, 0):
  1507             if wx.VERSION < (2, 8, 0):
  1508                 self.ClearSizer(sizer)
  1508                 self.ClearSizer(sizer)
  1509             else:
  1509             else:
  1510                 sizer.Clear(True)
  1510                 sizer.Clear(True)
  1522                 staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
  1522                 staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
  1523                 if first:
  1523                 if first:
  1524                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW|wx.TOP)
  1524                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW|wx.TOP)
  1525                 else:
  1525                 else:
  1526                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW)
  1526                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW)
  1527                 self.RefreshSizerElement(parent, staticboxsizer, plugin, element_infos["children"], element_path)
  1527                 self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path)
  1528             else:
  1528             else:
  1529                 boxsizer = wx.FlexGridSizer(cols=3, rows=1)
  1529                 boxsizer = wx.FlexGridSizer(cols=3, rows=1)
  1530                 boxsizer.AddGrowableCol(1)
  1530                 boxsizer.AddGrowableCol(1)
  1531                 if first:
  1531                 if first:
  1532                     sizer.AddSizer(boxsizer, 0, border=5, flag=wx.GROW|wx.ALL)
  1532                     sizer.AddSizer(boxsizer, 0, border=5, flag=wx.GROW|wx.ALL)
  1559                         button = wx.Button(id=button_id, name="browse_%s" % element_infos["name"], parent=parent, 
  1559                         button = wx.Button(id=button_id, name="browse_%s" % element_infos["name"], parent=parent, 
  1560                             label="...", pos=wx.Point(0, 0), size=wx.Size(25, 25))
  1560                             label="...", pos=wx.Point(0, 0), size=wx.Size(25, 25))
  1561                         browse_boxsizer.AddWindow(button, 0, border=0, flag=0)
  1561                         browse_boxsizer.AddWindow(button, 0, border=0, flag=0)
  1562                         button.Bind(wx.EVT_BUTTON, 
  1562                         button.Bind(wx.EVT_BUTTON, 
  1563                                     self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], 
  1563                                     self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], 
  1564                                                                    value_infos, plugin, element_path), 
  1564                                                                    value_infos, confnode, element_path), 
  1565                                     id=button_id)
  1565                                     id=button_id)
  1566                     else:
  1566                     else:
  1567                         combobox = wx.ComboBox(id=id, name=element_infos["name"], parent=parent, 
  1567                         combobox = wx.ComboBox(id=id, name=element_infos["name"], parent=parent, 
  1568                             pos=wx.Point(0, 0), size=wx.Size(300, 28), style=wx.CB_READONLY)
  1568                             pos=wx.Point(0, 0), size=wx.Size(300, 28), style=wx.CB_READONLY)
  1569                         boxsizer.AddWindow(combobox, 0, border=0, flag=0)
  1569                         boxsizer.AddWindow(combobox, 0, border=0, flag=0)
  1577                             staticbox = wx.StaticBox(id=-1, label="%s - %s"%(_(name), _(value)), 
  1577                             staticbox = wx.StaticBox(id=-1, label="%s - %s"%(_(name), _(value)), 
  1578                                 name='%s_staticbox'%element_infos["name"], parent=parent,
  1578                                 name='%s_staticbox'%element_infos["name"], parent=parent,
  1579                                 pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0)
  1579                                 pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0)
  1580                             staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
  1580                             staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
  1581                             sizer.AddSizer(staticboxsizer, 0, border=5, flag=wx.GROW|wx.BOTTOM)
  1581                             sizer.AddSizer(staticboxsizer, 0, border=5, flag=wx.GROW|wx.BOTTOM)
  1582                             self.RefreshSizerElement(parent, staticboxsizer, plugin, element_infos["children"], element_path)
  1582                             self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path)
  1583                             callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, plugin, element_path)
  1583                             callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, confnode, element_path)
  1584                         else:
  1584                         else:
  1585                             for choice in element_infos["type"]:
  1585                             for choice in element_infos["type"]:
  1586                                 combobox.Append(choice)
  1586                                 combobox.Append(choice)
  1587                             callback = self.GetChoiceCallBackFunction(combobox, plugin, element_path)
  1587                             callback = self.GetChoiceCallBackFunction(combobox, confnode, element_path)
  1588                         if element_infos["value"] is None:
  1588                         if element_infos["value"] is None:
  1589                             combobox.SetStringSelection("")
  1589                             combobox.SetStringSelection("")
  1590                         else:
  1590                         else:
  1591                             combobox.SetStringSelection(element_infos["value"])
  1591                             combobox.SetStringSelection(element_infos["value"])
  1592                         combobox.Bind(wx.EVT_COMBOBOX, callback, id=id)
  1592                         combobox.Bind(wx.EVT_COMBOBOX, callback, id=id)
  1601                         pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
  1601                         pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
  1602                     spinctrl.SetRange(scmin,scmax)
  1602                     spinctrl.SetRange(scmin,scmax)
  1603                     boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
  1603                     boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
  1604                     if element_infos["value"] is not None:
  1604                     if element_infos["value"] is not None:
  1605                         spinctrl.SetValue(element_infos["value"])
  1605                         spinctrl.SetValue(element_infos["value"])
  1606                     spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id)
  1606                     spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id)
  1607                 else:
  1607                 else:
  1608                     if element_infos["type"] == "boolean":
  1608                     if element_infos["type"] == "boolean":
  1609                         checkbox = wx.CheckBox(id=id, name=element_infos["name"], parent=parent, 
  1609                         checkbox = wx.CheckBox(id=id, name=element_infos["name"], parent=parent, 
  1610                             pos=wx.Point(0, 0), size=wx.Size(17, 25), style=0)
  1610                             pos=wx.Point(0, 0), size=wx.Size(17, 25), style=0)
  1611                         boxsizer.AddWindow(checkbox, 0, border=0, flag=0)
  1611                         boxsizer.AddWindow(checkbox, 0, border=0, flag=0)
  1612                         if element_infos["value"] is not None:
  1612                         if element_infos["value"] is not None:
  1613                             checkbox.SetValue(element_infos["value"])
  1613                             checkbox.SetValue(element_infos["value"])
  1614                         checkbox.Bind(wx.EVT_CHECKBOX, self.GetCheckBoxCallBackFunction(checkbox, plugin, element_path), id=id)
  1614                         checkbox.Bind(wx.EVT_CHECKBOX, self.GetCheckBoxCallBackFunction(checkbox, confnode, element_path), id=id)
  1615                     elif element_infos["type"] in ["unsignedLong", "long","integer"]:
  1615                     elif element_infos["type"] in ["unsignedLong", "long","integer"]:
  1616                         if element_infos["type"].startswith("unsigned"):
  1616                         if element_infos["type"].startswith("unsigned"):
  1617                             scmin = 0
  1617                             scmin = 0
  1618                         else:
  1618                         else:
  1619                             scmin = -(2**31)
  1619                             scmin = -(2**31)
  1622                             pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
  1622                             pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
  1623                         spinctrl.SetRange(scmin, scmax)
  1623                         spinctrl.SetRange(scmin, scmax)
  1624                         boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
  1624                         boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
  1625                         if element_infos["value"] is not None:
  1625                         if element_infos["value"] is not None:
  1626                             spinctrl.SetValue(element_infos["value"])
  1626                             spinctrl.SetValue(element_infos["value"])
  1627                         spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id)
  1627                         spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id)
  1628                     else:
  1628                     else:
  1629                         choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""]))))
  1629                         choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""]))))
  1630                         textctrl = TextCtrlAutoComplete.TextCtrlAutoComplete(id=id, 
  1630                         textctrl = TextCtrlAutoComplete.TextCtrlAutoComplete(id=id, 
  1631                                                                      name=element_infos["name"], 
  1631                                                                      name=element_infos["name"], 
  1632                                                                      parent=parent, 
  1632                                                                      parent=parent, 
  1638                                                                      style=0)
  1638                                                                      style=0)
  1639                         
  1639                         
  1640                         boxsizer.AddWindow(textctrl, 0, border=0, flag=0)
  1640                         boxsizer.AddWindow(textctrl, 0, border=0, flag=0)
  1641                         if element_infos["value"] is not None:
  1641                         if element_infos["value"] is not None:
  1642                             textctrl.ChangeValue(str(element_infos["value"]))
  1642                             textctrl.ChangeValue(str(element_infos["value"]))
  1643                         textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, plugin, element_path))
  1643                         textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, confnode, element_path))
  1644             first = False
  1644             first = False
  1645     
  1645     
  1646     def ResetView(self):
  1646     def ResetView(self):
  1647         IDEFrame.ResetView(self)
  1647         IDEFrame.ResetView(self)
  1648         self.PluginInfos = {}
  1648         self.ConfNodeInfos = {}
  1649         if self.PluginRoot is not None:
  1649         if self.CTR is not None:
  1650             self.PluginRoot.CloseProject()
  1650             self.CTR.CloseProject()
  1651         self.PluginRoot = None
  1651         self.CTR = None
  1652         self.Log.flush()
  1652         self.Log.flush()
  1653         if self.EnableDebug:
  1653         if self.EnableDebug:
  1654             self.DebugVariablePanel.SetDataProducer(None)
  1654             self.DebugVariablePanel.SetDataProducer(None)
  1655     
  1655     
  1656     def RefreshConfigRecentProjects(self, projectpath):
  1656     def RefreshConfigRecentProjects(self, projectpath):
  1660         recent_projects.insert(0, projectpath)
  1660         recent_projects.insert(0, projectpath)
  1661         self.Config.Write("RecentProjects", cPickle.dumps(recent_projects[:MAX_RECENT_PROJECTS]))
  1661         self.Config.Write("RecentProjects", cPickle.dumps(recent_projects[:MAX_RECENT_PROJECTS]))
  1662         self.Config.Flush()
  1662         self.Config.Flush()
  1663     
  1663     
  1664     def OnNewProjectMenu(self, event):
  1664     def OnNewProjectMenu(self, event):
  1665         if self.PluginRoot is not None and not self.CheckSaveBeforeClosing():
  1665         if self.CTR is not None and not self.CheckSaveBeforeClosing():
  1666             return
  1666             return
  1667         
  1667         
  1668         if not self.Config.HasEntry("lastopenedfolder"):
  1668         if not self.Config.HasEntry("lastopenedfolder"):
  1669             defaultpath = os.path.expanduser("~")
  1669             defaultpath = os.path.expanduser("~")
  1670         else:
  1670         else:
  1674         if dialog.ShowModal() == wx.ID_OK:
  1674         if dialog.ShowModal() == wx.ID_OK:
  1675             projectpath = dialog.GetPath()
  1675             projectpath = dialog.GetPath()
  1676             self.Config.Write("lastopenedfolder", os.path.dirname(projectpath))
  1676             self.Config.Write("lastopenedfolder", os.path.dirname(projectpath))
  1677             self.Config.Flush()
  1677             self.Config.Flush()
  1678             self.ResetView()
  1678             self.ResetView()
  1679             plugin_root = PluginsRoot(self, self.Log)
  1679             ctr = ConfigTreeRoot(self, self.Log)
  1680             result = plugin_root.NewProject(projectpath)
  1680             result = ctr.NewProject(projectpath)
  1681             if not result:
  1681             if not result:
  1682                 self.PluginRoot = plugin_root
  1682                 self.CTR = ctr
  1683                 self.Controler = self.PluginRoot
  1683                 self.Controler = self.CTR
  1684                 self.LibraryPanel.SetControler(self.Controler)
  1684                 self.LibraryPanel.SetControler(self.Controler)
  1685                 self.RefreshConfigRecentProjects(projectpath)
  1685                 self.RefreshConfigRecentProjects(projectpath)
  1686                 if self.EnableDebug:
  1686                 if self.EnableDebug:
  1687                     self.DebugVariablePanel.SetDataProducer(self.PluginRoot)
  1687                     self.DebugVariablePanel.SetDataProducer(self.CTR)
  1688                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
  1688                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
  1689                 self.RefreshAll()
  1689                 self.RefreshAll()
  1690             else:
  1690             else:
  1691                 self.ResetView()
  1691                 self.ResetView()
  1692                 self.ShowErrorMessage(result)
  1692                 self.ShowErrorMessage(result)
  1693             self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1693             self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1694         dialog.Destroy()
  1694         dialog.Destroy()
  1695     
  1695     
  1696     def OnOpenProjectMenu(self, event):
  1696     def OnOpenProjectMenu(self, event):
  1697         if self.PluginRoot is not None and not self.CheckSaveBeforeClosing():
  1697         if self.CTR is not None and not self.CheckSaveBeforeClosing():
  1698             return
  1698             return
  1699         
  1699         
  1700         if not self.Config.HasEntry("lastopenedfolder"):
  1700         if not self.Config.HasEntry("lastopenedfolder"):
  1701             defaultpath = os.path.expanduser("~")
  1701             defaultpath = os.path.expanduser("~")
  1702         else:
  1702         else:
  1710     def OpenProject(self, projectpath):
  1710     def OpenProject(self, projectpath):
  1711         if os.path.isdir(projectpath):
  1711         if os.path.isdir(projectpath):
  1712             self.Config.Write("lastopenedfolder", os.path.dirname(projectpath))
  1712             self.Config.Write("lastopenedfolder", os.path.dirname(projectpath))
  1713             self.Config.Flush()
  1713             self.Config.Flush()
  1714             self.ResetView()
  1714             self.ResetView()
  1715             self.PluginRoot = PluginsRoot(self, self.Log)
  1715             self.CTR = ConfigTreeRoot(self, self.Log)
  1716             self.Controler = self.PluginRoot
  1716             self.Controler = self.CTR
  1717             result = self.PluginRoot.LoadProject(projectpath)
  1717             result = self.CTR.LoadProject(projectpath)
  1718             if not result:
  1718             if not result:
  1719                 self.LibraryPanel.SetControler(self.Controler)
  1719                 self.LibraryPanel.SetControler(self.Controler)
  1720                 self.RefreshConfigRecentProjects(projectpath)
  1720                 self.RefreshConfigRecentProjects(projectpath)
  1721                 if self.EnableDebug:
  1721                 if self.EnableDebug:
  1722                     self.DebugVariablePanel.SetDataProducer(self.PluginRoot)
  1722                     self.DebugVariablePanel.SetDataProducer(self.CTR)
  1723                 self.LoadProjectOrganization()
  1723                 self.LoadProjectOrganization()
  1724                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
  1724                 self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
  1725                 self.RefreshAll()
  1725                 self.RefreshAll()
  1726             else:
  1726             else:
  1727                 self.ResetView()
  1727                 self.ResetView()
  1729         else:
  1729         else:
  1730             self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
  1730             self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
  1731         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1731         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1732     
  1732     
  1733     def OnCloseProjectMenu(self, event):
  1733     def OnCloseProjectMenu(self, event):
  1734         if self.PluginRoot is not None and not self.CheckSaveBeforeClosing():
  1734         if self.CTR is not None and not self.CheckSaveBeforeClosing():
  1735             return
  1735             return
  1736         
  1736         
  1737         self.SaveProjectOrganization()
  1737         self.SaveProjectOrganization()
  1738         self.ResetView()
  1738         self.ResetView()
  1739         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1739         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1740         self.RefreshAll()
  1740         self.RefreshAll()
  1741     
  1741     
  1742     def OnSaveProjectMenu(self, event):
  1742     def OnSaveProjectMenu(self, event):
  1743         if self.PluginRoot is not None:
  1743         if self.CTR is not None:
  1744             self.PluginRoot.SaveProject()
  1744             self.CTR.SaveProject()
  1745             self.RefreshAll()
  1745             self.RefreshAll()
  1746             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1746             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1747     
  1747     
  1748     def OnSaveProjectAsMenu(self, event):
  1748     def OnSaveProjectAsMenu(self, event):
  1749         if self.PluginRoot is not None:
  1749         if self.CTR is not None:
  1750             self.PluginRoot.SaveProjectAs()
  1750             self.CTR.SaveProjectAs()
  1751             self.RefreshAll()
  1751             self.RefreshAll()
  1752             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1752             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1753         event.Skip()
  1753         event.Skip()
  1754     
  1754     
  1755     def OnPropertiesMenu(self, event):
  1755     def OnPropertiesMenu(self, event):
  1763     
  1763     
  1764     def OnAboutMenu(self, event):
  1764     def OnAboutMenu(self, event):
  1765         OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc","about.html"), wx.Size(550, 500))
  1765         OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc","about.html"), wx.Size(550, 500))
  1766     
  1766     
  1767     def OnPouSelectedChanged(self, event):
  1767     def OnPouSelectedChanged(self, event):
  1768         wx.CallAfter(self.RefreshPluginMenu)
  1768         wx.CallAfter(self.RefreshConfNodeMenu)
  1769         IDEFrame.OnPouSelectedChanged(self, event)
  1769         IDEFrame.OnPouSelectedChanged(self, event)
  1770     
  1770     
  1771     def OnPageClose(self, event):
  1771     def OnPageClose(self, event):
  1772         wx.CallAfter(self.RefreshPluginMenu)
  1772         wx.CallAfter(self.RefreshConfNodeMenu)
  1773         IDEFrame.OnPageClose(self, event)
  1773         IDEFrame.OnPageClose(self, event)
  1774     
  1774     
  1775     def GetAddButtonFunction(self, plugin, window):
  1775     def GetAddButtonFunction(self, confnode, window):
  1776         def AddButtonFunction(event):
  1776         def AddButtonFunction(event):
  1777             if plugin and len(plugin.PlugChildsTypes) > 0:
  1777             if confnode and len(confnode.PlugChildsTypes) > 0:
  1778                 plugin_menu = wx.Menu(title='')
  1778                 confnode_menu = wx.Menu(title='')
  1779                 for name, XSDClass, help in plugin.PlugChildsTypes:
  1779                 for name, XSDClass, help in confnode.PlugChildsTypes:
  1780                     new_id = wx.NewId()
  1780                     new_id = wx.NewId()
  1781                     plugin_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name)
  1781                     confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name)
  1782                     self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name, plugin), id=new_id)
  1782                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
  1783                 window_pos = window.GetPosition()
  1783                 window_pos = window.GetPosition()
  1784                 wx.CallAfter(self.PLCConfig.PopupMenu, plugin_menu)
  1784                 wx.CallAfter(self.PLCConfig.PopupMenu, confnode_menu)
  1785             event.Skip()
  1785             event.Skip()
  1786         return AddButtonFunction
  1786         return AddButtonFunction
  1787     
  1787     
  1788     def GetDeleteButtonFunction(self, plugin):
  1788     def GetDeleteButtonFunction(self, confnode):
  1789         def DeleteButtonFunction(event):
  1789         def DeleteButtonFunction(event):
  1790             wx.CallAfter(self.DeletePlugin, plugin)
  1790             wx.CallAfter(self.DeleteConfNode, confnode)
  1791             event.Skip()
  1791             event.Skip()
  1792         return DeleteButtonFunction
  1792         return DeleteButtonFunction
  1793     
  1793     
  1794     def AddPlugin(self, PluginType, plugin):
  1794     def AddConfNode(self, ConfNodeType, confnode):
  1795         if self.PluginRoot.CheckProjectPathPerm():
  1795         if self.CTR.CheckProjectPathPerm():
  1796             dialog = wx.TextEntryDialog(self, _("Please enter a name for plugin:"), _("Add Plugin"), "", wx.OK|wx.CANCEL)
  1796             dialog = wx.TextEntryDialog(self, _("Please enter a name for confnode:"), _("Add ConfNode"), "", wx.OK|wx.CANCEL)
  1797             if dialog.ShowModal() == wx.ID_OK:
  1797             if dialog.ShowModal() == wx.ID_OK:
  1798                 PluginName = dialog.GetValue()
  1798                 ConfNodeName = dialog.GetValue()
  1799                 plugin.PlugAddChild(PluginName, PluginType)
  1799                 confnode.PlugAddChild(ConfNodeName, ConfNodeType)
  1800                 self.PluginRoot.RefreshPluginsBlockLists()
  1800                 self.CTR.RefreshConfNodesBlockLists()
  1801                 self._Refresh(TITLE, FILEMENU)
  1801                 self._Refresh(TITLE, FILEMENU)
  1802                 self.RefreshPluginTree()
  1802                 self.RefreshConfNodeTree()
  1803             dialog.Destroy()
  1803             dialog.Destroy()
  1804     
  1804     
  1805     def DeletePlugin(self, plugin):
  1805     def DeleteConfNode(self, confnode):
  1806         if self.PluginRoot.CheckProjectPathPerm():
  1806         if self.CTR.CheckProjectPathPerm():
  1807             dialog = wx.MessageDialog(self, _("Really delete plugin ?"), _("Remove plugin"), wx.YES_NO|wx.NO_DEFAULT)
  1807             dialog = wx.MessageDialog(self, _("Really delete confnode ?"), _("Remove confnode"), wx.YES_NO|wx.NO_DEFAULT)
  1808             if dialog.ShowModal() == wx.ID_YES:
  1808             if dialog.ShowModal() == wx.ID_YES:
  1809                 self.PluginInfos.pop(plugin)
  1809                 self.ConfNodeInfos.pop(confnode)
  1810                 plugin.PlugRemove()
  1810                 confnode.PlugRemove()
  1811                 del plugin
  1811                 del confnode
  1812                 self.PluginRoot.RefreshPluginsBlockLists()
  1812                 self.CTR.RefreshConfNodesBlockLists()
  1813                 self._Refresh(TITLE, FILEMENU)
  1813                 self._Refresh(TITLE, FILEMENU)
  1814                 self.RefreshPluginTree()
  1814                 self.RefreshConfNodeTree()
  1815             dialog.Destroy()
  1815             dialog.Destroy()
  1816     
  1816     
  1817 #-------------------------------------------------------------------------------
  1817 #-------------------------------------------------------------------------------
  1818 #                               Exception Handler
  1818 #                               Exception Handler
  1819 #-------------------------------------------------------------------------------
  1819 #-------------------------------------------------------------------------------