Beremiz.py
changeset 755 9f5dbd90e1e0
parent 749 050f5a001826
child 759 8f6ed225f4d8
child 760 d38560559afb
equal deleted inserted replaced
754:a8c258f7bdcf 755:9f5dbd90e1e0
   163 from docutil import OpenHtmlFrame
   163 from docutil import OpenHtmlFrame
   164 from PLCOpenEditor import IDEFrame, AppendMenu, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES 
   164 from PLCOpenEditor import IDEFrame, AppendMenu, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES 
   165 from PLCOpenEditor import EditorPanel, Viewer, TextViewer, GraphicViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor
   165 from PLCOpenEditor import EditorPanel, Viewer, TextViewer, GraphicViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor
   166 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY, ITEM_PROJECT, ITEM_RESOURCE
   166 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY, ITEM_PROJECT, ITEM_RESOURCE
   167 
   167 
   168 SCROLLBAR_UNIT = 10
       
   169 WINDOW_COLOUR = wx.Colour(240,240,240)
       
   170 TITLE_COLOUR = wx.Colour(200,200,220)
       
   171 CHANGED_TITLE_COLOUR = wx.Colour(220,200,220)
       
   172 CHANGED_WINDOW_COLOUR = wx.Colour(255,240,240)
       
   173 
       
   174 if wx.Platform == '__WXMSW__':
       
   175     faces = { 'times': 'Times New Roman',
       
   176               'mono' : 'Courier New',
       
   177               'helv' : 'Arial',
       
   178               'other': 'Comic Sans MS',
       
   179               'size' : 16,
       
   180              }
       
   181 else:
       
   182     faces = { 'times': 'Times',
       
   183               'mono' : 'Courier',
       
   184               'helv' : 'Helvetica',
       
   185               'other': 'new century schoolbook',
       
   186               'size' : 18,
       
   187              }
       
   188 
       
   189 MAX_RECENT_PROJECTS = 10
   168 MAX_RECENT_PROJECTS = 10
   190 
       
   191 # Some helpers to tweak GenBitmapTextButtons
       
   192 # TODO: declare customized classes instead.
       
   193 gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
       
   194 gen_textbutton_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenButton._GetLabelSize(obj)[:-1] + (False,))
       
   195 
       
   196 def make_genbitmaptogglebutton_flat(button):
       
   197     button.GetBackgroundBrush = gen_mini_GetBackgroundBrush(button)
       
   198     button.labelDelta = 0
       
   199     button.SetBezelWidth(0)
       
   200     button.SetUseFocusIndicator(False)
       
   201 
       
   202 # Patch wx.lib.imageutils so that gray is supported on alpha images
       
   203 import wx.lib.imageutils
       
   204 from wx.lib.imageutils import grayOut as old_grayOut
       
   205 def grayOut(anImage):
       
   206     if anImage.HasAlpha():
       
   207         AlphaData = anImage.GetAlphaData()
       
   208     else :
       
   209         AlphaData = None
       
   210 
       
   211     old_grayOut(anImage)
       
   212 
       
   213     if AlphaData is not None:
       
   214         anImage.SetAlphaData(AlphaData)
       
   215 
       
   216 wx.lib.imageutils.grayOut = grayOut
       
   217 
       
   218 class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
       
   219     def _GetLabelSize(self):
       
   220         """ used internally """
       
   221         w, h = self.GetTextExtent(self.GetLabel())
       
   222         if not self.bmpLabel:
       
   223             return w, h, False       # if there isn't a bitmap use the size of the text
       
   224 
       
   225         w_bmp = self.bmpLabel.GetWidth()+2
       
   226         h_bmp = self.bmpLabel.GetHeight()+2
       
   227         height = h + h_bmp
       
   228         if w_bmp > w:
       
   229             width = w_bmp
       
   230         else:
       
   231             width = w
       
   232         return width, height, False
       
   233 
       
   234     def DrawLabel(self, dc, width, height, dw=0, dy=0):
       
   235         bmp = self.bmpLabel
       
   236         if bmp != None:     # if the bitmap is used
       
   237             if self.bmpDisabled and not self.IsEnabled():
       
   238                 bmp = self.bmpDisabled
       
   239             if self.bmpFocus and self.hasFocus:
       
   240                 bmp = self.bmpFocus
       
   241             if self.bmpSelected and not self.up:
       
   242                 bmp = self.bmpSelected
       
   243             bw,bh = bmp.GetWidth(), bmp.GetHeight()
       
   244             if not self.up:
       
   245                 dw = dy = self.labelDelta
       
   246             hasMask = bmp.GetMask() != None
       
   247         else:
       
   248             bw = bh = 0     # no bitmap -> size is zero
       
   249 
       
   250         dc.SetFont(self.GetFont())
       
   251         if self.IsEnabled():
       
   252             dc.SetTextForeground(self.GetForegroundColour())
       
   253         else:
       
   254             dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
       
   255 
       
   256         label = self.GetLabel()
       
   257         tw, th = dc.GetTextExtent(label)        # size of text
       
   258         if not self.up:
       
   259             dw = dy = self.labelDelta
       
   260 
       
   261         pos_x = (width-bw)/2+dw      # adjust for bitmap and text to centre
       
   262         pos_y = (height-bh-th)/2+dy
       
   263         if bmp !=None:
       
   264             dc.DrawBitmap(bmp, pos_x, pos_y, hasMask) # draw bitmap if available
       
   265             pos_x = (width-tw)/2+dw      # adjust for bitmap and text to centre
       
   266             pos_y += bh + 2
       
   267 
       
   268         dc.DrawText(label, pos_x, pos_y)      # draw the text
       
   269 
       
   270 
   169 
   271 class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
   170 class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
   272     """ Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32, 
   171     """ Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32, 
   273     and accept image name as __init__ parameter, fail silently if file do not exist"""
   172     and accept image name as __init__ parameter, fail silently if file do not exist"""
   274     def __init__(self, parent, ID, bitmapname,
   173     def __init__(self, parent, ID, bitmapname,
   426         AppendMenu(parent, help='', id=wx.ID_PREVIEW,
   325         AppendMenu(parent, help='', id=wx.ID_PREVIEW,
   427               kind=wx.ITEM_NORMAL, text=_(u'Preview\tCTRL+SHIFT+P'))
   326               kind=wx.ITEM_NORMAL, text=_(u'Preview\tCTRL+SHIFT+P'))
   428         AppendMenu(parent, help='', id=wx.ID_PRINT,
   327         AppendMenu(parent, help='', id=wx.ID_PRINT,
   429               kind=wx.ITEM_NORMAL, text=_(u'Print\tCTRL+P'))
   328               kind=wx.ITEM_NORMAL, text=_(u'Print\tCTRL+P'))
   430         parent.AppendSeparator()
   329         parent.AppendSeparator()
   431         AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
       
   432               kind=wx.ITEM_NORMAL, text=_(u'&Properties'))
       
   433         parent.AppendSeparator()
       
   434         AppendMenu(parent, help='', id=wx.ID_EXIT,
   330         AppendMenu(parent, help='', id=wx.ID_EXIT,
   435               kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
   331               kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
   436         
   332         
   437         self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
   333         self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
   438         self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
   334         self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
   441         self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
   337         self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
   442         self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL)
   338         self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL)
   443         self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
   339         self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
   444         self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
   340         self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
   445         self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
   341         self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
   446         self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES)
       
   447         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
   342         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
   448     
   343     
   449         self.AddToMenuToolBar([(wx.ID_NEW, "new.png", _(u'New'), None),
   344         self.AddToMenuToolBar([(wx.ID_NEW, "new.png", _(u'New'), None),
   450                                (wx.ID_OPEN, "open.png", _(u'Open'), None),
   345                                (wx.ID_OPEN, "open.png", _(u'Open'), None),
   451                                (wx.ID_SAVE, "save.png", _(u'Save'), None),
   346                                (wx.ID_SAVE, "save.png", _(u'Save'), None),
   466     def _init_coll_HelpMenu_Items(self, parent):
   361     def _init_coll_HelpMenu_Items(self, parent):
   467         parent.Append(help='', id=wx.ID_ABOUT,
   362         parent.Append(help='', id=wx.ID_ABOUT,
   468               kind=wx.ITEM_NORMAL, text=_(u'About'))
   363               kind=wx.ITEM_NORMAL, text=_(u'About'))
   469         self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
   364         self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
   470     
   365     
   471     def _init_coll_PLCConfigMainSizer_Items(self, parent):
       
   472         parent.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
       
   473         parent.AddSizer(self.ConfNodeTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT)
       
   474         
       
   475     def _init_coll_PLCConfigMainSizer_Growables(self, parent):
       
   476         parent.AddGrowableCol(0)
       
   477         parent.AddGrowableRow(1)
       
   478     
       
   479     def _init_coll_ConfNodeTreeSizer_Growables(self, parent):
       
   480         parent.AddGrowableCol(0)
       
   481         parent.AddGrowableCol(1)
       
   482         
       
   483     def _init_beremiz_sizers(self):
       
   484         self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
       
   485         self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL)
       
   486         #self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2)
       
   487         self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2)
       
   488         
       
   489         self._init_coll_PLCConfigMainSizer_Items(self.PLCConfigMainSizer)
       
   490         self._init_coll_PLCConfigMainSizer_Growables(self.PLCConfigMainSizer)
       
   491         self._init_coll_ConfNodeTreeSizer_Growables(self.ConfNodeTreeSizer)
       
   492         
       
   493         self.PLCConfig.SetSizer(self.PLCConfigMainSizer)
       
   494         
       
   495     def _init_ctrls(self, prnt):
   366     def _init_ctrls(self, prnt):
   496         IDEFrame._init_ctrls(self, prnt)
   367         IDEFrame._init_ctrls(self, prnt)
   497         
   368         
   498         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR)
   369         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR)
   499         accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)]
   370         accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)]
   512             self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
   383             self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
   513             accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
   384             accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
   514         
   385         
   515         self.SetAcceleratorTable(wx.AcceleratorTable(accels))
   386         self.SetAcceleratorTable(wx.AcceleratorTable(accels))
   516         
   387         
   517         self.PLCConfig = wx.ScrolledWindow(id=ID_BEREMIZPLCCONFIG,
       
   518               name='PLCConfig', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
       
   519               size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL)
       
   520         self.PLCConfig.SetBackgroundColour(wx.WHITE)
       
   521         self.PLCConfig.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
       
   522         self.PLCConfig.Bind(wx.EVT_SIZE, self.OnMoveWindow)
       
   523         self.PLCConfig.Bind(wx.EVT_MOUSEWHEEL, self.OnPLCConfigScroll)
       
   524         self.PLCConfig.Hide()
       
   525         #self.MainTabs["PLCConfig"] = (self.PLCConfig, _("Topology"))
       
   526         #self.BottomNoteBook.InsertPage(0, self.PLCConfig, _("Topology"), True)
       
   527         
       
   528         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
   388         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
   529                   name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
   389                   name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
   530                   size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
   390                   size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
   531         self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
   391         self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
   532         self.MainTabs["LogConsole"] = (self.LogConsole, _("Log Console"))
   392         self.MainTabs["LogConsole"] = (self.LogConsole, _("Log Console"))
   541         self.AUIManager.AddPane(StatusToolBar, wx.aui.AuiPaneInfo().
   401         self.AUIManager.AddPane(StatusToolBar, wx.aui.AuiPaneInfo().
   542                   Name("StatusToolBar").Caption(_("Status ToolBar")).
   402                   Name("StatusToolBar").Caption(_("Status ToolBar")).
   543                   ToolbarPane().Top().Position(2).
   403                   ToolbarPane().Top().Position(2).
   544                   LeftDockable(False).RightDockable(False))
   404                   LeftDockable(False).RightDockable(False))
   545         
   405         
   546         self._init_beremiz_sizers()
       
   547 
       
   548         self.AUIManager.Update()
   406         self.AUIManager.Update()
   549         
   407         
   550     def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
   408     def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
   551         IDEFrame.__init__(self, parent, debug)
   409         IDEFrame.__init__(self, parent, debug)
   552         self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
   410         self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
   553         
   411         
   554         self.local_runtime = None
   412         self.local_runtime = None
   555         self.runtime_port = None
   413         self.runtime_port = None
   556         self.local_runtime_tmpdir = None
   414         self.local_runtime_tmpdir = None
   557         
   415         
   558         self.DisableEvents = False
       
   559         # Variable allowing disabling of PLCConfig scroll when Popup shown 
       
   560         self.ScrollingEnabled = True
       
   561         
       
   562         self.LastPanelSelected = None
   416         self.LastPanelSelected = None
   563         
       
   564         self.ConfNodeInfos = {}
       
   565         
   417         
   566         # Define Tree item icon list
   418         # Define Tree item icon list
   567         self.LocationImageList = wx.ImageList(16, 16)
   419         self.LocationImageList = wx.ImageList(16, 16)
   568         self.LocationImageDict = {}
   420         self.LocationImageDict = {}
   569         
   421         
   598                 self.LibraryPanel.SetControler(self.Controler)
   450                 self.LibraryPanel.SetControler(self.Controler)
   599                 self.ProjectTree.Enable(True)
   451                 self.ProjectTree.Enable(True)
   600                 self.PouInstanceVariablesPanel.SetController(self.Controler)
   452                 self.PouInstanceVariablesPanel.SetController(self.Controler)
   601                 self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
   453                 self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
   602                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   454                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   603                 self.RefreshStatusToolBar()
       
   604             else:
   455             else:
   605                 self.ResetView()
   456                 self.ResetView()
   606                 self.ShowErrorMessage(result)
   457                 self.ShowErrorMessage(result)
   607         else:
   458         else:
   608             self.CTR = ctr
   459             self.CTR = ctr
   610             if ctr is not None:
   461             if ctr is not None:
   611                 self.LibraryPanel.SetControler(self.Controler)
   462                 self.LibraryPanel.SetControler(self.Controler)
   612                 self.ProjectTree.Enable(True)
   463                 self.ProjectTree.Enable(True)
   613                 self.PouInstanceVariablesPanel.SetController(self.Controler)
   464                 self.PouInstanceVariablesPanel.SetController(self.Controler)
   614                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   465                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   615                 self.RefreshStatusToolBar()
       
   616         if self.EnableDebug:
   466         if self.EnableDebug:
   617             self.DebugVariablePanel.SetDataProducer(self.CTR)
   467             self.DebugVariablePanel.SetDataProducer(self.CTR)
   618         
   468         
   619         self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
   469         self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
   620         
   470         
   621         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
   471         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
   622         self.RefreshConfNodeMenu()
   472         self.RefreshConfNodeMenu()
   623         self.RefreshStatusToolBar()
   473         self.RefreshAll()
   624         self.LogConsole.SetFocus()
   474         self.LogConsole.SetFocus()
   625 
   475 
   626     def RiseLogConsole(self):
   476     def RiseLogConsole(self):
   627         self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
   477         self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
   628         
   478         
   748             self.Config.Flush()
   598             self.Config.Flush()
   749             
   599             
   750             event.Skip()
   600             event.Skip()
   751         else:
   601         else:
   752             event.Veto()
   602             event.Veto()
   753     
       
   754     def OnMoveWindow(self, event):
       
   755         self.GetBestSize()
       
   756         self.RefreshScrollBars()
       
   757         event.Skip()
       
   758     
       
   759     def EnableScrolling(self, enable):
       
   760         self.ScrollingEnabled = enable
       
   761     
       
   762     def OnPLCConfigScroll(self, event):
       
   763         if self.ScrollingEnabled:
       
   764             event.Skip()
       
   765 
       
   766     def OnPanelLeftDown(self, event):
       
   767         focused = self.FindFocus()
       
   768         if isinstance(focused, TextCtrlAutoComplete):
       
   769             focused.DismissListBox()
       
   770         event.Skip()
       
   771     
   603     
   772     def RefreshFileMenu(self):
   604     def RefreshFileMenu(self):
   773         self.RefreshRecentProjectsMenu()
   605         self.RefreshRecentProjectsMenu()
   774         
   606         
   775         MenuToolBar = self.Panes["MenuToolBar"]
   607         MenuToolBar = self.Panes["MenuToolBar"]
   897                 panel.RefreshConfNodeMenu(self.ConfNodeMenu)
   729                 panel.RefreshConfNodeMenu(self.ConfNodeMenu)
   898         else:
   730         else:
   899             self.MenuBar.EnableTop(CONFNODEMENU_POSITION, False)
   731             self.MenuBar.EnableTop(CONFNODEMENU_POSITION, False)
   900         self.MenuBar.UpdateMenus()
   732         self.MenuBar.UpdateMenus()
   901     
   733     
   902     def RefreshScrollBars(self):
       
   903         xstart, ystart = self.PLCConfig.GetViewStart()
       
   904         window_size = self.PLCConfig.GetClientSize()
       
   905         sizer = self.PLCConfig.GetSizer()
       
   906         if sizer:
       
   907             maxx, maxy = sizer.GetMinSize()
       
   908             posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
       
   909             posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
       
   910             self.PLCConfig.Scroll(posx, posy)
       
   911             self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
       
   912                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
       
   913 
       
   914     def RefreshPLCParams(self):
       
   915         self.Freeze()
       
   916         self.ClearSizer(self.PLCParamsSizer)
       
   917         
       
   918         if self.CTR is not None:    
       
   919             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
   920             if self.CTR.CTNTestModified():
       
   921                 bkgdclr = CHANGED_TITLE_COLOUR
       
   922             else:
       
   923                 bkgdclr = TITLE_COLOUR
       
   924                 
       
   925             if self.CTR not in self.ConfNodeInfos:
       
   926                 self.ConfNodeInfos[self.CTR] = {"right_visible" : False}
       
   927             
       
   928             plcwindow.SetBackgroundColour(TITLE_COLOUR)
       
   929             plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
       
   930             self.PLCParamsSizer.AddWindow(plcwindow, 0, border=0, flag=wx.GROW)
       
   931             
       
   932             plcwindowsizer = wx.BoxSizer(wx.HORIZONTAL)
       
   933             plcwindow.SetSizer(plcwindowsizer)
       
   934             
       
   935             st = wx.StaticText(plcwindow, -1)
       
   936             st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
   937             st.SetLabel(self.CTR.GetProjectName())
       
   938             plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER)
       
   939             
       
   940             addbutton_id = wx.NewId()
       
   941             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
       
   942                   name='AddConfNodeButton', parent=plcwindow, pos=wx.Point(0, 0),
       
   943                   size=wx.Size(16, 16), style=wx.NO_BORDER)
       
   944             addbutton.SetToolTipString(_("Add a sub confnode"))
       
   945             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(self.CTR), id=addbutton_id)
       
   946             plcwindowsizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
       
   947     
       
   948             plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
       
   949             plcwindowsizer.AddSizer(plcwindowmainsizer, 0, border=5, flag=wx.ALL)
       
   950             
       
   951             plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL)
       
   952             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
       
   953             
       
   954             msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"])
       
   955             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
       
   956             
       
   957             paramswindow = wx.Panel(plcwindow, -1, size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
       
   958             paramswindow.SetBackgroundColour(TITLE_COLOUR)
       
   959             paramswindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
       
   960             plcwindowbuttonsizer.AddWindow(paramswindow, 0, border=0, flag=0)
       
   961             
       
   962             psizer = wx.BoxSizer(wx.HORIZONTAL)
       
   963             paramswindow.SetSizer(psizer)
       
   964             
       
   965             confnode_infos = self.CTR.GetParamsAttributes()
       
   966             self.RefreshSizerElement(paramswindow, psizer, self.CTR, confnode_infos, None, False)
       
   967             
       
   968             if not self.ConfNodeInfos[self.CTR]["right_visible"]:
       
   969                 paramswindow.Hide()
       
   970             
       
   971             minimizebutton_id = wx.NewId()
       
   972             minimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=minimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
       
   973                   name='MinimizeButton', parent=plcwindow, pos=wx.Point(0, 0),
       
   974                   size=wx.Size(24, 24), style=wx.NO_BORDER)
       
   975             make_genbitmaptogglebutton_flat(minimizebutton)
       
   976             minimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
       
   977             minimizebutton.SetToggle(self.ConfNodeInfos[self.CTR]["right_visible"])
       
   978             plcwindowbuttonsizer.AddWindow(minimizebutton, 0, border=5, flag=wx.ALL)
       
   979             
       
   980             def togglewindow(event):
       
   981                 if minimizebutton.GetToggle():
       
   982                     paramswindow.Show()
       
   983                     msizer.SetCols(1)
       
   984                 else:
       
   985                     paramswindow.Hide()
       
   986                     msizer.SetCols(len(self.CTR.ConfNodeMethods))
       
   987                 self.ConfNodeInfos[self.CTR]["right_visible"] = minimizebutton.GetToggle()
       
   988                 self.PLCConfigMainSizer.Layout()
       
   989                 self.RefreshScrollBars()
       
   990                 event.Skip()
       
   991             minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id)
       
   992         
       
   993             self.ConfNodeInfos[self.CTR]["main"] = plcwindow
       
   994             self.ConfNodeInfos[self.CTR]["params"] = paramswindow
       
   995             
       
   996         self.PLCConfigMainSizer.Layout()
       
   997         self.RefreshScrollBars()
       
   998         self.Thaw()
       
   999 
       
  1000     def GenerateEnableButton(self, parent, sizer, confnode):
       
  1001         enabled = confnode.CTNEnabled()
       
  1002         if enabled is not None:
       
  1003             enablebutton_id = wx.NewId()
       
  1004             enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')),
       
  1005                   name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
       
  1006             enablebutton.SetToolTipString(_("Enable/Disable this confnode"))
       
  1007             make_genbitmaptogglebutton_flat(enablebutton)
       
  1008             enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png')))
       
  1009             enablebutton.SetToggle(enabled)
       
  1010             def toggleenablebutton(event):
       
  1011                 res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.Enabled", enablebutton.GetToggle())
       
  1012                 enablebutton.SetToggle(res)
       
  1013                 event.Skip()
       
  1014             enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
       
  1015             sizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1016         else:
       
  1017             sizer.AddSpacer(wx.Size(16, 16))
       
  1018     
       
  1019     def GenerateMethodButtonSizer(self, confnode, parent, horizontal = True):
       
  1020         normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
       
  1021         mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
       
  1022         if horizontal:
       
  1023             msizer = wx.FlexGridSizer(cols=len(confnode.ConfNodeMethods))
       
  1024         else:
       
  1025             msizer = wx.FlexGridSizer(cols=1)
       
  1026         for confnode_method in confnode.ConfNodeMethods:
       
  1027             if "method" in confnode_method and confnode_method.get("shown",True):
       
  1028                 id = wx.NewId()
       
  1029                 label = confnode_method["name"]
       
  1030                 button = GenBitmapTextButton(id=id, parent=parent,
       
  1031                     bitmap=wx.Bitmap(Bpath("images", "%s.png"%confnode_method.get("bitmap", "Unknown"))), label=label, 
       
  1032                     name=label, pos=wx.DefaultPosition, style=wx.NO_BORDER)
       
  1033                 button.SetFont(normal_bt_font)
       
  1034                 button.SetToolTipString(confnode_method["tooltip"])
       
  1035                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode, confnode_method["method"]), id=id)
       
  1036                 # a fancy underline on mouseover
       
  1037                 def setFontStyle(b, s):
       
  1038                     def fn(event):
       
  1039                         b.SetFont(s)
       
  1040                         b.Refresh()
       
  1041                         event.Skip()
       
  1042                     return fn
       
  1043                 button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font))
       
  1044                 button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font))
       
  1045                 #hack to force size to mini
       
  1046                 if not confnode_method.get("enabled",True):
       
  1047                     button.Disable()
       
  1048                 msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER)
       
  1049         return msizer
       
  1050 
       
  1051     def GenerateParamsPanel(self, confnode, bkgdclr, top_offset=0):
       
  1052         rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1053         rightwindow.SetBackgroundColour(bkgdclr)
       
  1054         
       
  1055         rightwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
       
  1056         rightwindow.SetSizer(rightwindowmainsizer)
       
  1057         
       
  1058         rightwindowsizer = wx.FlexGridSizer(cols=2, rows=1)
       
  1059         rightwindowsizer.AddGrowableCol(1)
       
  1060         rightwindowsizer.AddGrowableRow(0)
       
  1061         rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=0, flag=wx.GROW)
       
  1062         
       
  1063         msizer = self.GenerateMethodButtonSizer(confnode, rightwindow, not self.ConfNodeInfos[confnode]["right_visible"])
       
  1064         rightwindowsizer.AddSizer(msizer, 0, border=top_offset, flag=wx.TOP|wx.GROW)
       
  1065         
       
  1066         rightparamssizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1067         rightwindowsizer.AddSizer(rightparamssizer, 0, border=0, flag=wx.ALIGN_RIGHT)
       
  1068         
       
  1069         paramswindow = wx.Panel(rightwindow, -1, size=wx.Size(-1, -1))
       
  1070         paramswindow.SetBackgroundColour(bkgdclr)
       
  1071         
       
  1072         psizer = wx.BoxSizer(wx.VERTICAL)
       
  1073         paramswindow.SetSizer(psizer)
       
  1074         self.ConfNodeInfos[confnode]["params"] = paramswindow
       
  1075         
       
  1076         rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL)
       
  1077         
       
  1078         confnode_infos = confnode.GetParamsAttributes()
       
  1079         if len(confnode_infos) > 0:
       
  1080             self.RefreshSizerElement(paramswindow, psizer, confnode, confnode_infos, None, False)
       
  1081             
       
  1082             if not self.ConfNodeInfos[confnode]["right_visible"]:
       
  1083                 paramswindow.Hide()
       
  1084             
       
  1085             rightminimizebutton_id = wx.NewId()
       
  1086             rightminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=rightminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
       
  1087                   name='MinimizeButton', parent=rightwindow, pos=wx.Point(0, 0),
       
  1088                   size=wx.Size(24, 24), style=wx.NO_BORDER)
       
  1089             make_genbitmaptogglebutton_flat(rightminimizebutton)
       
  1090             rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
       
  1091             rightminimizebutton.SetToggle(self.ConfNodeInfos[confnode]["right_visible"])
       
  1092             rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL)
       
  1093                         
       
  1094             def togglerightwindow(event):
       
  1095                 if rightminimizebutton.GetToggle():
       
  1096                     rightparamssizer.Show(0)
       
  1097                     msizer.SetCols(1)
       
  1098                 else:
       
  1099                     rightparamssizer.Hide(0)
       
  1100                     msizer.SetCols(len(confnode.ConfNodeMethods))
       
  1101                 self.ConfNodeInfos[confnode]["right_visible"] = rightminimizebutton.GetToggle()
       
  1102                 self.PLCConfigMainSizer.Layout()
       
  1103                 self.RefreshScrollBars()
       
  1104                 event.Skip()
       
  1105             rightminimizebutton.Bind(wx.EVT_BUTTON, togglerightwindow, id=rightminimizebutton_id)
       
  1106         
       
  1107         return rightwindow
       
  1108     
       
  1109 
       
  1110     def RefreshConfNodeTree(self):
       
  1111         self.Freeze()
       
  1112         self.ClearSizer(self.ConfNodeTreeSizer)
       
  1113         if self.CTR is not None:
       
  1114             for child in self.CTR.IECSortedChildren():
       
  1115                 self.GenerateTreeBranch(child)
       
  1116                 if not self.ConfNodeInfos[child]["expanded"]:
       
  1117                     self.CollapseConfNode(child)
       
  1118         self.PLCConfigMainSizer.Layout()
       
  1119         self.RefreshScrollBars()
       
  1120         self.Thaw()
       
  1121 
       
  1122     def SetConfNodeParamsAttribute(self, confnode, *args, **kwargs):
       
  1123         res, StructChanged = confnode.SetParamsAttribute(*args, **kwargs)
       
  1124         if StructChanged:
       
  1125             wx.CallAfter(self.RefreshConfNodeTree)
       
  1126         else:
       
  1127             if confnode == self.CTR:
       
  1128                 bkgdclr = CHANGED_TITLE_COLOUR
       
  1129                 items = ["main", "params"]
       
  1130             else:
       
  1131                 bkgdclr = CHANGED_WINDOW_COLOUR
       
  1132                 items = ["left", "right", "params"]
       
  1133             for i in items:
       
  1134                 self.ConfNodeInfos[confnode][i].SetBackgroundColour(bkgdclr)
       
  1135                 self.ConfNodeInfos[confnode][i].Refresh()
       
  1136         self._Refresh(TITLE, FILEMENU)
       
  1137         return res
       
  1138 
       
  1139     def ExpandConfNode(self, confnode, force = False):
       
  1140         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1141             self.ConfNodeInfos[child]["left"].Show()
       
  1142             self.ConfNodeInfos[child]["right"].Show()
       
  1143             if force or self.ConfNodeInfos[child]["expanded"]:
       
  1144                 self.ExpandConfNode(child, force)
       
  1145                 if force:
       
  1146                     self.ConfNodeInfos[child]["expanded"] = True
       
  1147         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
       
  1148         if locations_infos is not None:
       
  1149             if force or locations_infos["root"]["expanded"]:
       
  1150                 self.ExpandLocation(locations_infos, "root", force)
       
  1151                 if force:
       
  1152                     locations_infos["root"]["expanded"] = True
       
  1153     
       
  1154     def CollapseConfNode(self, confnode, force = False):
       
  1155         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1156             self.ConfNodeInfos[child]["left"].Hide()
       
  1157             self.ConfNodeInfos[child]["right"].Hide()
       
  1158             self.CollapseConfNode(child, force)
       
  1159             if force:
       
  1160                 self.ConfNodeInfos[child]["expanded"] = False
       
  1161         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
       
  1162         if locations_infos is not None:
       
  1163             self.CollapseLocation(locations_infos, "root", force)
       
  1164             if force:
       
  1165                 locations_infos["root"]["expanded"] = False
       
  1166 
       
  1167     def ExpandLocation(self, locations_infos, group, force = False, refresh_size=True):
       
  1168         locations_infos[group]["expanded"] = True
       
  1169         if group == "root":
       
  1170             if locations_infos[group]["left"] is not None:
       
  1171                 locations_infos[group]["left"].Show()
       
  1172             if locations_infos[group]["right"] is not None:
       
  1173                 locations_infos[group]["right"].Show()
       
  1174         elif locations_infos["root"]["left"] is not None:
       
  1175             locations_infos["root"]["left"].Expand(locations_infos[group]["item"])
       
  1176             if force:
       
  1177                 for child in locations_infos[group]["children"]:
       
  1178                     self.ExpandLocation(locations_infos, child, force, False)
       
  1179         if locations_infos["root"]["left"] is not None and refresh_size:
       
  1180             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1181         
       
  1182     def CollapseLocation(self, locations_infos, group, force = False, refresh_size=True):
       
  1183         locations_infos[group]["expanded"] = False
       
  1184         if group == "root":
       
  1185             if locations_infos[group]["left"] is not None:
       
  1186                 locations_infos[group]["left"].Hide()
       
  1187             if locations_infos[group]["right"] is not None:
       
  1188                 locations_infos[group]["right"].Hide()
       
  1189         elif locations_infos["root"]["left"] is not None:
       
  1190             locations_infos["root"]["left"].Collapse(locations_infos[group]["item"])
       
  1191             if force:
       
  1192                 for child in locations_infos[group]["children"]:
       
  1193                     self.CollapseLocation(locations_infos, child, force, False)
       
  1194         if locations_infos["root"]["left"] is not None and refresh_size:
       
  1195             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1196     
       
  1197     def GenerateTreeBranch(self, confnode):
       
  1198         leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1199         if confnode.CTNTestModified():
       
  1200             bkgdclr=CHANGED_WINDOW_COLOUR
       
  1201         else:
       
  1202             bkgdclr=WINDOW_COLOUR
       
  1203 
       
  1204         leftwindow.SetBackgroundColour(bkgdclr)
       
  1205         
       
  1206         if not self.ConfNodeInfos.has_key(confnode):
       
  1207             self.ConfNodeInfos[confnode] = {"expanded" : False, "right_visible" : False}
       
  1208             
       
  1209         self.ConfNodeInfos[confnode]["children"] = confnode.IECSortedChildren()
       
  1210         confnode_locations = []
       
  1211         if len(self.ConfNodeInfos[confnode]["children"]) == 0:
       
  1212             confnode_locations = confnode.GetVariableLocationTree()["children"]
       
  1213             if not self.ConfNodeInfos[confnode].has_key("locations_infos"):
       
  1214                 self.ConfNodeInfos[confnode]["locations_infos"] = {"root": {"expanded" : False}}
       
  1215             
       
  1216             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["left"] = None
       
  1217             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["right"] = None
       
  1218             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["children"] = []
       
  1219         
       
  1220         self.ConfNodeTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW)
       
  1221         
       
  1222         leftwindowsizer = wx.FlexGridSizer(cols=1, rows=2)
       
  1223         leftwindowsizer.AddGrowableCol(0)
       
  1224         leftwindow.SetSizer(leftwindowsizer)
       
  1225         
       
  1226         leftbuttonmainsizer = wx.FlexGridSizer(cols=3, rows=1)
       
  1227         leftbuttonmainsizer.AddGrowableCol(0)
       
  1228         leftwindowsizer.AddSizer(leftbuttonmainsizer, 0, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT) #|wx.TOP
       
  1229         
       
  1230         leftbuttonsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1231         leftbuttonmainsizer.AddSizer(leftbuttonsizer, 0, border=5, flag=wx.GROW|wx.RIGHT)
       
  1232         
       
  1233         leftsizer = wx.BoxSizer(wx.VERTICAL)
       
  1234         leftbuttonsizer.AddSizer(leftsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1235 
       
  1236         rolesizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1237         leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
       
  1238         
       
  1239         #self.GenerateEnableButton(leftwindow, rolesizer, confnode)
       
  1240 
       
  1241         roletext = wx.StaticText(leftwindow, -1)
       
  1242         roletext.SetLabel(confnode.CTNHelp)
       
  1243         rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT)
       
  1244         
       
  1245         confnode_IECChannel = confnode.BaseParams.getIEC_Channel()
       
  1246         
       
  1247         iecsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1248         leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1249 
       
  1250         st = wx.StaticText(leftwindow, -1)
       
  1251         st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
  1252         st.SetLabel(confnode.GetFullIEC_Channel())
       
  1253         iecsizer.AddWindow(st, 0, border=0, flag=0)
       
  1254 
       
  1255         updownsizer = wx.BoxSizer(wx.VERTICAL)
       
  1256         iecsizer.AddSizer(updownsizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
       
  1257 
       
  1258         if confnode_IECChannel > 0:
       
  1259             ieccdownbutton_id = wx.NewId()
       
  1260             ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCDown.png')),
       
  1261                   name='IECCDownButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1262                   size=wx.Size(16, 16), style=wx.NO_BORDER)
       
  1263             ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel - 1), id=ieccdownbutton_id)
       
  1264             updownsizer.AddWindow(ieccdownbutton, 0, border=0, flag=wx.ALIGN_LEFT)
       
  1265 
       
  1266         ieccupbutton_id = wx.NewId()
       
  1267         ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCUp.png')),
       
  1268               name='IECCUpButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1269               size=wx.Size(16, 16), style=wx.NO_BORDER)
       
  1270         ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel + 1), id=ieccupbutton_id)
       
  1271         updownsizer.AddWindow(ieccupbutton, 0, border=0, flag=wx.ALIGN_LEFT)
       
  1272 
       
  1273         adddeletesizer = wx.BoxSizer(wx.VERTICAL)
       
  1274         iecsizer.AddSizer(adddeletesizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
       
  1275 
       
  1276         deletebutton_id = wx.NewId()
       
  1277         deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Delete.png')),
       
  1278               name='DeleteConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1279               size=wx.Size(16, 16), style=wx.NO_BORDER)
       
  1280         deletebutton.SetToolTipString(_("Delete this confnode"))
       
  1281         deletebutton.Bind(wx.EVT_BUTTON, self.GetDeleteButtonFunction(confnode), id=deletebutton_id)
       
  1282         adddeletesizer.AddWindow(deletebutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
       
  1283 
       
  1284         if len(confnode.CTNChildrenTypes) > 0:
       
  1285             addbutton_id = wx.NewId()
       
  1286             addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')),
       
  1287                   name='AddConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1288                   size=wx.Size(16, 16), style=wx.NO_BORDER)
       
  1289             addbutton.SetToolTipString(_("Add a sub confnode"))
       
  1290             addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(confnode), id=addbutton_id)
       
  1291             adddeletesizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER)
       
  1292         
       
  1293         expandbutton_id = wx.NewId()
       
  1294         expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'plus.png')),
       
  1295               name='ExpandButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1296               size=wx.Size(13, 13), style=wx.NO_BORDER)
       
  1297         expandbutton.labelDelta = 0
       
  1298         expandbutton.SetBezelWidth(0)
       
  1299         expandbutton.SetUseFocusIndicator(False)
       
  1300         expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png')))
       
  1301             
       
  1302         if len(self.ConfNodeInfos[confnode]["children"]) > 0:
       
  1303             expandbutton.SetToggle(self.ConfNodeInfos[confnode]["expanded"])
       
  1304             def togglebutton(event):
       
  1305                 if expandbutton.GetToggle():
       
  1306                     self.ExpandConfNode(confnode)
       
  1307                 else:
       
  1308                     self.CollapseConfNode(confnode)
       
  1309                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
       
  1310                 self.PLCConfigMainSizer.Layout()
       
  1311                 self.RefreshScrollBars()
       
  1312                 event.Skip()
       
  1313             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
       
  1314         elif len(confnode_locations) > 0:
       
  1315             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
       
  1316             expandbutton.SetToggle(locations_infos["root"]["expanded"])
       
  1317             def togglebutton(event):
       
  1318                 if expandbutton.GetToggle():
       
  1319                     self.ExpandLocation(locations_infos, "root")
       
  1320                 else:
       
  1321                     self.CollapseLocation(locations_infos, "root")
       
  1322                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
       
  1323                 locations_infos["root"]["expanded"] = expandbutton.GetToggle()
       
  1324                 self.PLCConfigMainSizer.Layout()
       
  1325                 self.RefreshScrollBars()
       
  1326                 event.Skip()
       
  1327             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
       
  1328         else:
       
  1329             expandbutton.Enable(False)
       
  1330         iecsizer.AddWindow(expandbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1331         
       
  1332         tc_id = wx.NewId()
       
  1333         tc = wx.TextCtrl(leftwindow, tc_id, size=wx.Size(150, 25), style=wx.NO_BORDER)
       
  1334         tc.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
  1335         tc.ChangeValue(confnode.MandatoryParams[1].getName())
       
  1336         tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, confnode, "BaseParams.Name"), id=tc_id)
       
  1337         iecsizer.AddWindow(tc, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1338         
       
  1339         rightwindow = self.GenerateParamsPanel(confnode, bkgdclr, 8)
       
  1340         self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
       
  1341         
       
  1342         self.ConfNodeInfos[confnode]["left"] = leftwindow
       
  1343         self.ConfNodeInfos[confnode]["right"] = rightwindow
       
  1344         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1345             self.GenerateTreeBranch(child)
       
  1346             if not self.ConfNodeInfos[child]["expanded"]:
       
  1347                 self.CollapseConfNode(child)
       
  1348         
       
  1349         if len(confnode_locations) > 0:
       
  1350             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
       
  1351             treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, 
       
  1352                                    style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT)
       
  1353             treectrl.SetImageList(self.LocationImageList)
       
  1354             treectrl.Bind(wx.EVT_TREE_BEGIN_DRAG, self.GenerateLocationBeginDragFunction(locations_infos))
       
  1355             treectrl.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.GenerateLocationExpandCollapseFunction(locations_infos, True))
       
  1356             treectrl.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.GenerateLocationExpandCollapseFunction(locations_infos, False))
       
  1357             treectrl.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelTreeCtrl)
       
  1358             
       
  1359             treectrl.AddRoot("")
       
  1360             self.ConfNodeTreeSizer.AddWindow(treectrl, 0, border=0, flag=0)
       
  1361             
       
  1362             rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1363             rightwindow.SetBackgroundColour(wx.WHITE)
       
  1364             self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
       
  1365             
       
  1366             locations_infos["root"]["left"] = treectrl
       
  1367             locations_infos["root"]["right"] = rightwindow
       
  1368             for location in confnode_locations:
       
  1369                 locations_infos["root"]["children"].append("root.%s" % location["name"])
       
  1370                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
       
  1371             if locations_infos["root"]["expanded"]:
       
  1372                 self.ConfNodeTreeSizer.Layout()
       
  1373                 self.ExpandLocation(locations_infos, "root")
       
  1374             else:
       
  1375                 self.RefreshTreeCtrlSize(treectrl)
       
  1376     
       
  1377     def GenerateLocationTreeBranch(self, treectrl, root, locations_infos, parent, location):
       
  1378         location_name = "%s.%s" % (parent, location["name"])
       
  1379         if not locations_infos.has_key(location_name):
       
  1380             locations_infos[location_name] = {"expanded" : False}
       
  1381         
       
  1382         if location["type"] in [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]:
       
  1383             label = "%(name)s (%(location)s)" % location
       
  1384         elif location["location"] != "":
       
  1385             label = "%(location)s: %(name)s" % location
       
  1386         else:
       
  1387             label = location["name"]
       
  1388         item = treectrl.AppendItem(root, label)
       
  1389         treectrl.SetPyData(item, location_name)
       
  1390         treectrl.SetItemImage(item, self.LocationImageDict[location["type"]])
       
  1391         
       
  1392         locations_infos[location_name]["item"] = item
       
  1393         locations_infos[location_name]["children"] = []
       
  1394         infos = location.copy()
       
  1395         infos.pop("children")
       
  1396         locations_infos[location_name]["infos"] = infos
       
  1397         for child in location["children"]:
       
  1398             child_name = "%s.%s" % (location_name, child["name"])
       
  1399             locations_infos[location_name]["children"].append(child_name)
       
  1400             self.GenerateLocationTreeBranch(treectrl, item, locations_infos, location_name, child)
       
  1401         if locations_infos[location_name]["expanded"]:
       
  1402             self.ExpandLocation(locations_infos, location_name)
       
  1403     
       
  1404     def GenerateLocationBeginDragFunction(self, locations_infos):
       
  1405         def OnLocationBeginDragFunction(event):
       
  1406             item = event.GetItem()
       
  1407             location_name = locations_infos["root"]["left"].GetPyData(item)
       
  1408             if location_name is not None:
       
  1409                 infos = locations_infos[location_name]["infos"]
       
  1410                 if infos["type"] in [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]:
       
  1411                     data = wx.TextDataObject(str((infos["location"], "location", infos["IEC_type"], infos["var_name"], infos["description"])))
       
  1412                     dragSource = wx.DropSource(self)
       
  1413                     dragSource.SetData(data)
       
  1414                     dragSource.DoDragDrop()
       
  1415         return OnLocationBeginDragFunction
       
  1416     
       
  1417     def RefreshTreeCtrlSize(self, treectrl):
       
  1418         rect = self.GetTreeCtrlItemRect(treectrl, treectrl.GetRootItem())
       
  1419         treectrl.SetMinSize(wx.Size(max(rect.width, rect.x + rect.width) + 20, max(rect.height, rect.y + rect.height) + 20))
       
  1420         self.PLCConfigMainSizer.Layout()
       
  1421         self.PLCConfig.Refresh()
       
  1422         wx.CallAfter(self.RefreshScrollBars)
       
  1423     
       
  1424     def OnMouseWheelTreeCtrl(self, event):
       
  1425         x, y = self.PLCConfig.GetViewStart()
       
  1426         rotation = - (event.GetWheelRotation() / event.GetWheelDelta()) * 3
       
  1427         if event.ShiftDown():
       
  1428             self.PLCConfig.Scroll(x + rotation, y)
       
  1429         else:
       
  1430             self.PLCConfig.Scroll(x, y + rotation)
       
  1431     
       
  1432     def GetTreeCtrlItemRect(self, treectrl, item):
       
  1433         item_rect = treectrl.GetBoundingRect(item, True)
       
  1434         if item_rect is not None:
       
  1435             minx, miny = item_rect.x, item_rect.y
       
  1436             maxx, maxy = item_rect.x + item_rect.width, item_rect.y + item_rect.height
       
  1437         else:
       
  1438             minx = miny = maxx = maxy = 0
       
  1439         
       
  1440         if treectrl.ItemHasChildren(item) and (item == treectrl.GetRootItem() or treectrl.IsExpanded(item)):
       
  1441             if wx.VERSION >= (2, 6, 0):
       
  1442                 child, item_cookie = treectrl.GetFirstChild(item)
       
  1443             else:
       
  1444                 child, item_cookie = treectrl.GetFirstChild(item, 0)
       
  1445             while child.IsOk():
       
  1446                 child_rect = self.GetTreeCtrlItemRect(treectrl, child)
       
  1447                 minx = min(minx, child_rect.x)
       
  1448                 miny = min(miny, child_rect.y)
       
  1449                 maxx = max(maxx, child_rect.x + child_rect.width)
       
  1450                 maxy = max(maxy, child_rect.y + child_rect.height)
       
  1451                 child, item_cookie = treectrl.GetNextChild(item, item_cookie)
       
  1452                 
       
  1453         return wx.Rect(minx, miny, maxx - minx, maxy - miny)
       
  1454     
       
  1455     def GenerateLocationExpandCollapseFunction(self, locations_infos, expand):
       
  1456         def OnLocationExpandedFunction(event):
       
  1457             item = event.GetItem()
       
  1458             location_name = locations_infos["root"]["left"].GetPyData(item)
       
  1459             if location_name is not None:
       
  1460                 locations_infos[location_name]["expanded"] = expand
       
  1461                 self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1462             event.Skip()
       
  1463         return OnLocationExpandedFunction
       
  1464     
       
  1465     def RefreshAll(self):
   734     def RefreshAll(self):
  1466         self.RefreshPLCParams()
   735         self.RefreshStatusToolBar()
  1467         self.RefreshConfNodeTree()
       
  1468         
       
  1469     def GetItemChannelChangedFunction(self, confnode, value):
       
  1470         def OnConfNodeTreeItemChannelChanged(event):
       
  1471             res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.IEC_Channel", value)
       
  1472             event.Skip()
       
  1473         return OnConfNodeTreeItemChannelChanged
       
  1474     
   736     
  1475     def _GetAddConfNodeFunction(self, name, confnode=None):
   737     def _GetAddConfNodeFunction(self, name, confnode=None):
  1476         def OnConfNodeMenu(event):
   738         def OnConfNodeMenu(event):
  1477             wx.CallAfter(self.AddConfNode, name, confnode)
   739             wx.CallAfter(self.AddConfNode, name, confnode)
  1478         return OnConfNodeMenu
   740         return OnConfNodeMenu
  1479     
       
  1480     def Gen_AddConfNodeMenu(self, confnode):
       
  1481         def AddConfNodeMenu(event):
       
  1482             main_menu = wx.Menu(title='')
       
  1483             if len(confnode.CTNChildrenTypes) > 0:
       
  1484                 for name, XSDClass, help in confnode.CTNChildrenTypes:
       
  1485                     new_id = wx.NewId()
       
  1486                     main_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Append ")+help)
       
  1487                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
       
  1488             self.PopupMenuXY(main_menu)
       
  1489             main_menu.Destroy()
       
  1490         return AddConfNodeMenu
       
  1491     
   741     
  1492     def GetMenuCallBackFunction(self, method):
   742     def GetMenuCallBackFunction(self, method):
  1493         """ Generate the callbackfunc for a given CTR method"""
   743         """ Generate the callbackfunc for a given CTR method"""
  1494         def OnMenu(event):
   744         def OnMenu(event):
  1495             # Disable button to prevent re-entrant call 
   745             # Disable button to prevent re-entrant call 
  1499             # Re-enable button 
   749             # Re-enable button 
  1500             event.GetEventObject().Enable()
   750             event.GetEventObject().Enable()
  1501             # Trigger refresh on Idle
   751             # Trigger refresh on Idle
  1502             wx.CallAfter(self.RefreshStatusToolBar)
   752             wx.CallAfter(self.RefreshStatusToolBar)
  1503         return OnMenu
   753         return OnMenu
  1504     
       
  1505     def GetButtonCallBackFunction(self, confnode, method):
       
  1506         """ Generate the callbackfunc for a given confnode method"""
       
  1507         def OnButtonClick(event):
       
  1508             # Disable button to prevent re-entrant call 
       
  1509             event.GetEventObject().Disable()
       
  1510             # Call
       
  1511             getattr(confnode,method)()
       
  1512             # Re-enable button 
       
  1513             event.GetEventObject().Enable()
       
  1514             # Trigger refresh on Idle
       
  1515             wx.CallAfter(self.RefreshAll)
       
  1516             event.Skip()
       
  1517         return OnButtonClick
       
  1518     
       
  1519     def GetChoiceCallBackFunction(self, choicectrl, confnode, path):
       
  1520         def OnChoiceChanged(event):
       
  1521             res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection())
       
  1522             choicectrl.SetStringSelection(res)
       
  1523             event.Skip()
       
  1524         return OnChoiceChanged
       
  1525     
       
  1526     def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, confnode, path):
       
  1527         def OnChoiceContentChanged(event):
       
  1528             res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection())
       
  1529             if wx.VERSION < (2, 8, 0):
       
  1530                 self.ParamsPanel.Freeze()
       
  1531                 choicectrl.SetStringSelection(res)
       
  1532                 infos = self.CTR.GetParamsAttributes(path)
       
  1533                 staticbox = staticboxsizer.GetStaticBox()
       
  1534                 staticbox.SetLabel("%(name)s - %(value)s"%infos)
       
  1535                 self.RefreshSizerElement(self.ParamsPanel, staticboxsizer, infos["children"], "%s.%s"%(path, infos["name"]), selected=selected)
       
  1536                 self.ParamsPanelMainSizer.Layout()
       
  1537                 self.ParamsPanel.Thaw()
       
  1538                 self.ParamsPanel.Refresh()
       
  1539             else:
       
  1540                 wx.CallAfter(self.RefreshAll)
       
  1541             event.Skip()
       
  1542         return OnChoiceContentChanged
       
  1543     
       
  1544     def GetTextCtrlCallBackFunction(self, textctrl, confnode, path):
       
  1545         def OnTextCtrlChanged(event):
       
  1546             res = self.SetConfNodeParamsAttribute(confnode, path, textctrl.GetValue())
       
  1547             if res != textctrl.GetValue():
       
  1548                 textctrl.ChangeValue(res)
       
  1549             event.Skip()
       
  1550         return OnTextCtrlChanged
       
  1551     
       
  1552     def GetCheckBoxCallBackFunction(self, chkbx, confnode, path):
       
  1553         def OnCheckBoxChanged(event):
       
  1554             res = self.SetConfNodeParamsAttribute(confnode, path, chkbx.IsChecked())
       
  1555             chkbx.SetValue(res)
       
  1556             event.Skip()
       
  1557         return OnCheckBoxChanged
       
  1558     
       
  1559     def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, confnode, path):
       
  1560         infos = [value_infos]
       
  1561         def OnBrowseButton(event):
       
  1562             dialog = BrowseValuesLibraryDialog(self, name, library, infos[0])
       
  1563             if dialog.ShowModal() == wx.ID_OK:
       
  1564                 value, value_infos = self.SetConfNodeParamsAttribute(confnode, path, dialog.GetValueInfos())
       
  1565                 textctrl.ChangeValue(value)
       
  1566                 infos[0] = value_infos
       
  1567             dialog.Destroy()
       
  1568             event.Skip()
       
  1569         return OnBrowseButton
       
  1570     
       
  1571     def ClearSizer(self, sizer):
       
  1572         staticboxes = []
       
  1573         for item in sizer.GetChildren():
       
  1574             if item.IsSizer():
       
  1575                 item_sizer = item.GetSizer()
       
  1576                 self.ClearSizer(item_sizer)
       
  1577                 if isinstance(item_sizer, wx.StaticBoxSizer):
       
  1578                     staticboxes.append(item_sizer.GetStaticBox())
       
  1579         sizer.Clear(True)
       
  1580         for staticbox in staticboxes:
       
  1581             staticbox.Destroy()
       
  1582                 
       
  1583     def RefreshSizerElement(self, parent, sizer, confnode, elements, path, clean = True):
       
  1584         if clean:
       
  1585             if wx.VERSION < (2, 8, 0):
       
  1586                 self.ClearSizer(sizer)
       
  1587             else:
       
  1588                 sizer.Clear(True)
       
  1589         first = True
       
  1590         for element_infos in elements:
       
  1591             if path:
       
  1592                 element_path = "%s.%s"%(path, element_infos["name"])
       
  1593             else:
       
  1594                 element_path = element_infos["name"]
       
  1595             if element_infos["type"] == "element":
       
  1596                 label = element_infos["name"]
       
  1597                 staticbox = wx.StaticBox(id=-1, label=_(label), 
       
  1598                     name='%s_staticbox'%element_infos["name"], parent=parent,
       
  1599                     pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0)
       
  1600                 staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
       
  1601                 if first:
       
  1602                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW|wx.TOP)
       
  1603                 else:
       
  1604                     sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW)
       
  1605                 self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path)
       
  1606             else:
       
  1607                 boxsizer = wx.FlexGridSizer(cols=3, rows=1)
       
  1608                 boxsizer.AddGrowableCol(1)
       
  1609                 if first:
       
  1610                     sizer.AddSizer(boxsizer, 0, border=5, flag=wx.GROW|wx.ALL)
       
  1611                 else:
       
  1612                     sizer.AddSizer(boxsizer, 0, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
       
  1613                 staticbitmap = GenStaticBitmap(ID=-1, bitmapname="%s.png"%element_infos["name"],
       
  1614                     name="%s_bitmap"%element_infos["name"], parent=parent,
       
  1615                     pos=wx.Point(0, 0), size=wx.Size(24, 24), style=0)
       
  1616                 boxsizer.AddWindow(staticbitmap, 0, border=5, flag=wx.RIGHT)
       
  1617                 label = element_infos["name"]
       
  1618                 statictext = wx.StaticText(id=-1, label="%s:"%_(label), 
       
  1619                     name="%s_label"%element_infos["name"], parent=parent, 
       
  1620                     pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
  1621                 boxsizer.AddWindow(statictext, 0, border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT)
       
  1622                 id = wx.NewId()
       
  1623                 if isinstance(element_infos["type"], types.ListType):
       
  1624                     if isinstance(element_infos["value"], types.TupleType):
       
  1625                         browse_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1626                         boxsizer.AddSizer(browse_boxsizer, 0, border=0, flag=0)
       
  1627                         
       
  1628                         textctrl = wx.TextCtrl(id=id, name=element_infos["name"], parent=parent, 
       
  1629                             pos=wx.Point(0, 0), size=wx.Size(275, 25), style=wx.TE_READONLY)
       
  1630                         if element_infos["value"] is not None:
       
  1631                             textctrl.SetValue(element_infos["value"][0])
       
  1632                             value_infos = element_infos["value"][1]
       
  1633                         else:
       
  1634                             value_infos = None
       
  1635                         browse_boxsizer.AddWindow(textctrl, 0, border=0, flag=0)
       
  1636                         button_id = wx.NewId()
       
  1637                         button = wx.Button(id=button_id, name="browse_%s" % element_infos["name"], parent=parent, 
       
  1638                             label="...", pos=wx.Point(0, 0), size=wx.Size(25, 25))
       
  1639                         browse_boxsizer.AddWindow(button, 0, border=0, flag=0)
       
  1640                         button.Bind(wx.EVT_BUTTON, 
       
  1641                                     self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], 
       
  1642                                                                    value_infos, confnode, element_path), 
       
  1643                                     id=button_id)
       
  1644                     else:
       
  1645                         combobox = wx.ComboBox(id=id, name=element_infos["name"], parent=parent, 
       
  1646                             pos=wx.Point(0, 0), size=wx.Size(300, 28), style=wx.CB_READONLY)
       
  1647                         boxsizer.AddWindow(combobox, 0, border=0, flag=0)
       
  1648                         if element_infos["use"] == "optional":
       
  1649                             combobox.Append("")
       
  1650                         if len(element_infos["type"]) > 0 and isinstance(element_infos["type"][0], types.TupleType):
       
  1651                             for choice, xsdclass in element_infos["type"]:
       
  1652                                 combobox.Append(choice)
       
  1653                             name = element_infos["name"]
       
  1654                             value = element_infos["value"]
       
  1655                             staticbox = wx.StaticBox(id=-1, label="%s - %s"%(_(name), _(value)), 
       
  1656                                 name='%s_staticbox'%element_infos["name"], parent=parent,
       
  1657                                 pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0)
       
  1658                             staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
       
  1659                             sizer.AddSizer(staticboxsizer, 0, border=5, flag=wx.GROW|wx.BOTTOM)
       
  1660                             self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path)
       
  1661                             callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, confnode, element_path)
       
  1662                         else:
       
  1663                             for choice in element_infos["type"]:
       
  1664                                 combobox.Append(choice)
       
  1665                             callback = self.GetChoiceCallBackFunction(combobox, confnode, element_path)
       
  1666                         if element_infos["value"] is None:
       
  1667                             combobox.SetStringSelection("")
       
  1668                         else:
       
  1669                             combobox.SetStringSelection(element_infos["value"])
       
  1670                         combobox.Bind(wx.EVT_COMBOBOX, callback, id=id)
       
  1671                 elif isinstance(element_infos["type"], types.DictType):
       
  1672                     scmin = -(2**31)
       
  1673                     scmax = 2**31-1
       
  1674                     if "min" in element_infos["type"]:
       
  1675                         scmin = element_infos["type"]["min"]
       
  1676                     if "max" in element_infos["type"]:
       
  1677                         scmax = element_infos["type"]["max"]
       
  1678                     spinctrl = wx.SpinCtrl(id=id, name=element_infos["name"], parent=parent, 
       
  1679                         pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
       
  1680                     spinctrl.SetRange(scmin,scmax)
       
  1681                     boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
       
  1682                     if element_infos["value"] is not None:
       
  1683                         spinctrl.SetValue(element_infos["value"])
       
  1684                     spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id)
       
  1685                 else:
       
  1686                     if element_infos["type"] == "boolean":
       
  1687                         checkbox = wx.CheckBox(id=id, name=element_infos["name"], parent=parent, 
       
  1688                             pos=wx.Point(0, 0), size=wx.Size(17, 25), style=0)
       
  1689                         boxsizer.AddWindow(checkbox, 0, border=0, flag=0)
       
  1690                         if element_infos["value"] is not None:
       
  1691                             checkbox.SetValue(element_infos["value"])
       
  1692                         checkbox.Bind(wx.EVT_CHECKBOX, self.GetCheckBoxCallBackFunction(checkbox, confnode, element_path), id=id)
       
  1693                     elif element_infos["type"] in ["unsignedLong", "long","integer"]:
       
  1694                         if element_infos["type"].startswith("unsigned"):
       
  1695                             scmin = 0
       
  1696                         else:
       
  1697                             scmin = -(2**31)
       
  1698                         scmax = 2**31-1
       
  1699                         spinctrl = wx.SpinCtrl(id=id, name=element_infos["name"], parent=parent, 
       
  1700                             pos=wx.Point(0, 0), size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
       
  1701                         spinctrl.SetRange(scmin, scmax)
       
  1702                         boxsizer.AddWindow(spinctrl, 0, border=0, flag=0)
       
  1703                         if element_infos["value"] is not None:
       
  1704                             spinctrl.SetValue(element_infos["value"])
       
  1705                         spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id)
       
  1706                     else:
       
  1707                         choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""]))))
       
  1708                         textctrl = TextCtrlAutoComplete(id=id, 
       
  1709                                                                      name=element_infos["name"], 
       
  1710                                                                      parent=parent, 
       
  1711                                                                      appframe=self, 
       
  1712                                                                      choices=choices, 
       
  1713                                                                      element_path=element_path,
       
  1714                                                                      pos=wx.Point(0, 0), 
       
  1715                                                                      size=wx.Size(300, 25), 
       
  1716                                                                      style=0)
       
  1717                         
       
  1718                         boxsizer.AddWindow(textctrl, 0, border=0, flag=0)
       
  1719                         if element_infos["value"] is not None:
       
  1720                             textctrl.ChangeValue(str(element_infos["value"]))
       
  1721                         textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, confnode, element_path))
       
  1722             first = False
       
  1723     
   754     
  1724     def GetConfigEntry(self, entry_name, default):
   755     def GetConfigEntry(self, entry_name, default):
  1725         return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default))))
   756         return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default))))
  1726     
   757     
  1727     def ResetView(self):
   758     def ResetView(self):
  1775                 self.PouInstanceVariablesPanel.SetController(self.Controler)
   806                 self.PouInstanceVariablesPanel.SetController(self.Controler)
  1776                 self.RefreshConfigRecentProjects(projectpath)
   807                 self.RefreshConfigRecentProjects(projectpath)
  1777                 if self.EnableDebug:
   808                 if self.EnableDebug:
  1778                     self.DebugVariablePanel.SetDataProducer(self.CTR)
   809                     self.DebugVariablePanel.SetDataProducer(self.CTR)
  1779                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   810                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
  1780                 self.RefreshStatusToolBar()
       
  1781             else:
   811             else:
  1782                 self.ResetView()
   812                 self.ResetView()
  1783                 self.ShowErrorMessage(result)
   813                 self.ShowErrorMessage(result)
       
   814             self.RefreshAll()
  1784             self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
   815             self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1785         dialog.Destroy()
   816         dialog.Destroy()
  1786     
   817     
  1787     def OnOpenProjectMenu(self, event):
   818     def OnOpenProjectMenu(self, event):
  1788         if self.CTR is not None and not self.CheckSaveBeforeClosing():
   819         if self.CTR is not None and not self.CheckSaveBeforeClosing():
  1813                 self.RefreshConfigRecentProjects(projectpath)
   844                 self.RefreshConfigRecentProjects(projectpath)
  1814                 if self.EnableDebug:
   845                 if self.EnableDebug:
  1815                     self.DebugVariablePanel.SetDataProducer(self.CTR)
   846                     self.DebugVariablePanel.SetDataProducer(self.CTR)
  1816                 self.LoadProjectLayout()
   847                 self.LoadProjectLayout()
  1817                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
   848                 self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
  1818                 self.RefreshStatusToolBar()
       
  1819             else:
   849             else:
  1820                 self.ResetView()
   850                 self.ResetView()
  1821                 self.ShowErrorMessage(result)
   851                 self.ShowErrorMessage(result)
       
   852             self.RefreshAll()
  1822         else:
   853         else:
  1823             self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
   854             self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
  1824         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
   855         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1825     
   856     
  1826     def OnCloseProjectMenu(self, event):
   857     def OnCloseProjectMenu(self, event):
  1828             return
   859             return
  1829         
   860         
  1830         self.SaveProjectLayout()
   861         self.SaveProjectLayout()
  1831         self.ResetView()
   862         self.ResetView()
  1832         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
   863         self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
  1833         self.RefreshStatusToolBar()
   864         self.RefreshAll()
  1834     
   865     
  1835     def OnSaveProjectMenu(self, event):
   866     def OnSaveProjectMenu(self, event):
  1836         if self.CTR is not None:
   867         if self.CTR is not None:
  1837             self.CTR.SaveProject()
   868             self.CTR.SaveProject()
  1838             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
   869             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1840     def OnSaveProjectAsMenu(self, event):
   871     def OnSaveProjectAsMenu(self, event):
  1841         if self.CTR is not None:
   872         if self.CTR is not None:
  1842             self.CTR.SaveProjectAs()
   873             self.CTR.SaveProjectAs()
  1843             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
   874             self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
  1844         event.Skip()
   875         event.Skip()
  1845     
       
  1846     def OnPropertiesMenu(self, event):
       
  1847         self.EditProjectSettings()
       
  1848     
   876     
  1849     def OnQuitMenu(self, event):
   877     def OnQuitMenu(self, event):
  1850         self.Close()
   878         self.Close()
  1851         
   879         
  1852     def OnAboutMenu(self, event):
   880     def OnAboutMenu(self, event):
  1884                     confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name)
   912                     confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name)
  1885                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
   913                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
  1886 
   914 
  1887             new_id = wx.NewId()
   915             new_id = wx.NewId()
  1888             AppendMenu(confnode_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
   916             AppendMenu(confnode_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
  1889             self.Bind(wx.EVT_MENU, self.GetDeleteButtonFunction(confnode), id=new_id)
   917             self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), id=new_id)
  1890                 
   918                 
  1891             self.PopupMenu(confnode_menu)
   919             self.PopupMenu(confnode_menu)
  1892             confnode_menu.Destroy()
   920             confnode_menu.Destroy()
  1893             
   921             
  1894             event.Skip()
   922             event.Skip()
  1923                 elif words[0] == "R":
   951                 elif words[0] == "R":
  1924                     return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)])
   952                     return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)])
  1925                 else:
   953                 else:
  1926                     IDEFrame.SelectProjectTreeItem(self, tagname)
   954                     IDEFrame.SelectProjectTreeItem(self, tagname)
  1927             
   955             
  1928     def GetAddButtonFunction(self, confnode, window):
   956     def GetDeleteMenuFunction(self, confnode):
  1929         def AddButtonFunction(event):
   957         def DeleteMenuFunction(event):
  1930             if confnode and len(confnode.CTNChildrenTypes) > 0:
       
  1931                 confnode_menu = wx.Menu(title='')
       
  1932                 for name, XSDClass, help in confnode.CTNChildrenTypes:
       
  1933                     new_id = wx.NewId()
       
  1934                     confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name)
       
  1935                     self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id)
       
  1936                 window_pos = window.GetPosition()
       
  1937                 wx.CallAfter(self.PLCConfig.PopupMenu, confnode_menu)
       
  1938             event.Skip()
       
  1939         return AddButtonFunction
       
  1940     
       
  1941     def GetDeleteButtonFunction(self, confnode):
       
  1942         def DeleteButtonFunction(event):
       
  1943             wx.CallAfter(self.DeleteConfNode, confnode)
   958             wx.CallAfter(self.DeleteConfNode, confnode)
  1944             event.Skip()
   959         return DeleteMenuFunction
  1945         return DeleteButtonFunction
       
  1946     
   960     
  1947     def AddConfNode(self, ConfNodeType, confnode=None):
   961     def AddConfNode(self, ConfNodeType, confnode=None):
  1948         if self.CTR.CheckProjectPathPerm():
   962         if self.CTR.CheckProjectPathPerm():
  1949             dialog = wx.TextEntryDialog(self, _("Please enter a name for confnode:"), _("Add ConfNode"), "", wx.OK|wx.CANCEL)
   963             dialog = wx.TextEntryDialog(self, _("Please enter a name for confnode:"), _("Add ConfNode"), "", wx.OK|wx.CANCEL)
  1950             if dialog.ShowModal() == wx.ID_OK:
   964             if dialog.ShowModal() == wx.ID_OK:
  1951                 ConfNodeName = dialog.GetValue()
   965                 ConfNodeName = dialog.GetValue()
  1952                 if confnode is not None:
   966                 if confnode is not None:
  1953                     confnode.CTNAddChild(ConfNodeName, ConfNodeType)
   967                     confnode.CTNAddChild(ConfNodeName, ConfNodeType)
  1954                 else:
   968                 else:
  1955                     self.CTR.CTNAddChild(ConfNodeName, ConfNodeType)
   969                     self.CTR.CTNAddChild(ConfNodeName, ConfNodeType)
  1956                 self.CTR.RefreshConfNodesBlockLists()
       
  1957                 self._Refresh(TITLE, FILEMENU, PROJECTTREE)
   970                 self._Refresh(TITLE, FILEMENU, PROJECTTREE)
  1958                 self.RefreshConfNodeTree()
       
  1959             dialog.Destroy()
   971             dialog.Destroy()
  1960     
   972     
  1961     def DeleteConfNode(self, confnode):
   973     def DeleteConfNode(self, confnode):
  1962         if self.CTR.CheckProjectPathPerm():
   974         if self.CTR.CheckProjectPathPerm():
  1963             dialog = wx.MessageDialog(self, _("Really delete confnode ?"), _("Remove confnode"), wx.YES_NO|wx.NO_DEFAULT)
   975             dialog = wx.MessageDialog(self, _("Really delete confnode ?"), _("Remove confnode"), wx.YES_NO|wx.NO_DEFAULT)
  1964             if dialog.ShowModal() == wx.ID_YES:
   976             if dialog.ShowModal() == wx.ID_YES:
  1965                 self.ConfNodeInfos.pop(confnode)
       
  1966                 confnode.CTNRemove()
   977                 confnode.CTNRemove()
  1967                 del confnode
   978                 del confnode
  1968                 self.CTR.RefreshConfNodesBlockLists()
       
  1969                 self._Refresh(TITLE, FILEMENU, PROJECTTREE)
   979                 self._Refresh(TITLE, FILEMENU, PROJECTTREE)
  1970                 self.RefreshConfNodeTree()
       
  1971             dialog.Destroy()
   980             dialog.Destroy()
  1972     
   981     
  1973 #-------------------------------------------------------------------------------
   982 #-------------------------------------------------------------------------------
  1974 #                               Exception Handler
   983 #                               Exception Handler
  1975 #-------------------------------------------------------------------------------
   984 #-------------------------------------------------------------------------------