--- a/Beremiz.py Tue Jan 31 00:41:46 2012 +0100
+++ b/Beremiz.py Tue Jan 31 23:28:03 2012 +0100
@@ -32,6 +32,7 @@
+from types import ListType CWD = os.path.split(os.path.realpath(__file__))[0]
@@ -172,6 +173,8 @@
+MAX_RECENT_PROJECTS = 10 # Some helpers to tweak GenBitmapTextButtons
# TODO: declare customized classes instead.
gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
@@ -327,13 +330,32 @@
ID_BEREMIZPLCCONFIG, ID_BEREMIZLOGCONSOLE,
ID_BEREMIZINSPECTOR] = [wx.NewId() for _init_ctrls in range(5)]
+[ID_FILEMENURECENTPROJECTS, +] = [wx.NewId() for _init_ctrls in range(1)] + def _init_coll_MenuBar_Menus(self, parent): + IDEFrame._init_coll_MenuBar_Menus(self, parent) + parent.Insert(pos=PLUGINMENU_POSITION, + menu=self.PluginMenu, title=_(u'&Plugin')) + self.PluginMenu = wx.Menu(title='') + self.RecentProjectsMenu = wx.Menu(title='') + IDEFrame._init_utils(self) def _init_coll_FileMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_NEW,
kind=wx.ITEM_NORMAL, text=_(u'New\tCTRL+N'))
AppendMenu(parent, help='', id=wx.ID_OPEN,
kind=wx.ITEM_NORMAL, text=_(u'Open\tCTRL+O'))
+ parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("Recent Projects"), self.RecentProjectsMenu) + parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_SAVE,
kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
AppendMenu(parent, help='', id=wx.ID_SAVEAS,
@@ -453,6 +475,8 @@
# Variable allowing disabling of PLCConfig scroll when Popup shown
self.ScrollingEnabled = True
+ self.LastPanelSelected = None # Define Tree item icon list
@@ -494,6 +518,7 @@
self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
+ self.RefreshPluginMenu() self.LogConsole.SetFocus()
def RiseLogConsole(self):
@@ -610,6 +635,8 @@
def RefreshFileMenu(self):
+ self.RefreshRecentProjectsMenu() if self.PluginRoot is not None:
selected = self.TabsOpened.GetSelection()
@@ -642,7 +669,67 @@
self.FileMenu.Enable(wx.ID_SAVEAS, False)
self.FileMenu.Enable(wx.ID_PROPERTIES, False)
self.FileMenu.Enable(wx.ID_CLOSE_ALL, False)
+ def RefreshRecentProjectsMenu(self): + for i in xrange(self.RecentProjectsMenu.GetMenuItemCount()): + item = self.RecentProjectsMenu.FindItemByPosition(0) + self.RecentProjectsMenu.Delete(item.GetId()) + recent_projects = cPickle.loads(str(self.Config.Read("RecentProjects", cPickle.dumps([])))) + self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) + for idx, projectpath in enumerate(recent_projects): + AppendMenu(self.RecentProjectsMenu, help='', id=id, + kind=wx.ITEM_NORMAL, text="%d: %s" % (idx + 1, projectpath)) + self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id) + def GenerateOpenRecentProjectFunction(self, projectpath): + def OpenRecentProject(event): + if self.PluginRoot is not None and not self.CheckSaveBeforeClosing(): + self.OpenProject(projectpath) + return OpenRecentProject + def GenerateMenuRecursive(self, items, menu): + for kind, infos in items: + if isinstance(kind, ListType): + self.GenerateMenuRecursive(kind, submenu) + menu.AppendMenu(id, text, submenu) + elif kind == wx.ITEM_SEPARATOR: + text, id, help, callback = infos + AppendMenu(menu, help='', id=id, kind=kind, text=text) + if callback is not None: + self.Bind(wx.EVT_MENU, callback, id=id) + def RefreshPluginMenu(self): + if self.PluginRoot is not None: + selected = self.TabsOpened.GetSelection() + panel = self.TabsOpened.GetPage(selected) + if panel != self.LastPanelSelected: + for i in xrange(self.PluginMenu.GetMenuItemCount()): + item = self.PluginMenu.FindItemByPosition(0) + self.PluginMenu.Delete(item.GetId()) + self.LastPanelSelected = panel + items = panel.GetPluginMenuItems() + self.MenuBar.EnableTop(PLUGINMENU_POSITION, len(items) > 0) + self.GenerateMenuRecursive(items, self.PluginMenu) + panel.RefreshPluginMenu(self.PluginMenu) + self.MenuBar.EnableTop(PLUGINMENU_POSITION, False) + self.MenuBar.UpdateMenus() def RefreshScrollBars(self):
xstart, ystart = self.PLCConfig.GetViewStart()
window_size = self.PLCConfig.GetClientSize()
@@ -741,6 +828,25 @@
+ def GenerateEnableButton(self, parent, sizer, plugin): + enabled = plugin.PlugEnabled() + if enabled is not None: + enablebutton_id = wx.NewId() + enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')), + name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER) + enablebutton.SetToolTipString(_("Enable/Disable this plugin")) + make_genbitmaptogglebutton_flat(enablebutton) + enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png'))) + enablebutton.SetToggle(enabled) + def toggleenablebutton(event): + res = self.SetPluginParamsAttribute(plugin, "BaseParams.Enabled", enablebutton.GetToggle()) + enablebutton.SetToggle(res) + enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id) + sizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) + sizer.AddSpacer(wx.Size(16, 16)) def GenerateMethodButtonSizer(self, plugin, parent, horizontal = True):
normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
@@ -773,6 +879,65 @@
msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER)
+ def GenerateParamsPanel(self, plugin, bkgdclr): + rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) + rightwindow.SetBackgroundColour(bkgdclr) + rightwindowmainsizer = wx.BoxSizer(wx.VERTICAL) + rightwindow.SetSizer(rightwindowmainsizer) + rightwindowsizer = wx.FlexGridSizer(cols=2, rows=1) + rightwindowsizer.AddGrowableCol(1) + rightwindowsizer.AddGrowableRow(0) + rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=0, flag=wx.GROW) + msizer = self.GenerateMethodButtonSizer(plugin, rightwindow, not self.PluginInfos[plugin]["right_visible"]) + rightwindowsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW) + rightparamssizer = wx.BoxSizer(wx.HORIZONTAL) + rightwindowsizer.AddSizer(rightparamssizer, 0, border=0, flag=wx.ALIGN_RIGHT) + paramswindow = wx.Panel(rightwindow, -1, size=wx.Size(-1, -1)) + paramswindow.SetBackgroundColour(bkgdclr) + psizer = wx.BoxSizer(wx.HORIZONTAL) + paramswindow.SetSizer(psizer) + self.PluginInfos[plugin]["params"] = paramswindow + rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL) + plugin_infos = plugin.GetParamsAttributes() + if len(plugin_infos) > 0: + self.RefreshSizerElement(paramswindow, psizer, plugin, plugin_infos, None, False) + if not self.PluginInfos[plugin]["right_visible"]: + rightminimizebutton_id = wx.NewId() + rightminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=rightminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')), + name='MinimizeButton', parent=rightwindow, pos=wx.Point(0, 0), + size=wx.Size(24, 24), style=wx.NO_BORDER) + make_genbitmaptogglebutton_flat(rightminimizebutton) + rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png'))) + rightminimizebutton.SetToggle(self.PluginInfos[plugin]["right_visible"]) + rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL) + def togglerightwindow(event): + if rightminimizebutton.GetToggle(): + rightparamssizer.Show(0) + rightparamssizer.Hide(0) + msizer.SetCols(len(plugin.PluginMethods)) + self.PluginInfos[plugin]["right_visible"] = rightminimizebutton.GetToggle() + self.PLCConfigMainSizer.Layout() + self.RefreshScrollBars() + rightminimizebutton.Bind(wx.EVT_BUTTON, togglerightwindow, id=rightminimizebutton_id) def RefreshPluginTree(self):
self.ClearSizer(self.PluginTreeSizer)
@@ -859,7 +1024,7 @@
self.CollapseLocation(locations_infos, child, force, False)
if locations_infos["root"]["left"] is not None and refresh_size:
self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
def GenerateTreeBranch(self, plugin):
leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
if plugin.PlugTestModified():
@@ -901,20 +1066,8 @@
rolesizer = wx.BoxSizer(wx.HORIZONTAL)
leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
- enablebutton_id = wx.NewId()
- enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')),
- name='EnableButton', parent=leftwindow, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
- enablebutton.SetToolTipString(_("Enable/Disable this plugin"))
- make_genbitmaptogglebutton_flat(enablebutton)
- enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png')))
- enablebutton.SetToggle(plugin.MandatoryParams[1].getEnabled())
- def toggleenablebutton(event):
- res = self.SetPluginParamsAttribute(plugin, "BaseParams.Enabled", enablebutton.GetToggle())
- enablebutton.SetToggle(res)
- enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
- rolesizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+ self.GenerateEnableButton(leftwindow, rolesizer, plugin) roletext = wx.StaticText(leftwindow, -1)
roletext.SetLabel(plugin.PlugHelp)
@@ -1013,62 +1166,9 @@
tc.ChangeValue(plugin.MandatoryParams[1].getName())
tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, plugin, "BaseParams.Name"), id=tc_id)
iecsizer.AddWindow(tc, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
- rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
- rightwindow.SetBackgroundColour(bkgdclr)
- self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
- rightwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
- rightwindow.SetSizer(rightwindowmainsizer)
- rightwindowsizer = wx.FlexGridSizer(cols=2, rows=1)
- rightwindowsizer.AddGrowableCol(1)
- rightwindowsizer.AddGrowableRow(0)
- rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=8, flag=wx.TOP|wx.GROW)
- msizer = self.GenerateMethodButtonSizer(plugin, rightwindow, not self.PluginInfos[plugin]["right_visible"])
- rightwindowsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
- rightparamssizer = wx.BoxSizer(wx.HORIZONTAL)
- rightwindowsizer.AddSizer(rightparamssizer, 0, border=0, flag=wx.ALIGN_RIGHT)
- paramswindow = wx.Panel(rightwindow, -1, size=wx.Size(-1, -1))
- paramswindow.SetBackgroundColour(bkgdclr)
- psizer = wx.BoxSizer(wx.HORIZONTAL)
- paramswindow.SetSizer(psizer)
- self.PluginInfos[plugin]["params"] = paramswindow
- rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL)
- plugin_infos = plugin.GetParamsAttributes()
- self.RefreshSizerElement(paramswindow, psizer, plugin, plugin_infos, None, False)
- if not self.PluginInfos[plugin]["right_visible"]:
- rightminimizebutton_id = wx.NewId()
- rightminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=rightminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')),
- name='MinimizeButton', parent=rightwindow, pos=wx.Point(0, 0),
- size=wx.Size(24, 24), style=wx.NO_BORDER)
- make_genbitmaptogglebutton_flat(rightminimizebutton)
- rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png')))
- rightminimizebutton.SetToggle(self.PluginInfos[plugin]["right_visible"])
- rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL)
- def togglerightwindow(event):
- if rightminimizebutton.GetToggle():
- rightparamssizer.Show(0)
- rightparamssizer.Hide(0)
- msizer.SetCols(len(plugin.PluginMethods))
- self.PluginInfos[plugin]["right_visible"] = rightminimizebutton.GetToggle()
- self.PLCConfigMainSizer.Layout()
- self.RefreshScrollBars()
- rightminimizebutton.Bind(wx.EVT_BUTTON, togglerightwindow, id=rightminimizebutton_id)
+ rightwindow = self.GenerateParamsPanel(plugin, bkgdclr) + self.PluginTreeSizer.AddWindow(rightwindow, 0, border=8, flag=wx.TOP|wx.GROW) self.PluginInfos[plugin]["left"] = leftwindow
self.PluginInfos[plugin]["right"] = rightwindow
@@ -1385,7 +1485,7 @@
spinctrl.SetValue(element_infos["value"])
spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id)
- choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""]))))
+ choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""])))) textctrl = TextCtrlAutoComplete.TextCtrlAutoComplete(id=id,
name=element_infos["name"],
@@ -1451,26 +1551,33 @@
dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, wx.DD_NEW_DIR_BUTTON)
if dialog.ShowModal() == wx.ID_OK:
- projectpath = dialog.GetPath()
- if os.path.isdir(projectpath):
- self.Config.Write("lastopenedfolder", os.path.dirname(projectpath))
+ self.OpenProject(dialog.GetPath()) + def OpenProject(self, projectpath): + if os.path.isdir(projectpath): + self.Config.Write("lastopenedfolder", os.path.dirname(projectpath)) + recent_projects = cPickle.loads(str(self.Config.Read("RecentProjects", cPickle.dumps([])))) + if projectpath in recent_projects: + recent_projects.remove(projectpath) + recent_projects.insert(0, projectpath) + self.Config.Write("RecentProjects", cPickle.dumps(recent_projects[:MAX_RECENT_PROJECTS])) + self.PluginRoot = PluginsRoot(self, self.Log) + self.Controler = self.PluginRoot + result = self.PluginRoot.LoadProject(projectpath) + self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) - self.PluginRoot = PluginsRoot(self, self.Log)
- self.Controler = self.PluginRoot
- result = self.PluginRoot.LoadProject(projectpath)
- self.DebugVariablePanel.SetDataProducer(self.PluginRoot)
- self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
- self.ShowErrorMessage(result)
- self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
- self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU)
+ self.ShowErrorMessage(result) + self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath) + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) def OnCloseProjectMenu(self, event):
if self.PluginRoot is not None and not self.CheckSaveBeforeClosing():
@@ -1505,6 +1612,14 @@
def OnAboutMenu(self, event):
OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc","about.html"), wx.Size(550, 500))
+ def OnPouSelectedChanged(self, event): + wx.CallAfter(self.RefreshPluginMenu) + IDEFrame.OnPouSelectedChanged(self, event) + def OnPageClose(self, event): + wx.CallAfter(self.RefreshPluginMenu) + IDEFrame.OnPageClose(self, event) def GetAddButtonFunction(self, plugin, window):
def AddButtonFunction(event):
if plugin and len(plugin.PlugChildsTypes) > 0:
--- a/plugger.py Tue Jan 31 00:41:46 2012 +0100
+++ b/plugger.py Tue Jan 31 23:28:03 2012 +0100
@@ -135,14 +135,20 @@
def PlugPath(self,PlugName=None):
- PlugName = self.BaseParams.getName()
+ PlugName = self.PlugName() return os.path.join(self.PlugParent.PlugPath(),
PlugName + NameTypeSeparator + self.PlugType)
+ return self.BaseParams.getName() + return self.BaseParams.getEnabled() parent = self.PlugParent.PlugFullName()
- return parent + "." + self.BaseParams.getName()
+ return parent + "." + self.PlugName() return self.BaseParams.getName()
def GetIconPath(self, name):
@@ -498,10 +504,11 @@
self._View = self.EditorType(app_frame.TabsOpened, self, app_frame)
- app_frame.EditProjectElement(self._View, self.GetFilename())
+ app_frame.EditProjectElement(self._View, self.PlugName()) - def OnCloseEditor(self):
+ def OnCloseEditor(self, view): if self._View is not None:
@@ -1840,7 +1847,7 @@
self.logger.write_error(_("Couldn't start PLC !\n"))
- self.UpdateMethodsFromPLCStatus()
+ wx.CallAfter(self.UpdateMethodsFromPLCStatus) # def _Do_Test_Debug(self):
@@ -1869,7 +1876,7 @@
- self.UpdateMethodsFromPLCStatus()
+ wx.CallAfter(self.UpdateMethodsFromPLCStatus) # don't accept re-connetion is already connected
@@ -1963,7 +1970,7 @@
- self.UpdateMethodsFromPLCStatus()
+ wx.CallAfter(self.UpdateMethodsFromPLCStatus) # Get the last build PLC's
@@ -2003,7 +2010,7 @@
self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n"))
- self.UpdateMethodsFromPLCStatus()
+ wx.CallAfter(self.UpdateMethodsFromPLCStatus) {"bitmap" : opjimg("Build"),