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