#This file is part of Beremiz, a Integrated Development Environment for
#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
#See COPYING file for copyrights details.
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#General Public License for more details.
#You should have received a copy of the GNU General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os, sys, getopt, wx
from wx.lib.agw.advancedsplash import AdvancedSplash
from types import ListType
CWD = os.path.split(os.path.realpath(__file__))[0]
return os.path.join(CWD,*args)
if __name__ == '__main__':
print "\nUsage of Beremiz.py :"
print "\n %s [Projectpath] [Buildpath]\n"%sys.argv[0]
opts, args = getopt.getopt(sys.argv[1:], "hu:e:", ["help", "updatecheck=", "extend="])
except getopt.GetoptError:
# print help information and exit:
if o in ("-h", "--help"):
if o in ("-u", "--updatecheck"):
if o in ("-e", "--extend"):
if os.path.exists("BEREMIZ_DEBUG"):
__builtin__.__dict__["BMZ_DBG"] = True
__builtin__.__dict__["BMZ_DBG"] = False
app = wx.PySimpleApp(redirect=BMZ_DBG)
app.SetAppName('beremiz')
wx.InitAllImageHandlers()
bmp = wx.Image(Bpath("images", "splash.png")).ConvertToBitmap()
#splash=AdvancedSplash(None, bitmap=bmp, style=wx.SPLASH_CENTRE_ON_SCREEN, timeout=4000)
splash=AdvancedSplash(None, bitmap=bmp)
if updateinfo_url is not None:
updateinfo = "Fetching %s" % updateinfo_url
# warn for possible updates
updateinfo = urllib2.urlopen(updateinfo_url,None).read()
updateinfo = "update info unavailable."
from threading import Thread
splash.SetText(text=updateinfo)
updateinfoThread = Thread(target=updateinfoproc)
splash.SetText(text=updateinfo)
from util.TranslationCatalogs import AddCatalog, locale
from util.BitmapLibrary import AddBitmapFolder, GetBitmap
AddCatalog(os.path.join(CWD, "locale"))
AddBitmapFolder(os.path.join(CWD, "images"))
if __name__ == '__main__':
# Import module for internationalization
__builtin__.__dict__['loc'] = locale
__builtin__.__dict__['_'] = wx.GetTranslation
for extfilename in extensions:
extension_folder = os.path.split(os.path.realpath(extfilename))[0]
sys.path.append(extension_folder)
AddCatalog(os.path.join(extension_folder, "locale"))
AddBitmapFolder(os.path.join(extension_folder, "images"))
execfile(extfilename, locals())
import wx.lib.buttons, wx.lib.statbmp
import types, time, re, platform, time, traceback, commands
from docutil import OpenHtmlFrame
from IDEFrame import IDEFrame, AppendMenu
from IDEFrame import TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath
from editors.EditorPanel import EditorPanel
from editors.Viewer import Viewer
from editors.TextViewer import TextViewer
from editors.GraphicViewer import GraphicViewer
from editors.ResourceEditor import ConfigurationEditor, ResourceEditor
from editors.DataTypeEditor import DataTypeEditor
from util.MiniTextControler import MiniTextControler
from util.ProcessLogger import ProcessLogger
from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY, ITEM_PROJECT, ITEM_RESOURCE
from ProjectController import ProjectController, MATIEC_ERROR_MODEL, ITEM_CONFNODE
class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
""" Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32,
and accept image name as __init__ parameter, fail silently if file do not exist"""
def __init__(self, parent, ID, bitmapname,
pos = wx.DefaultPosition, size = wx.DefaultSize,
wx.lib.statbmp.GenStaticBitmap.__init__(self, parent, ID,
def OnPaint(self, event):
colour = self.GetParent().GetBackgroundColour()
dc.SetPen(wx.Pen(colour))
dc.SetBrush(wx.Brush(colour ))
dc.DrawRectangle(0, 0, *dc.GetSizeTuple())
dc.DrawBitmap(self._bitmap, 0, 0, True)
from threading import Lock,Timer,currentThread
MainThread = currentThread().ident
from time import time as gettime
""" Base class for file like objects to facilitate StdOut for the Shell."""
def __init__(self, output, risecall):
self.red_white = wx.TextAttr("RED", "WHITE")
self.red_yellow = wx.TextAttr("RED", "YELLOW")
self.black_white = wx.TextAttr("BLACK", "WHITE")
self.default_style = None
# to prevent rapid fire on rising log panel
self.RefreshLock = Lock()
self.TimerAccessLock = Lock()
self.LastRefreshTime = gettime()
self.LastRefreshTimer = None
def write(self, s, style = None):
self.stack.append((s,style))
self.TimerAccessLock.acquire()
if self.LastRefreshTimer:
self.LastRefreshTimer.cancel()
self.LastRefreshTimer=None
self.TimerAccessLock.release()
if current_time - self.LastRefreshTime > REFRESH_PERIOD and self.RefreshLock.acquire(False):
self.TimerAccessLock.acquire()
self.LastRefreshTimer = Timer(REFRESH_PERIOD, self._timer_expired)
self.LastRefreshTimer.start()
self.TimerAccessLock.release()
def _timer_expired(self):
if self.RefreshLock.acquire(False):
self.TimerAccessLock.acquire()
self.LastRefreshTimer = Timer(REFRESH_PERIOD, self._timer_expired)
self.LastRefreshTimer.start()
self.TimerAccessLock.release()
wx.CallAfter(self._write)
if MainThread == currentThread().ident:
if self.YieldLock.acquire(0):
for s, style in self.stack:
if style is None : style=self.black_white
if self.default_style != style:
self.output.SetDefaultStyle(style)
self.default_style = style
self.output.AppendText(s)
self.output.ScrollLines(s.count('\n')+1)
self.output.ShowPosition(self.output.GetLastPosition())
self.LastRefreshTime = gettime()
self.RefreshLock.release()
if newtime - self.rising_timer > 1:
self.rising_timer = newtime
def write_warning(self, s):
self.write(s,self.red_white)
def write_error(self, s):
self.write(s,self.red_yellow)
[ID_BEREMIZ, ID_BEREMIZMAINSPLITTER,
ID_BEREMIZPLCCONFIG, ID_BEREMIZLOGCONSOLE,
ID_BEREMIZINSPECTOR] = [wx.NewId() for _init_ctrls in range(5)]
[ID_FILEMENURECENTPROJECTS,
] = [wx.NewId() for _init_ctrls in range(1)]
CONFNODEMENU_POSITION = 3
self.ConfNodeMenu = 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)
AppendMenu(parent, help='', id=wx.ID_SAVE,
kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S')
AppendMenu(parent, help='', id=wx.ID_SAVEAS,
kind=wx.ITEM_NORMAL, text=_(u'Save as') + '\tCTRL+SHIFT+S')
AppendMenu(parent, help='', id=wx.ID_CLOSE,
kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W')
AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL,
kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W')
AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P')
AppendMenu(parent, help='', id=wx.ID_PREVIEW,
kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P')
AppendMenu(parent, help='', id=wx.ID_PRINT,
kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P')
AppendMenu(parent, help='', id=wx.ID_EXIT,
kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q')
self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL)
self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
self.AddToMenuToolBar([(wx.ID_NEW, "new", _(u'New'), None),
(wx.ID_OPEN, "open", _(u'Open'), None),
(wx.ID_SAVE, "save", _(u'Save'), None),
(wx.ID_SAVEAS, "saveas", _(u'Save As...'), None),
(wx.ID_PRINT, "print", _(u'Print'), None)])
def _init_coll_AddMenu_Items(self, parent):
IDEFrame._init_coll_AddMenu_Items(self, parent, False)
AppendMenu(parent, help='', id=new_id,
kind=wx.ITEM_NORMAL, text=_(u'&Resource'))
self.Bind(wx.EVT_MENU, self.AddResourceMenu, id=new_id)
for name, XSDClass, help in ProjectController.CTNChildrenTypes:
AppendMenu(parent, help='', id=new_id,
kind=wx.ITEM_NORMAL, text=help)
self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), id=new_id)
def _init_coll_HelpMenu_Items(self, parent):
parent.Append(help='', id=wx.ID_ABOUT,
kind=wx.ITEM_NORMAL, text=_(u'About'))
self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
def _init_ctrls(self, prnt):
IDEFrame._init_ctrls(self, prnt)
self.EditMenuSize = self.EditMenu.GetMenuItemCount()
self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR)
accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)]
for method,shortcut in [("Stop", wx.WXK_F4),
def OnMethodGen(obj,meth):
obj.CTR.CallMethod('_'+meth)
wx.CallAfter(self.RefreshStatusToolBar)
self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
self.SetAcceleratorTable(wx.AcceleratorTable(accels))
self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
self.MainTabs["LogConsole"] = (self.LogConsole, _("Log Console"))
self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"])
#self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT)
StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
StatusToolBar.SetToolBitmapSize(wx.Size(25, 25))
self.Panes["StatusToolBar"] = StatusToolBar
self.AUIManager.AddPane(StatusToolBar, wx.aui.AuiPaneInfo().
Name("StatusToolBar").Caption(_("Status ToolBar")).
ToolbarPane().Top().Position(1).
LeftDockable(False).RightDockable(False))
def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
IDEFrame.__init__(self, parent, debug)
self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
self.local_runtime = None
self.local_runtime_tmpdir = None
self.LastPanelSelected = None
# Define Tree item icon list
self.LocationImageList = wx.ImageList(16, 16)
self.LocationImageDict = {}
# Icons for location items
for imgname, itemtype in [
("CONFIGURATION", LOCATION_CONFNODE),
("RESOURCE", LOCATION_MODULE),
("PROGRAM", LOCATION_GROUP),
("VAR_INPUT", LOCATION_VAR_INPUT),
("VAR_OUTPUT", LOCATION_VAR_OUTPUT),
("VAR_LOCAL", LOCATION_VAR_MEMORY)]:
self.LocationImageDict[itemtype] = self.LocationImageList.Add(GetBitmap(imgname))
for imgname, itemtype in [
("Extension", ITEM_CONFNODE)]:
self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
# Add beremiz's icon in top left corner of the frame
self.SetIcon(wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO))
if projectOpen is not None:
projectOpen = DecodeFileSystemPath(projectOpen, False)
if ctr is None and projectOpen is None and self.Config.HasEntry("currenteditedproject"):
projectOpen = DecodeFileSystemPath(self.Config.Read("currenteditedproject"))
if projectOpen is not None and os.path.isdir(projectOpen):
self.CTR = ProjectController(self, self.Log)
self.Controler = self.CTR
result = self.CTR.LoadProject(projectOpen, buildpath)
self.LibraryPanel.SetController(self.Controler)
self.ProjectTree.Enable(True)
self.PouInstanceVariablesPanel.SetController(self.Controler)
self.RefreshConfigRecentProjects(os.path.abspath(projectOpen))
self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
self.ShowErrorMessage(result)
self.LibraryPanel.SetController(self.Controler)
self.ProjectTree.Enable(True)
self.PouInstanceVariablesPanel.SetController(self.Controler)
self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
self.DebugVariablePanel.SetDataProducer(self.CTR)
self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
self.LogConsole.SetFocus()
def RiseLogConsole(self):
self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
projectname = self.CTR.GetProjectName()
if self.CTR.ProjectTestModified():
projectname = "~%s~" % projectname
self.SetTitle("%s - %s" % (name, projectname))
def StartLocalRuntime(self, taskbaricon = True):
if (self.local_runtime is None) or (self.local_runtime.exitcode is not None):
# create temporary directory for runtime working directory
self.local_runtime_tmpdir = tempfile.mkdtemp()
# choose an arbitrary random port for runtime
self.runtime_port = int(random.random() * 1000) + 61131
self.local_runtime = ProcessLogger(self.Log,
"\"%s\" \"%s\" -p %s -i localhost %s %s"%(sys.executable,
Bpath("Beremiz_service.py"),
{False : "-x 0", True :"-x 1"}[taskbaricon],
self.local_runtime_tmpdir),
timeout=500, keyword = "working")
self.local_runtime.spin()
def KillLocalRuntime(self):
if self.local_runtime is not None:
self.local_runtime.kill(gently=False)
shutil.rmtree(self.local_runtime_tmpdir)
self.local_runtime = None
def OnOpenWidgetInspector(self, evt):
# Activate the widget inspection tool
from wx.lib.inspection import InspectionTool
if not InspectionTool().initialized:
# Find a widget to be selected in the tree. Use either the
# one under the cursor, if any, or this frame.
wnd = wx.FindWindowAtPointer()
InspectionTool().Show(wnd, True)
def OnLogConsoleDClick(self, event):
wx.CallAfter(self.SearchLineForError)
def SearchLineForError(self):
text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint())
line = self.LogConsole.GetLineText(len(text.splitlines()) - 1)
result = MATIEC_ERROR_MODEL.match(line)
first_line, first_column, last_line, last_column, error = result.groups()
infos = self.CTR.ShowError(self.Log,
(int(first_line), int(first_column)),
(int(last_line), int(last_column)))
## Function displaying an Error dialog in PLCOpenEditor.
# @return False if closing cancelled.
def CheckSaveBeforeClosing(self, title=_("Close Project")):
if self.CTR.ProjectTestModified():
dialog = wx.MessageDialog(self,
_("There are changes, do you want to save?"),
wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
answer = dialog.ShowModal()
elif answer == wx.ID_CANCEL:
for idx in xrange(self.TabsOpened.GetPageCount()):
window = self.TabsOpened.GetPage(idx)
if not window.CheckSaveBeforeClosing():
def GetTabInfos(self, tab):
if (isinstance(tab, EditorPanel) and
not isinstance(tab, (Viewer,
return ("confnode", tab.Controler.CTNFullName(), tab.GetTagName())
elif (isinstance(tab, TextViewer) and
(tab.Controler is None or isinstance(tab.Controler, MiniTextControler))):
return ("confnode", None, tab.GetInstancePath())
return IDEFrame.GetTabInfos(self, tab)
def LoadTab(self, notebook, page_infos):
if page_infos[0] == "confnode":
if page_infos[1] is None:
confnode = self.CTR.GetChildByName(page_infos[1])
return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:]))
return IDEFrame.LoadTab(self, notebook, page_infos)
def OnCloseFrame(self, event):
if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")):
self.CTR.KillDebugThread()
project_path = os.path.realpath(self.CTR.GetProjectPath())
self.Config.Write("currenteditedproject", EncodeFileSystemPath(project_path))
def RefreshFileMenu(self):
self.RefreshRecentProjectsMenu()
MenuToolBar = self.Panes["MenuToolBar"]
selected = self.TabsOpened.GetSelection()
window = self.TabsOpened.GetPage(selected)
viewer_is_modified = window.IsModified()
is_viewer = isinstance(window, Viewer)
viewer_is_modified = is_viewer = False
if self.TabsOpened.GetPageCount() > 0:
self.FileMenu.Enable(wx.ID_CLOSE, True)
self.FileMenu.Enable(wx.ID_PREVIEW, True)
self.FileMenu.Enable(wx.ID_PRINT, True)
MenuToolBar.EnableTool(wx.ID_PRINT, True)
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
MenuToolBar.EnableTool(wx.ID_PRINT, False)
self.FileMenu.Enable(wx.ID_CLOSE, False)
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
MenuToolBar.EnableTool(wx.ID_PRINT, False)
self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
project_modified = self.CTR.ProjectTestModified() or viewer_is_modified
self.FileMenu.Enable(wx.ID_SAVE, project_modified)
MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
self.FileMenu.Enable(wx.ID_SAVEAS, True)
MenuToolBar.EnableTool(wx.ID_SAVEAS, True)
self.FileMenu.Enable(wx.ID_CLOSE_ALL, True)
self.FileMenu.Enable(wx.ID_CLOSE, False)
self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
MenuToolBar.EnableTool(wx.ID_PRINT, False)
self.FileMenu.Enable(wx.ID_SAVE, False)
MenuToolBar.EnableTool(wx.ID_SAVE, False)
self.FileMenu.Enable(wx.ID_SAVEAS, False)
MenuToolBar.EnableTool(wx.ID_SAVEAS, False)
self.FileMenu.Enable(wx.ID_CLOSE_ALL, False)
def RefreshRecentProjectsMenu(self):
recent_projects = map(DecodeFileSystemPath,
self.GetConfigEntry("RecentProjects", []))
self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0)
for idx, projectpath in enumerate(recent_projects):
text = u'%d: %s' % (idx + 1, projectpath)
if idx < self.RecentProjectsMenu.GetMenuItemCount():
item = self.RecentProjectsMenu.FindItemByPosition(idx)
self.Disconnect(id, id, wx.EVT_BUTTON._getEvtType())
AppendMenu(self.RecentProjectsMenu, help='', id=id,
kind=wx.ITEM_NORMAL, text=text)
self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id)
def GenerateOpenRecentProjectFunction(self, projectpath):
def OpenRecentProject(event):
if self.CTR is not None and not self.CheckSaveBeforeClosing():
self.OpenProject(projectpath)
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)
self.Bind(wx.EVT_MENU, callback, id=id)
def RefreshEditorToolBar(self):
IDEFrame.RefreshEditorToolBar(self)
self.AUIManager.GetPane("EditorToolBar").Position(2)
self.AUIManager.GetPane("StatusToolBar").Position(1)
def RefreshStatusToolBar(self):
StatusToolBar = self.Panes["StatusToolBar"]
StatusToolBar.ClearTools()
for confnode_method in self.CTR.StatusMethods:
if "method" in confnode_method and confnode_method.get("shown",True):
StatusToolBar.AddSimpleTool(id,
GetBitmap(confnode_method.get("bitmap", "Unknown")),
confnode_method["tooltip"])
self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), id=id)
self.AUIManager.GetPane("StatusToolBar").BestSize(StatusToolBar.GetBestSize()).Show()
self.AUIManager.GetPane("StatusToolBar").Hide()
self.AUIManager.GetPane("EditorToolBar").Position(2)
self.AUIManager.GetPane("StatusToolBar").Position(1)
def RefreshEditMenu(self):
IDEFrame.RefreshEditMenu(self)
selected = self.TabsOpened.GetSelection()
panel = self.TabsOpened.GetPage(selected)
if panel != self.LastPanelSelected:
for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()):
item = self.EditMenu.FindItemByPosition(self.EditMenuSize)
self.EditMenu.RemoveItem(item)
self.EditMenu.Delete(item.GetId())
self.LastPanelSelected = panel
items = panel.GetConfNodeMenuItems()
self.EditMenu.AppendSeparator()
self.GenerateMenuRecursive(items, self.EditMenu)
panel.RefreshConfNodeMenu(self.EditMenu)
for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()):
item = self.EditMenu.FindItemByPosition(i)
self.EditMenu.RemoveItem(item)
self.EditMenu.Delete(item.GetId())
self.LastPanelSelected = None
self.MenuBar.UpdateMenus()
self.RefreshStatusToolBar()
def GetMenuCallBackFunction(self, method):
""" Generate the callbackfunc for a given CTR method"""
# Disable button to prevent re-entrant call
event.GetEventObject().Disable()
getattr(self.CTR, method)()
event.GetEventObject().Enable()
def GetConfigEntry(self, entry_name, default):
return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default))))
self.DebugVariablePanel.SetDataProducer(None)
def RefreshConfigRecentProjects(self, projectpath):
recent_projects = map(DecodeFileSystemPath,
self.GetConfigEntry("RecentProjects", []))
if projectpath in recent_projects:
recent_projects.remove(projectpath)
recent_projects.insert(0, projectpath)
self.Config.Write("RecentProjects", cPickle.dumps(
map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS])))
def ResetPerspective(self):
IDEFrame.ResetPerspective(self)
self.RefreshStatusToolBar()
def RestoreLastLayout(self):
IDEFrame.RestoreLastLayout(self)
self.RefreshStatusToolBar()
def OnNewProjectMenu(self, event):
if self.CTR is not None and not self.CheckSaveBeforeClosing():
defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder"))
defaultpath = os.path.expanduser("~")
dialog = wx.DirDialog(self , _("Choose a project"), defaultpath)
if dialog.ShowModal() == wx.ID_OK:
projectpath = dialog.GetPath()
self.Config.Write("lastopenedfolder",
EncodeFileSystemPath(os.path.dirname(projectpath)))
ctr = ProjectController(self, self.Log)
result = ctr.NewProject(projectpath)
self.Controler = self.CTR
self.LibraryPanel.SetController(self.Controler)
self.ProjectTree.Enable(True)
self.PouInstanceVariablesPanel.SetController(self.Controler)
self.RefreshConfigRecentProjects(projectpath)
self.DebugVariablePanel.SetDataProducer(self.CTR)
self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
self.ShowErrorMessage(result)
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
def OnOpenProjectMenu(self, event):
if self.CTR is not None and not self.CheckSaveBeforeClosing():
defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder"))
defaultpath = os.path.expanduser("~")
dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE|
if dialog.ShowModal() == wx.ID_OK:
self.OpenProject(dialog.GetPath())
def OpenProject(self, projectpath):
if os.path.isdir(projectpath):
self.Config.Write("lastopenedfolder",
EncodeFileSystemPath(os.path.dirname(projectpath)))
self.CTR = ProjectController(self, self.Log)
self.Controler = self.CTR
result = self.CTR.LoadProject(projectpath)
self.LibraryPanel.SetController(self.Controler)
self.ProjectTree.Enable(True)
self.PouInstanceVariablesPanel.SetController(self.Controler)
self.RefreshConfigRecentProjects(projectpath)
self.DebugVariablePanel.SetDataProducer(self.CTR)
self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
self.ShowErrorMessage(result)
self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath)
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
def OnCloseProjectMenu(self, event):
if self.CTR is not None and not self.CheckSaveBeforeClosing():
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
def OnSaveProjectMenu(self, event):
selected = self.TabsOpened.GetSelection()
window = self.TabsOpened.GetPage(selected)
self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
def OnSaveProjectAsMenu(self, event):
selected = self.TabsOpened.GetSelection()
window = self.TabsOpened.GetPage(selected)
self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
def OnQuitMenu(self, event):
def OnAboutMenu(self, event):
OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc", "about.html"), wx.Size(550, 500))
def OnProjectTreeItemBeginEdit(self, event):
selected = event.GetItem()
if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFNODE:
IDEFrame.OnProjectTreeItemBeginEdit(self, event)
def OnProjectTreeRightUp(self, event):
if wx.Platform == '__WXMSW__':
item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY()))
item_infos = self.ProjectTree.GetPyData(item)
if item_infos["type"] == ITEM_CONFNODE:
confnode_menu = wx.Menu(title='')
confnode = item_infos["confnode"]
if confnode is not None and len(confnode.CTNChildrenTypes) > 0:
for name, XSDClass, help in confnode.CTNChildrenTypes:
confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Add") + " " + name)
self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name, confnode), id=new_id)
AppendMenu(confnode_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), id=new_id)
self.PopupMenu(confnode_menu)
IDEFrame.OnProjectTreeRightUp(self, event)
def OnProjectTreeItemActivated(self, event):
selected = event.GetItem()
name = self.ProjectTree.GetItemText(selected)
item_infos = self.ProjectTree.GetPyData(selected)
if item_infos["type"] == ITEM_CONFNODE:
item_infos["confnode"]._OpenView()
elif item_infos["type"] == ITEM_PROJECT:
IDEFrame.OnProjectTreeItemActivated(self, event)
def ProjectTreeItemSelect(self, select_item):
name = self.ProjectTree.GetItemText(select_item)
item_infos = self.ProjectTree.GetPyData(select_item)
if item_infos["type"] == ITEM_CONFNODE:
item_infos["confnode"]._OpenView(onlyopened=True)
elif item_infos["type"] == ITEM_PROJECT:
self.CTR._OpenView(onlyopened=True)
IDEFrame.ProjectTreeItemSelect(self, select_item)
def SelectProjectTreeItem(self, tagname):
if self.ProjectTree is not None:
root = self.ProjectTree.GetRootItem()
words = tagname.split("::")
self.ProjectTree.SelectItem(root)
wx.CallAfter(self.ResetSelectedItem)
return self.RecursiveProjectTreeItemSelection(root,
[(word, ITEM_CONFNODE) for word in tagname.split(".")])
return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)])
IDEFrame.SelectProjectTreeItem(self, tagname)
def GetAddConfNodeFunction(self, name, confnode=None):
def AddConfNodeMenuFunction(event):
wx.CallAfter(self.AddConfNode, name, confnode)
return AddConfNodeMenuFunction
def GetDeleteMenuFunction(self, confnode):
def DeleteMenuFunction(event):
wx.CallAfter(self.DeleteConfNode, confnode)
return DeleteMenuFunction
def AddResourceMenu(self, event):
config_names = self.CTR.GetProjectConfigNames()
if len(config_names) > 0:
tagname = self.Controler.ProjectAddConfigurationResource(config_names[0])
self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
self.EditProjectElement(ITEM_RESOURCE, tagname)
def AddConfNode(self, ConfNodeType, confnode=None):
if self.CTR.CheckProjectPathPerm():
ConfNodeName = "%s_0" % ConfNodeType
confnode.CTNAddChild(ConfNodeName, ConfNodeType)
self.CTR.CTNAddChild(ConfNodeName, ConfNodeType)
self._Refresh(TITLE, FILEMENU, PROJECTTREE)
def DeleteConfNode(self, confnode):
if self.CTR.CheckProjectPathPerm():
dialog = wx.MessageDialog(self,
_("Really delete node '%s'?") % confnode.CTNName(),
_("Remove %s node") % confnode.CTNType,
if dialog.ShowModal() == wx.ID_YES:
self._Refresh(TITLE, FILEMENU, PROJECTTREE)
#-------------------------------------------------------------------------------
# Highlights showing functions
#-------------------------------------------------------------------------------
def ShowHighlight(self, infos, start, end, highlight_type):
config_name = self.Controler.GetProjectMainConfigurationName()
if config_name is not None and infos[0] == self.Controler.ComputeConfigurationName(config_name):
selected = self.TabsOpened.GetSelection()
viewer = self.TabsOpened.GetPage(selected)
viewer.AddHighlight(infos[1:], start, end, highlight_type)
IDEFrame.ShowHighlight(self, infos, start, end, highlight_type)
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
Max_Traceback_List_Size = 20
def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path):
for i,line in enumerate(traceback.extract_tb(e_tb)):
trcbck = " " + str(i+1) + ". "
if line[0].find(os.getcwd()) == -1:
trcbck += "file : " + str(line[0]) + ", "
trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ", "
trcbck += "line : " + str(line[1]) + ", " + "function : " + str(line[2])
trcbck_lst.append(trcbck)
cap = wx.Window_GetCapture()
dlg = wx.SingleChoiceDialog(None,
An unhandled exception (bug) occured. Bug report saved at :
Please be kind enough to send this file to:
beremiz-devel@lists.sourceforge.net
You should now restart Beremiz.
str(e_type) + " : " + str(e_value),
res = (dlg.ShowModal() == wx.ID_OK)
def get_last_traceback(tb):
def format_namespace(d, indent=' '):
return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()])
ignored_exceptions = [] # a problem with a line in a module is only reported once per session
def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
def handle_exception(e_type, e_value, e_traceback):
traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
last_tb = get_last_traceback(e_traceback)
ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
if ex not in ignored_exceptions:
bug_report_path = path+os.sep+"bug_report_"+date.replace(':','-').replace(' ','_')+".txt"
result = Display_Exception_Dialog(e_type,e_value,e_traceback,bug_report_path)
ignored_exceptions.append(ex)
'app-title' : wx.GetApp().GetAppName(), # app_title
'app-version' : app_version,
'wx-version' : wx.VERSION_STRING,
'wx-platform' : wx.Platform,
'python-version' : platform.python_version(), #sys.version.split()[0],
'platform' : platform.platform(),
info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
last_tb = get_last_traceback(e_traceback)
exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
info['locals'] = format_namespace(exception_locals)
if 'self' in exception_locals:
info['self'] = format_namespace(exception_locals['self'].__dict__)
output = open(bug_report_path,'w')
output.write(a+":\n"+str(info[a])+"\n\n")
#sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
sys.excepthook = handle_exception
if __name__ == '__main__':
# Install a exception handle for bug reports
AddExceptHook(os.getcwd(),updateinfo_url)
frame = Beremiz(None, projectOpen, buildpath)