Laurent@814: #!/usr/bin/env python Laurent@814: # -*- coding: utf-8 -*- Laurent@814: andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. Laurent@814: # andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD Laurent@814: # andrej@1571: # See COPYING file for copyrights details. Laurent@814: # andrej@1571: # This program is free software; you can redistribute it and/or andrej@1571: # modify it under the terms of the GNU General Public License andrej@1571: # as published by the Free Software Foundation; either version 2 andrej@1571: # of the License, or (at your option) any later version. Laurent@814: # andrej@1571: # This program is distributed in the hope that it will be useful, andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1571: # GNU General Public License for more details. Laurent@814: # andrej@1571: # You should have received a copy of the GNU General Public License andrej@1571: # along with this program; if not, write to the Free Software andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Laurent@814: Laurent@814: import wx Laurent@814: import os, sys, platform, time, traceback, getopt andrej@1560: import version Laurent@814: Edouard@1451: beremiz_dir = os.path.dirname(os.path.realpath(__file__)) Laurent@814: Laurent@814: __version__ = "$Revision: 1.130 $" Laurent@814: Laurent@814: if __name__ == '__main__': Edouard@1451: # Usage message displayed when help request or when error detected in Laurent@814: # command line Laurent@814: def usage(): Laurent@814: print "\nUsage of PLCOpenEditor.py :" Laurent@814: print "\n %s [Filepath]\n"%sys.argv[0] Laurent@814: Laurent@814: # Parse options given to PLCOpenEditor in command line Laurent@814: try: Laurent@814: opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) Laurent@814: except getopt.GetoptError: Laurent@814: # print help information and exit: Laurent@814: usage() Laurent@814: sys.exit(2) Edouard@1451: Laurent@814: # Extract if help has been requested Laurent@814: for o, a in opts: Laurent@814: if o in ("-h", "--help"): Laurent@814: usage() Laurent@814: sys.exit() Edouard@1451: Laurent@814: # Extract the optional filename to open Laurent@814: fileOpen = None Laurent@814: if len(args) > 1: Laurent@814: usage() Laurent@814: sys.exit() Laurent@814: elif len(args) == 1: Laurent@814: fileOpen = args[0] Edouard@1451: Laurent@814: # Create wxApp (Need to create App before internationalization because of Edouard@1451: # Windows) andrej@1533: if wx.VERSION >= (3, 0, 0): andrej@1533: app = wx.App() andrej@1533: else: andrej@1533: app = wx.PySimpleApp() andrej@1533: Laurent@814: Edouard@1388: from util.misc import InstallLocalRessources Edouard@1451: InstallLocalRessources(beremiz_dir) Edouard@1388: laurent@815: from docutil import * Laurent@814: from IDEFrame import IDEFrame, AppendMenu Laurent@814: from IDEFrame import TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, PAGETITLES Laurent@814: from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath Laurent@814: from editors.Viewer import Viewer Laurent@814: from PLCControler import PLCControler Laurent@1030: from dialogs import ProjectDialog andrej@1565: from dialogs.AboutDialog import ShowAboutDialog Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # PLCOpenEditor Main Class Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: # Define PLCOpenEditor FileMenu extra items id Edouard@1451: [ID_PLCOPENEDITORFILEMENUGENERATE, Laurent@814: ] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)] Laurent@814: Laurent@814: class PLCOpenEditor(IDEFrame): Laurent@814: Laurent@814: # Compatibility function for wx versions < 2.6 Laurent@814: if wx.VERSION < (2, 6, 0): Laurent@814: def Bind(self, event, function, id = None): Laurent@814: if id is not None: Laurent@814: event(self, id, function) Laurent@814: else: Laurent@814: event(self, function) Laurent@814: Laurent@814: def _init_coll_FileMenu_Items(self, parent): Laurent@814: AppendMenu(parent, help='', id=wx.ID_NEW, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'New') +'\tCTRL+N') Laurent@814: AppendMenu(parent, help='', id=wx.ID_OPEN, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O') Laurent@814: AppendMenu(parent, help='', id=wx.ID_CLOSE, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W') Laurent@814: AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_SAVE, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S') Laurent@814: AppendMenu(parent, help='', id=wx.ID_SAVEAS, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Save As...') + '\tCTRL+SHIFT+S') Laurent@814: AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Generate Program') + '\tCTRL+G') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P') Laurent@814: AppendMenu(parent, help='', id=wx.ID_PREVIEW, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P') Laurent@814: AppendMenu(parent, help='', id=wx.ID_PRINT, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_PROPERTIES, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'&Properties')) Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_EXIT, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q') Edouard@1451: Laurent@814: self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) Laurent@814: self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) Laurent@814: self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE) Laurent@814: self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) Laurent@814: self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) Laurent@814: self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) Laurent@814: self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu, Laurent@814: id=ID_PLCOPENEDITORFILEMENUGENERATE) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES) Laurent@814: self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT) Edouard@1451: Laurent@814: self.AddToMenuToolBar([(wx.ID_NEW, "new", _(u'New'), None), Laurent@814: (wx.ID_OPEN, "open", _(u'Open'), None), Laurent@814: (wx.ID_SAVE, "save", _(u'Save'), None), Laurent@814: (wx.ID_SAVEAS, "saveas", _(u'Save As...'), None), Laurent@814: (wx.ID_PRINT, "print", _(u'Print'), None)]) Edouard@1451: Laurent@814: def _init_coll_HelpMenu_Items(self, parent): Edouard@1451: AppendMenu(parent, help='', id=wx.ID_HELP, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor') + '\tF1') Laurent@814: #AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS, Laurent@814: # kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2') Laurent@814: #AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT, Laurent@814: # kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3') Laurent@814: AppendMenu(parent, help='', id=wx.ID_ABOUT, Laurent@814: kind=wx.ITEM_NORMAL, text=_(u'About')) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP) Laurent@814: #self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS) Laurent@814: self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) Laurent@814: Laurent@814: ## Constructor of the PLCOpenEditor class. Laurent@814: # @param parent The parent window. Laurent@814: # @param controler The controler been used by PLCOpenEditor (default: None). Laurent@814: # @param fileOpen The filepath to open if no controler defined (default: None). Laurent@814: # @param debug The filepath to open if no controler defined (default: False). Laurent@814: def __init__(self, parent, fileOpen = None): andrej@1533: self.icon = wx.Icon(os.path.join(beremiz_dir, "images", "poe.ico"), wx.BITMAP_TYPE_ICO) Laurent@814: IDEFrame.__init__(self, parent) Edouard@1451: Laurent@814: result = None Edouard@1451: Laurent@814: # Open the filepath if defined Laurent@814: if fileOpen is not None: Laurent@814: fileOpen = DecodeFileSystemPath(fileOpen, False) Laurent@814: if os.path.isfile(fileOpen): Laurent@814: # Create a new controller Laurent@814: controler = PLCControler() Laurent@814: result = controler.OpenXMLFile(fileOpen) Laurent@1330: self.Controler = controler Laurent@1330: self.LibraryPanel.SetController(controler) Laurent@1330: self.ProjectTree.Enable(True) Laurent@1330: self.PouInstanceVariablesPanel.SetController(controler) Laurent@1330: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) Edouard@1451: Laurent@814: # Define PLCOpenEditor icon andrej@1533: self.SetIcon(self.icon) Laurent@814: Laurent@814: self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) Edouard@1451: Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) Edouard@1451: Laurent@814: if result is not None: andrej@1581: (num, line) = result andrej@1581: self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1 = num, a2 = line)) Laurent@814: Laurent@814: def OnCloseFrame(self, event): Laurent@814: if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")): Laurent@814: self.AUIManager.UnInit() Edouard@1451: Laurent@814: self.SaveLastState() Edouard@1451: Laurent@814: event.Skip() Laurent@814: else: Laurent@814: event.Veto() Laurent@814: Laurent@814: def RefreshTitle(self): Laurent@814: name = _("PLCOpenEditor") Laurent@814: if self.Controler is not None: Laurent@814: self.SetTitle("%s - %s"%(name, self.Controler.GetFilename())) Laurent@814: else: Laurent@814: self.SetTitle(name) Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # File Menu Functions Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: def RefreshFileMenu(self): Laurent@814: MenuToolBar = self.Panes["MenuToolBar"] Laurent@814: if self.Controler is not None: Laurent@814: selected = self.TabsOpened.GetSelection() Laurent@814: if selected >= 0: Laurent@814: graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) Laurent@814: else: Laurent@814: graphic_viewer = False Laurent@814: if self.TabsOpened.GetPageCount() > 0: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, True) Laurent@814: if graphic_viewer: Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, True) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, True) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, True) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) Laurent@814: project_modified = not self.Controler.ProjectIsSaved() Laurent@814: self.FileMenu.Enable(wx.ID_SAVE, project_modified) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) Laurent@814: self.FileMenu.Enable(wx.ID_PROPERTIES, True) Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) Laurent@814: self.FileMenu.Enable(wx.ID_SAVEAS, True) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVEAS, True) Laurent@814: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, True) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PAGE_SETUP, False) Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: self.FileMenu.Enable(wx.ID_SAVE, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PROPERTIES, False) Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) Laurent@814: self.FileMenu.Enable(wx.ID_SAVEAS, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVEAS, False) Laurent@814: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, False) Laurent@814: Laurent@814: def OnNewProjectMenu(self, event): Laurent@814: if self.Controler is not None and not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: dialog = ProjectDialog(self) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: properties = dialog.GetValues() Laurent@814: self.ResetView() Laurent@814: self.Controler = PLCControler() Laurent@814: self.Controler.CreateNewProject(properties) Laurent@814: self.LibraryPanel.SetController(self.Controler) Laurent@1295: self.ProjectTree.Enable(True) Edouard@1451: self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, Laurent@814: LIBRARYTREE) Laurent@814: Laurent@814: def OnOpenProjectMenu(self, event): Laurent@814: if self.Controler is not None and not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: filepath = "" Laurent@814: if self.Controler is not None: Laurent@814: filepath = self.Controler.GetFilePath() Laurent@814: if filepath != "": Laurent@814: directory = os.path.dirname(filepath) Laurent@814: else: Laurent@814: directory = os.getcwd() Edouard@1451: Laurent@814: result = None Edouard@1451: Laurent@814: dialog = wx.FileDialog(self, _("Choose a file"), directory, "", _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.OPEN) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: filepath = dialog.GetPath() Laurent@814: if os.path.isfile(filepath): Laurent@814: self.ResetView() Laurent@814: controler = PLCControler() Laurent@814: result = controler.OpenXMLFile(filepath) Laurent@1330: self.Controler = controler Laurent@1330: self.LibraryPanel.SetController(controler) Laurent@1330: self.ProjectTree.Enable(True) Laurent@1330: self.PouInstanceVariablesPanel.SetController(controler) Laurent@1330: self._Refresh(PROJECTTREE, LIBRARYTREE) Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) Laurent@814: dialog.Destroy() Edouard@1451: Laurent@814: if result is not None: andrej@1581: (num, line) = result andrej@1581: self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1 = num, a2 = line)) Edouard@1451: Laurent@814: def OnCloseProjectMenu(self, event): Laurent@814: if not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: self.ResetView() Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) Laurent@814: Laurent@814: def OnSaveProjectMenu(self, event): Laurent@814: self.SaveProject() Laurent@814: Laurent@814: def OnSaveProjectAsMenu(self, event): Laurent@814: self.SaveProjectAs() Laurent@814: Laurent@814: def OnGenerateProgramMenu(self, event): Laurent@814: dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE|wx.CHANGE_DIR) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: filepath = dialog.GetPath() Laurent@814: message_text = "" Laurent@814: header, icon = _("Done"), wx.ICON_INFORMATION Laurent@814: if os.path.isdir(os.path.dirname(filepath)): Laurent@814: program, errors, warnings = self.Controler.GenerateProgram(filepath) Laurent@1312: message_text += "".join([_("warning: %s\n") % warning for warning in warnings]) Laurent@814: if len(errors) > 0: Laurent@1312: message_text += "".join([_("error: %s\n") % error for error in errors]) Laurent@814: message_text += _("Can't generate program to file %s!")%filepath Laurent@814: header, icon = _("Error"), wx.ICON_ERROR Laurent@814: else: Laurent@814: message_text += _("Program was successfully generated!") Laurent@814: else: Laurent@814: message_text += _("\"%s\" is not a valid folder!")%os.path.dirname(filepath) Laurent@814: header, icon = _("Error"), wx.ICON_ERROR Laurent@814: message = wx.MessageDialog(self, message_text, header, wx.OK|icon) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: dialog.Destroy() Laurent@814: Laurent@814: def OnPLCOpenEditorMenu(self, event): Laurent@814: wx.MessageBox(_("No documentation available.\nComing soon.")) Edouard@1451: Laurent@814: def OnPLCOpenMenu(self, event): Edouard@1451: open_pdf(os.path.join(beremiz_dir, "plcopen", "TC6_XML_V101.pdf")) Edouard@1451: Laurent@814: def OnAboutMenu(self, event): andrej@1565: info = version.GetAboutDialogInfo() andrej@1565: info.Name = "PLCOpenEditor" andrej@1565: info.Description = _("PLCOpenEditor is part of Beremiz project.\n\n" andrej@1565: "Beremiz is an ") + info.Description andrej@1565: info.Icon = wx.Icon(os.path.join(beremiz_dir, "images", "aboutlogo.png"), wx.BITMAP_TYPE_PNG) andrej@1565: ShowAboutDialog(self, info) Laurent@814: Laurent@814: def SaveProject(self): Laurent@814: result = self.Controler.SaveXMLFile() Laurent@814: if not result: Laurent@814: self.SaveProjectAs() Laurent@814: else: Laurent@814: self._Refresh(TITLE, FILEMENU, PAGETITLES) Edouard@1451: Laurent@814: def SaveProjectAs(self): Laurent@814: filepath = self.Controler.GetFilePath() Laurent@814: if filepath != "": Laurent@814: directory, filename = os.path.split(filepath) Laurent@814: else: Laurent@814: directory, filename = os.getcwd(), "%(projectName)s.xml"%self.Controler.GetProjectProperties() Laurent@814: dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: filepath = dialog.GetPath() Laurent@814: if os.path.isdir(os.path.dirname(filepath)): Laurent@814: result = self.Controler.SaveXMLFile(filepath) Laurent@814: if not result: Laurent@814: self.ShowErrorMessage(_("Can't save project to file %s!")%filepath) Laurent@814: else: Laurent@814: self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath)) Laurent@814: self._Refresh(TITLE, FILEMENU, PAGETITLES) Laurent@814: dialog.Destroy() Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # Exception Handler Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: Max_Traceback_List_Size = 20 Laurent@814: Laurent@814: def Display_Exception_Dialog(e_type,e_value,e_tb): Laurent@814: trcbck_lst = [] Laurent@814: for i,line in enumerate(traceback.extract_tb(e_tb)): Laurent@814: trcbck = " " + str(i+1) + _(". ") Laurent@814: if line[0].find(os.getcwd()) == -1: Laurent@814: trcbck += _("file : ") + str(line[0]) + _(", ") Laurent@814: else: Laurent@814: trcbck += _("file : ") + str(line[0][len(os.getcwd()):]) + _(", ") Laurent@814: trcbck += _("line : ") + str(line[1]) + _(", ") + _("function : ") + str(line[2]) Laurent@814: trcbck_lst.append(trcbck) Edouard@1451: Laurent@814: # Allow clicking.... Laurent@814: cap = wx.Window_GetCapture() Laurent@814: if cap: Laurent@814: cap.ReleaseMouse() Laurent@814: Edouard@1451: dlg = wx.SingleChoiceDialog(None, Laurent@814: _(""" andrej@1580: An unhandled exception (bug) occured. Bug report saved at : andrej@1580: (%s) Laurent@814: Laurent@814: Please be kind enough to send this file to: andrej@1580: beremiz-devel@lists.sourceforge.net andrej@1580: andrej@1580: You should now restart program. andrej@1580: andrej@1580: Traceback: andrej@1580: """) % bug_report_path + andrej@1580: repr(e_type) + " : " + repr(e_value), Laurent@814: _("Error"), Laurent@814: trcbck_lst) Laurent@814: try: Laurent@814: res = (dlg.ShowModal() == wx.ID_OK) Laurent@814: finally: Laurent@814: dlg.Destroy() Laurent@814: Laurent@814: return res Laurent@814: Laurent@814: def Display_Error_Dialog(e_value): Laurent@814: message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_ERROR) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: Laurent@814: def get_last_traceback(tb): Laurent@814: while tb.tb_next: Laurent@814: tb = tb.tb_next Laurent@814: return tb Laurent@814: Laurent@814: Laurent@814: def format_namespace(d, indent=' '): Laurent@814: return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()]) Laurent@814: Laurent@814: Laurent@814: ignored_exceptions = [] # a problem with a line in a module is only reported once per session Laurent@814: Laurent@814: def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]): Edouard@1451: Laurent@814: def handle_exception(e_type, e_value, e_traceback): Laurent@814: traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func Laurent@814: last_tb = get_last_traceback(e_traceback) Laurent@814: ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno) Laurent@814: if str(e_value).startswith("!!!"): Laurent@814: Display_Error_Dialog(e_value) Laurent@814: elif ex not in ignored_exceptions: Laurent@814: result = Display_Exception_Dialog(e_type,e_value,e_traceback) Laurent@814: if result: Laurent@814: ignored_exceptions.append(ex) Laurent@814: info = { Laurent@814: 'app-title' : wx.GetApp().GetAppName(), # app_title Laurent@814: 'app-version' : app_version, Laurent@814: 'wx-version' : wx.VERSION_STRING, Laurent@814: 'wx-platform' : wx.Platform, Laurent@814: 'python-version' : platform.python_version(), #sys.version.split()[0], Laurent@814: 'platform' : platform.platform(), Laurent@814: 'e-type' : e_type, Laurent@814: 'e-value' : e_value, Laurent@814: 'date' : time.ctime(), Laurent@814: 'cwd' : os.getcwd(), Laurent@814: } Laurent@814: if e_traceback: Laurent@814: info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value) Laurent@814: last_tb = get_last_traceback(e_traceback) Laurent@814: exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred Laurent@814: info['locals'] = format_namespace(exception_locals) Laurent@814: if 'self' in exception_locals: Laurent@814: info['self'] = format_namespace(exception_locals['self'].__dict__) Edouard@1451: Laurent@814: output = open(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w') Laurent@814: lst = info.keys() Laurent@814: lst.sort() Laurent@814: for a in lst: Laurent@814: output.write(a+":\n"+str(info[a])+"\n\n") Laurent@814: Laurent@814: #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args) Laurent@814: sys.excepthook = handle_exception Laurent@814: Laurent@814: if __name__ == '__main__': andrej@1533: if wx.VERSION < (3, 0, 0): andrej@1533: wx.InitAllImageHandlers() Edouard@1451: Laurent@814: # Install a exception handle for bug reports andrej@1560: AddExceptHook(os.getcwd(), version.app_version) Edouard@1451: Laurent@814: frame = PLCOpenEditor(None, fileOpen=fileOpen) Laurent@814: Laurent@814: frame.Show() Laurent@814: app.MainLoop() Edouard@1451: