diff -r 1460273f40ed -r 5743cbdff669 PLCOpenEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PLCOpenEditor.py Fri Sep 07 16:45:55 2012 +0200 @@ -0,0 +1,608 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#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 wx +import os, sys, platform, time, traceback, getopt + +CWD = os.path.split(os.path.realpath(__file__))[0] + +from util.BitmapLibrary import AddBitmapFolder, GetBitmap +AddBitmapFolder(os.path.join(CWD, "images")) + +from docutil import * + +__version__ = "$Revision: 1.130 $" + +if __name__ == '__main__': + # Usage message displayed when help request or when error detected in + # command line + def usage(): + print "\nUsage of PLCOpenEditor.py :" + print "\n %s [Filepath]\n"%sys.argv[0] + + # Parse options given to PLCOpenEditor in command line + try: + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) + except getopt.GetoptError: + # print help information and exit: + usage() + sys.exit(2) + + # Extract if help has been requested + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + + # Extract the optional filename to open + fileOpen = None + if len(args) > 1: + usage() + sys.exit() + elif len(args) == 1: + fileOpen = args[0] + + # Create wxApp (Need to create App before internationalization because of + # Windows) + app = wx.PySimpleApp() + +# Import module for internationalization +import gettext +import __builtin__ + +# Get folder containing translation files +localedir = os.path.join(CWD,"locale") +# Get the default language +langid = wx.LANGUAGE_DEFAULT +# Define translation domain (name of translation files) +domain = "Beremiz" + +# Define locale for wx +loc = __builtin__.__dict__.get('loc', None) +if loc is None: + test_loc = wx.Locale(langid) + test_loc.AddCatalogLookupPathPrefix(localedir) + if test_loc.AddCatalog(domain): + loc = wx.Locale(langid) + else: + loc = wx.Locale(wx.LANGUAGE_ENGLISH) + __builtin__.__dict__['loc'] = loc +# Define location for searching translation files +loc.AddCatalogLookupPathPrefix(localedir) +# Define locale domain +loc.AddCatalog(domain) + +if __name__ == '__main__': + __builtin__.__dict__['_'] = wx.GetTranslation + +from IDEFrame import IDEFrame, AppendMenu +from IDEFrame import TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, PAGETITLES +from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath +from editors.Viewer import Viewer +from PLCControler import PLCControler + +#------------------------------------------------------------------------------- +# PLCOpenEditor Main Class +#------------------------------------------------------------------------------- + +# Define PLCOpenEditor FileMenu extra items id +[ID_PLCOPENEDITORFILEMENUGENERATE, +] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)] + +class PLCOpenEditor(IDEFrame): + + # Compatibility function for wx versions < 2.6 + if wx.VERSION < (2, 6, 0): + def Bind(self, event, function, id = None): + if id is not None: + event(self, id, function) + else: + event(self, function) + + 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') + 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') + 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, + kind=wx.ITEM_NORMAL, text=_(u'Save As...') + '\tCTRL+SHIFT+S') + AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE, + kind=wx.ITEM_NORMAL, text=_(u'Generate Program') + '\tCTRL+G') + parent.AppendSeparator() + 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') + parent.AppendSeparator() + AppendMenu(parent, help='', id=wx.ID_PROPERTIES, + kind=wx.ITEM_NORMAL, text=_(u'&Properties')) + parent.AppendSeparator() + 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.OnCloseTabMenu, id=wx.ID_CLOSE) + self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) + 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.OnGenerateProgramMenu, + id=ID_PLCOPENEDITORFILEMENUGENERATE) + 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.OnPropertiesMenu, id=wx.ID_PROPERTIES) + 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_HelpMenu_Items(self, parent): + AppendMenu(parent, help='', id=wx.ID_HELP, + kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor') + '\tF1') + #AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS, + # kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2') + #AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT, + # kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3') + AppendMenu(parent, help='', id=wx.ID_ABOUT, + kind=wx.ITEM_NORMAL, text=_(u'About')) + self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP) + #self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS) + self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) + + ## Constructor of the PLCOpenEditor class. + # @param parent The parent window. + # @param controler The controler been used by PLCOpenEditor (default: None). + # @param fileOpen The filepath to open if no controler defined (default: None). + # @param debug The filepath to open if no controler defined (default: False). + def __init__(self, parent, fileOpen = None): + IDEFrame.__init__(self, parent) + + result = None + + # Open the filepath if defined + if fileOpen is not None: + fileOpen = DecodeFileSystemPath(fileOpen, False) + if os.path.isfile(fileOpen): + # Create a new controller + controler = PLCControler() + result = controler.OpenXMLFile(fileOpen) + if result is None: + self.Controler = controler + self.LibraryPanel.SetController(controler) + self.ProjectTree.Enable(True) + self.PouInstanceVariablesPanel.SetController(controler) + self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) + + # Define PLCOpenEditor icon + self.SetIcon(wx.Icon(os.path.join(CWD, "images", "poe.ico"),wx.BITMAP_TYPE_ICO)) + + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) + + if result is not None: + self.ShowErrorMessage(result) + + def OnCloseFrame(self, event): + if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")): + self.AUIManager.UnInit() + + self.SaveLastState() + + event.Skip() + else: + event.Veto() + + def RefreshTitle(self): + name = _("PLCOpenEditor") + if self.Controler is not None: + self.SetTitle("%s - %s"%(name, self.Controler.GetFilename())) + else: + self.SetTitle(name) + +#------------------------------------------------------------------------------- +# File Menu Functions +#------------------------------------------------------------------------------- + + def RefreshFileMenu(self): + MenuToolBar = self.Panes["MenuToolBar"] + if self.Controler is not None: + selected = self.TabsOpened.GetSelection() + if selected >= 0: + graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) + else: + graphic_viewer = False + if self.TabsOpened.GetPageCount() > 0: + self.FileMenu.Enable(wx.ID_CLOSE, True) + if graphic_viewer: + self.FileMenu.Enable(wx.ID_PREVIEW, True) + self.FileMenu.Enable(wx.ID_PRINT, True) + MenuToolBar.EnableTool(wx.ID_PRINT, True) + else: + self.FileMenu.Enable(wx.ID_PREVIEW, False) + self.FileMenu.Enable(wx.ID_PRINT, False) + MenuToolBar.EnableTool(wx.ID_PRINT, False) + else: + 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 = not self.Controler.ProjectIsSaved() + self.FileMenu.Enable(wx.ID_SAVE, project_modified) + MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) + self.FileMenu.Enable(wx.ID_PROPERTIES, True) + self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) + self.FileMenu.Enable(wx.ID_SAVEAS, True) + MenuToolBar.EnableTool(wx.ID_SAVEAS, True) + self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, True) + else: + 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_PROPERTIES, False) + self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) + self.FileMenu.Enable(wx.ID_SAVEAS, False) + MenuToolBar.EnableTool(wx.ID_SAVEAS, False) + self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, False) + + def OnNewProjectMenu(self, event): + if self.Controler is not None and not self.CheckSaveBeforeClosing(): + return + dialog = ProjectDialog(self) + if dialog.ShowModal() == wx.ID_OK: + properties = dialog.GetValues() + self.ResetView() + self.Controler = PLCControler() + self.Controler.CreateNewProject(properties) + self.LibraryPanel.SetController(self.Controler) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, + LIBRARYTREE) + + def OnOpenProjectMenu(self, event): + if self.Controler is not None and not self.CheckSaveBeforeClosing(): + return + filepath = "" + if self.Controler is not None: + filepath = self.Controler.GetFilePath() + if filepath != "": + directory = os.path.dirname(filepath) + else: + directory = os.getcwd() + + result = None + + dialog = wx.FileDialog(self, _("Choose a file"), directory, "", _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.OPEN) + if dialog.ShowModal() == wx.ID_OK: + filepath = dialog.GetPath() + if os.path.isfile(filepath): + self.ResetView() + controler = PLCControler() + result = controler.OpenXMLFile(filepath) + if result is None: + self.Controler = controler + self.LibraryPanel.SetController(controler) + self.ProjectTree.Enable(True) + self.PouInstanceVariablesPanel.SetController(controler) + self.LoadProjectLayout() + self._Refresh(PROJECTTREE, LIBRARYTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) + dialog.Destroy() + + if result is not None: + self.ShowErrorMessage(result) + + def OnCloseProjectMenu(self, event): + if not self.CheckSaveBeforeClosing(): + return + self.SaveProjectLayout() + self.ResetView() + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) + + def OnSaveProjectMenu(self, event): + self.SaveProject() + + def OnSaveProjectAsMenu(self, event): + self.SaveProjectAs() + + def OnGenerateProgramMenu(self, event): + dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE|wx.CHANGE_DIR) + if dialog.ShowModal() == wx.ID_OK: + filepath = dialog.GetPath() + message_text = "" + header, icon = _("Done"), wx.ICON_INFORMATION + if os.path.isdir(os.path.dirname(filepath)): + program, errors, warnings = self.Controler.GenerateProgram(filepath) + message_text += "".join([_("warning: %s\n") for warning in warnings]) + if len(errors) > 0: + message_text += "".join([_("error: %s\n") for error in errors]) + message_text += _("Can't generate program to file %s!")%filepath + header, icon = _("Error"), wx.ICON_ERROR + else: + message_text += _("Program was successfully generated!") + else: + message_text += _("\"%s\" is not a valid folder!")%os.path.dirname(filepath) + header, icon = _("Error"), wx.ICON_ERROR + message = wx.MessageDialog(self, message_text, header, wx.OK|icon) + message.ShowModal() + message.Destroy() + dialog.Destroy() + + def OnPLCOpenEditorMenu(self, event): + wx.MessageBox(_("No documentation available.\nComing soon.")) + + def OnPLCOpenMenu(self, event): + open_pdf(os.path.join(CWD, "plcopen", "TC6_XML_V101.pdf")) + + def OnAboutMenu(self, event): + OpenHtmlFrame(self,_("About PLCOpenEditor"), os.path.join(CWD, "doc", "plcopen_about.html"), wx.Size(350, 350)) + + def SaveProject(self): + result = self.Controler.SaveXMLFile() + if not result: + self.SaveProjectAs() + else: + self._Refresh(TITLE, FILEMENU, PAGETITLES) + + def SaveProjectAs(self): + filepath = self.Controler.GetFilePath() + if filepath != "": + directory, filename = os.path.split(filepath) + else: + directory, filename = os.getcwd(), "%(projectName)s.xml"%self.Controler.GetProjectProperties() + dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT) + if dialog.ShowModal() == wx.ID_OK: + filepath = dialog.GetPath() + if os.path.isdir(os.path.dirname(filepath)): + result = self.Controler.SaveXMLFile(filepath) + if not result: + self.ShowErrorMessage(_("Can't save project to file %s!")%filepath) + else: + self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath)) + self._Refresh(TITLE, FILEMENU, PAGETITLES) + dialog.Destroy() + +#------------------------------------------------------------------------------- +# Debug Variables Panel +#------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------- +# Viewer Printout +#------------------------------------------------------------------------------- + +UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0] + +class GraphicPrintout(wx.Printout): + def __init__(self, viewer, page_size, margins, preview = False): + wx.Printout.__init__(self) + self.Viewer = viewer + self.PageSize = page_size + if self.PageSize[0] == 0 or self.PageSize[1] == 0: + self.PageSize = (1050, 1485) + self.Preview = preview + self.Margins = margins + self.FontSize = 5 + self.TextMargin = 3 + + maxx, maxy = viewer.GetMaxSize() + self.PageGrid = (UPPER_DIV(maxx, self.PageSize[0]), + UPPER_DIV(maxy, self.PageSize[1])) + + def GetPageNumber(self): + return self.PageGrid[0] * self.PageGrid[1] + + def HasPage(self, page): + return page <= self.GetPageNumber() + + def GetPageInfo(self): + page_number = self.GetPageNumber() + return (1, page_number, 1, page_number) + + def OnBeginDocument(self, startPage, endPage): + dc = self.GetDC() + if not self.Preview and isinstance(dc, wx.PostScriptDC): + dc.SetResolution(720) + super(GraphicPrintout, self).OnBeginDocument(startPage, endPage) + + def OnPrintPage(self, page): + dc = self.GetDC() + dc.SetUserScale(1.0, 1.0) + dc.SetDeviceOrigin(0, 0) + dc.printing = not self.Preview + + # Get the size of the DC in pixels + ppiPrinterX, ppiPrinterY = self.GetPPIPrinter() + ppiScreenX, ppiScreenY = self.GetPPIScreen() + pw, ph = self.GetPageSizePixels() + dw, dh = dc.GetSizeTuple() + Xscale = (float(dw) * float(ppiPrinterX)) / (float(pw) * 25.4) + Yscale = (float(dh) * float(ppiPrinterY)) / (float(ph) * 25.4) + + fontsize = self.FontSize * Yscale + text_margin = self.TextMargin * Yscale + + margin_left = self.Margins[0].x * Xscale + margin_top = self.Margins[0].y * Yscale + area_width = dw - self.Margins[1].x * Xscale - margin_left + area_height = dh - self.Margins[1].y * Yscale - margin_top + + dc.SetPen(MiterPen(wx.BLACK)) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.DrawRectangle(margin_left, margin_top, area_width, area_height) + + dc.SetFont(wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) + dc.SetTextForeground(wx.BLACK) + block_name = " - ".join(self.Viewer.GetTagName().split("::")[1:]) + text_width, text_height = dc.GetTextExtent(block_name) + dc.DrawText(block_name, margin_left, margin_top - text_height - self.TextMargin) + dc.DrawText(_("Page: %d") % page, margin_left, margin_top + area_height + self.TextMargin) + + # Calculate the position on the DC for centering the graphic + posX = area_width * ((page - 1) % self.PageGrid[0]) + posY = area_height * ((page - 1) / self.PageGrid[0]) + + scaleX = float(area_width) / float(self.PageSize[0]) + scaleY = float(area_height) / float(self.PageSize[1]) + scale = min(scaleX, scaleY) + + # Set the scale and origin + dc.SetDeviceOrigin(-posX + margin_left, -posY + margin_top) + dc.SetClippingRegion(posX, posY, self.PageSize[0] * scale, self.PageSize[1] * scale) + dc.SetUserScale(scale, scale) + + #------------------------------------------- + + self.Viewer.DoDrawing(dc, True) + + return True + +#------------------------------------------------------------------------------- +# Exception Handler +#------------------------------------------------------------------------------- + +Max_Traceback_List_Size = 20 + +def Display_Exception_Dialog(e_type,e_value,e_tb): + trcbck_lst = [] + 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]) + _(", ") + else: + trcbck += _("file : ") + str(line[0][len(os.getcwd()):]) + _(", ") + trcbck += _("line : ") + str(line[1]) + _(", ") + _("function : ") + str(line[2]) + trcbck_lst.append(trcbck) + + # Allow clicking.... + cap = wx.Window_GetCapture() + if cap: + cap.ReleaseMouse() + + dlg = wx.SingleChoiceDialog(None, + _(""" +An error has occurred. + +Click OK to save an error report. + +Please be kind enough to send this file to: +edouard.tisserant@gmail.com + +Error: +""") + + str(e_type) + _(" : ") + str(e_value), + _("Error"), + trcbck_lst) + try: + res = (dlg.ShowModal() == wx.ID_OK) + finally: + dlg.Destroy() + + return res + +def Display_Error_Dialog(e_value): + message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + +def get_last_traceback(tb): + while tb.tb_next: + tb = tb.tb_next + return 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 str(e_value).startswith("!!!"): + Display_Error_Dialog(e_value) + elif ex not in ignored_exceptions: + result = Display_Exception_Dialog(e_type,e_value,e_traceback) + if result: + ignored_exceptions.append(ex) + info = { + '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(), + 'e-type' : e_type, + 'e-value' : e_value, + 'date' : time.ctime(), + 'cwd' : os.getcwd(), + } + if e_traceback: + 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(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w') + lst = info.keys() + lst.sort() + for a in lst: + 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__': + wx.InitAllImageHandlers() + + # Install a exception handle for bug reports + AddExceptHook(os.getcwd(),__version__) + + frame = PLCOpenEditor(None, fileOpen=fileOpen) + + frame.Show() + app.MainLoop() +