andrej@1662: #!/usr/bin/env python andrej@1662: # -*- coding: utf-8 -*- andrej@1662: andrej@1662: # This file is part of Beremiz, a Integrated Development Environment for andrej@1662: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1662: # andrej@1662: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1662: # Copyright (C) 2016: Andrey Skvortsov andrej@1662: # andrej@1662: # See COPYING file for copyrights details. andrej@1662: # andrej@1662: # This program is free software; you can redistribute it and/or andrej@1662: # modify it under the terms of the GNU General Public License andrej@1662: # as published by the Free Software Foundation; either version 2 andrej@1662: # of the License, or (at your option) any later version. andrej@1662: # andrej@1662: # This program is distributed in the hope that it will be useful, andrej@1662: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1662: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1662: # GNU General Public License for more details. andrej@1662: # andrej@1662: # You should have received a copy of the GNU General Public License andrej@1662: # along with this program; if not, write to the Free Software andrej@1662: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1662: andrej@1662: andrej@1662: import os, sys andrej@1662: import tempfile andrej@1662: import shutil andrej@1662: import random andrej@1662: import time andrej@1662: import version andrej@1680: import util.paths as paths andrej@1662: from types import ListType andrej@1662: andrej@1680: beremiz_dir = paths.AbsDir(__file__) andrej@1662: andrej@1662: def Bpath(*args): andrej@1662: return os.path.join(beremiz_dir,*args) andrej@1662: andrej@1662: andrej@1662: andrej@1662: import wx.lib.buttons, wx.lib.statbmp, wx.stc andrej@1662: import cPickle andrej@1662: import types, time, re, platform, time, traceback, commands andrej@1662: andrej@1662: from docutil import OpenHtmlFrame andrej@1662: from editors.EditorPanel import EditorPanel andrej@1662: from editors.Viewer import Viewer andrej@1662: from editors.TextViewer import TextViewer andrej@1662: from editors.ResourceEditor import ConfigurationEditor, ResourceEditor andrej@1662: from editors.DataTypeEditor import DataTypeEditor andrej@1662: from util.MiniTextControler import MiniTextControler andrej@1662: from util.ProcessLogger import ProcessLogger andrej@1662: from controls.LogViewer import LogViewer andrej@1662: from controls.CustomStyledTextCtrl import CustomStyledTextCtrl andrej@1662: from controls import EnhancedStatusBar as esb andrej@1662: from dialogs.AboutDialog import ShowAboutDialog andrej@1662: andrej@1662: from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY, ITEM_PROJECT, ITEM_RESOURCE andrej@1662: from ProjectController import ProjectController, GetAddMenuItems, MATIEC_ERROR_MODEL, ITEM_CONFNODE andrej@1662: andrej@1662: andrej@1662: MAX_RECENT_PROJECTS = 9 andrej@1662: andrej@1662: if wx.Platform == '__WXMSW__': andrej@1662: faces = { andrej@1662: 'mono' : 'Courier New', andrej@1662: 'size' : 8, andrej@1662: } andrej@1662: else: andrej@1662: faces = { andrej@1662: 'mono' : 'Courier', andrej@1662: 'size' : 10, andrej@1662: } andrej@1662: andrej@1662: from threading import Lock,Timer,currentThread andrej@1662: MainThread = currentThread().ident andrej@1662: REFRESH_PERIOD = 0.1 andrej@1662: from time import time as gettime andrej@1662: class LogPseudoFile: andrej@1662: """ Base class for file like objects to facilitate StdOut for the Shell.""" andrej@1662: def __init__(self, output, risecall): andrej@1662: self.red_white = 1 andrej@1662: self.red_yellow = 2 andrej@1662: self.black_white = wx.stc.STC_STYLE_DEFAULT andrej@1662: self.output = output andrej@1662: self.risecall = risecall andrej@1662: # to prevent rapid fire on rising log panel andrej@1662: self.rising_timer = 0 andrej@1662: self.lock = Lock() andrej@1662: self.YieldLock = Lock() andrej@1662: self.RefreshLock = Lock() andrej@1662: self.TimerAccessLock = Lock() andrej@1662: self.stack = [] andrej@1662: self.LastRefreshTime = gettime() andrej@1662: self.LastRefreshTimer = None andrej@1662: andrej@1662: def write(self, s, style = None): andrej@1662: if self.lock.acquire(): andrej@1662: self.stack.append((s,style)) andrej@1662: self.lock.release() andrej@1662: current_time = gettime() andrej@1662: self.TimerAccessLock.acquire() andrej@1662: if self.LastRefreshTimer: andrej@1662: self.LastRefreshTimer.cancel() andrej@1662: self.LastRefreshTimer=None andrej@1662: self.TimerAccessLock.release() andrej@1662: if current_time - self.LastRefreshTime > REFRESH_PERIOD and self.RefreshLock.acquire(False): andrej@1662: self._should_write() andrej@1662: else: andrej@1662: self.TimerAccessLock.acquire() andrej@1662: self.LastRefreshTimer = Timer(REFRESH_PERIOD, self._timer_expired) andrej@1662: self.LastRefreshTimer.start() andrej@1662: self.TimerAccessLock.release() andrej@1662: andrej@1662: def _timer_expired(self): andrej@1662: if self.RefreshLock.acquire(False): andrej@1662: self._should_write() andrej@1662: else: andrej@1662: self.TimerAccessLock.acquire() andrej@1662: self.LastRefreshTimer = Timer(REFRESH_PERIOD, self._timer_expired) andrej@1662: self.LastRefreshTimer.start() andrej@1662: self.TimerAccessLock.release() andrej@1662: andrej@1662: def _should_write(self): andrej@1662: wx.CallAfter(self._write) andrej@1662: if MainThread == currentThread().ident: andrej@1662: app = wx.GetApp() andrej@1662: if app is not None: andrej@1662: if self.YieldLock.acquire(0): andrej@1662: app.Yield() andrej@1662: self.YieldLock.release() andrej@1662: andrej@1662: def _write(self): andrej@1662: if self.output : andrej@1662: self.output.Freeze() andrej@1662: self.lock.acquire() andrej@1662: for s, style in self.stack: andrej@1662: if style is None : style=self.black_white andrej@1662: if style != self.black_white: andrej@1662: self.output.StartStyling(self.output.GetLength(), 0xff) andrej@1662: andrej@1662: # Temporary deactivate read only mode on StyledTextCtrl for andrej@1662: # adding text. It seems that text modifications, even andrej@1662: # programmatically, are disabled in StyledTextCtrl when read andrej@1662: # only is active andrej@1662: start_pos = self.output.GetLength() andrej@1662: self.output.SetReadOnly(False) andrej@1662: self.output.AppendText(s) andrej@1662: self.output.SetReadOnly(True) andrej@1662: text_len = self.output.GetLength() - start_pos andrej@1662: andrej@1662: if style != self.black_white: andrej@1662: self.output.SetStyling(text_len, style) andrej@1662: self.stack = [] andrej@1662: self.lock.release() andrej@1662: self.output.Thaw() andrej@1662: self.LastRefreshTime = gettime() andrej@1662: try: andrej@1662: self.RefreshLock.release() andrej@1662: except: andrej@1662: pass andrej@1662: newtime = time.time() andrej@1662: if newtime - self.rising_timer > 1: andrej@1662: self.risecall(self.output) andrej@1662: self.rising_timer = newtime andrej@1662: andrej@1662: def write_warning(self, s): andrej@1662: self.write(s,self.red_white) andrej@1662: andrej@1662: def write_error(self, s): andrej@1662: self.write(s,self.red_yellow) andrej@1662: andrej@1662: def writeyield(self, s): andrej@1662: self.write(s) andrej@1662: wx.GetApp().Yield() andrej@1662: andrej@1662: def flush(self): andrej@1662: # Temporary deactivate read only mode on StyledTextCtrl for clearing andrej@1662: # text. It seems that text modifications, even programmatically, are andrej@1662: # disabled in StyledTextCtrl when read only is active andrej@1662: self.output.SetReadOnly(False) andrej@1662: self.output.SetText("") andrej@1662: self.output.SetReadOnly(True) andrej@1662: andrej@1662: def isatty(self): andrej@1662: return False andrej@1662: andrej@1662: ID_FILEMENURECENTPROJECTS = wx.NewId() andrej@1662: andrej@1662: from IDEFrame import TITLE,\ andrej@1662: EDITORTOOLBAR,\ andrej@1662: FILEMENU,\ andrej@1662: EDITMENU,\ andrej@1662: DISPLAYMENU,\ andrej@1662: PROJECTTREE,\ andrej@1662: POUINSTANCEVARIABLESPANEL,\ andrej@1662: LIBRARYTREE,\ andrej@1662: SCALING,\ andrej@1662: PAGETITLES,\ andrej@1662: IDEFrame, AppendMenu,\ andrej@1662: EncodeFileSystemPath, DecodeFileSystemPath andrej@1662: from util.BitmapLibrary import GetBitmap andrej@1662: andrej@1662: class Beremiz(IDEFrame): andrej@1662: andrej@1662: def _init_utils(self): andrej@1662: self.ConfNodeMenu = wx.Menu(title='') andrej@1662: self.RecentProjectsMenu = wx.Menu(title='') andrej@1662: andrej@1662: IDEFrame._init_utils(self) andrej@1662: andrej@1662: def _init_coll_FileMenu_Items(self, parent): andrej@1662: AppendMenu(parent, help='', id=wx.ID_NEW, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N') andrej@1662: AppendMenu(parent, help='', id=wx.ID_OPEN, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O') andrej@1662: parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu) andrej@1662: parent.AppendSeparator() andrej@1662: AppendMenu(parent, help='', id=wx.ID_SAVE, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S') andrej@1662: AppendMenu(parent, help='', id=wx.ID_SAVEAS, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Save as') + '\tCTRL+SHIFT+S') andrej@1662: AppendMenu(parent, help='', id=wx.ID_CLOSE, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W') andrej@1662: AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W') andrej@1662: parent.AppendSeparator() andrej@1662: AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P') andrej@1662: AppendMenu(parent, help='', id=wx.ID_PREVIEW, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P') andrej@1662: AppendMenu(parent, help='', id=wx.ID_PRINT, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P') andrej@1662: parent.AppendSeparator() andrej@1662: AppendMenu(parent, help='', id=wx.ID_EXIT, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q') andrej@1662: andrej@1662: self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) andrej@1662: self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) andrej@1662: self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) andrej@1662: self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) andrej@1662: self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE) andrej@1662: self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) andrej@1662: self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP) andrej@1662: self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW) andrej@1662: self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT) andrej@1662: self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT) andrej@1662: andrej@1662: self.AddToMenuToolBar([(wx.ID_NEW, "new", _(u'New'), None), andrej@1662: (wx.ID_OPEN, "open", _(u'Open'), None), andrej@1662: (wx.ID_SAVE, "save", _(u'Save'), None), andrej@1662: (wx.ID_SAVEAS, "saveas", _(u'Save As...'), None), andrej@1662: (wx.ID_PRINT, "print", _(u'Print'), None)]) andrej@1662: andrej@1662: def _RecursiveAddMenuItems(self, menu, items): andrej@1662: for name, text, help, children in items: andrej@1662: new_id = wx.NewId() andrej@1662: if len(children) > 0: andrej@1662: new_menu = wx.Menu(title='') andrej@1662: menu.AppendMenu(new_id, text, new_menu) andrej@1662: self._RecursiveAddMenuItems(new_menu, children) andrej@1662: else: andrej@1662: AppendMenu(menu, help=help, id=new_id, andrej@1662: kind=wx.ITEM_NORMAL, text=text) andrej@1662: self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), andrej@1662: id=new_id) andrej@1662: andrej@1662: def _init_coll_AddMenu_Items(self, parent): andrej@1662: IDEFrame._init_coll_AddMenu_Items(self, parent, False) andrej@1662: self._RecursiveAddMenuItems(parent, GetAddMenuItems()) andrej@1662: andrej@1662: def _init_coll_HelpMenu_Items(self, parent): andrej@1662: parent.Append(help='', id=wx.ID_ABOUT, andrej@1662: kind=wx.ITEM_NORMAL, text=_(u'About')) andrej@1662: self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) andrej@1662: andrej@1662: def _init_coll_ConnectionStatusBar_Fields(self, parent): andrej@1662: parent.SetFieldsCount(3) andrej@1662: andrej@1662: parent.SetStatusText(number=0, text='') andrej@1662: parent.SetStatusText(number=1, text='') andrej@1662: parent.SetStatusText(number=2, text='') andrej@1662: andrej@1662: parent.SetStatusWidths([-1, 300, 200]) andrej@1662: andrej@1662: def _init_ctrls(self, prnt): andrej@1662: IDEFrame._init_ctrls(self, prnt) andrej@1662: andrej@1662: self.EditMenuSize = self.EditMenu.GetMenuItemCount() andrej@1662: andrej@1662: inspectorID = wx.NewId() andrej@1662: self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID) andrej@1662: accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), inspectorID)] andrej@1662: andrej@1662: keyID = wx.NewId() andrej@1662: self.Bind(wx.EVT_MENU, self.SwitchFullScrMode, id=keyID) andrej@1662: accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_F12, keyID)] andrej@1662: andrej@1662: for method,shortcut in [("Stop", wx.WXK_F4), andrej@1662: ("Run", wx.WXK_F5), andrej@1662: ("Transfer", wx.WXK_F6), andrej@1662: ("Connect", wx.WXK_F7), andrej@1662: ("Build", wx.WXK_F11)]: andrej@1662: def OnMethodGen(obj,meth): andrej@1662: def OnMethod(evt): andrej@1662: if obj.CTR is not None: andrej@1662: obj.CTR.CallMethod('_'+meth) andrej@1662: wx.CallAfter(self.RefreshStatusToolBar) andrej@1662: return OnMethod andrej@1662: newid = wx.NewId() andrej@1662: self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid) andrej@1662: accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)] andrej@1662: andrej@1662: self.SetAcceleratorTable(wx.AcceleratorTable(accels)) andrej@1662: andrej@1662: self.LogConsole = CustomStyledTextCtrl( andrej@1662: name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0), andrej@1662: size=wx.Size(0, 0)) andrej@1662: self.LogConsole.Bind(wx.EVT_SET_FOCUS, self.OnLogConsoleFocusChanged) andrej@1662: self.LogConsole.Bind(wx.EVT_KILL_FOCUS, self.OnLogConsoleFocusChanged) andrej@1662: self.LogConsole.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnLogConsoleUpdateUI) andrej@1662: self.LogConsole.SetReadOnly(True) andrej@1662: self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR) andrej@1662: andrej@1662: # Define Log Console styles andrej@1662: self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) andrej@1662: self.LogConsole.StyleClearAll() andrej@1662: self.LogConsole.StyleSetSpec(1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces) andrej@1662: self.LogConsole.StyleSetSpec(2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) andrej@1662: andrej@1662: # Define Log Console markers andrej@1662: self.LogConsole.SetMarginSensitive(1, True) andrej@1662: self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) andrej@1662: self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") andrej@1662: andrej@1662: self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) andrej@1662: andrej@1662: self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) andrej@1662: self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) andrej@1662: andrej@1662: self.MainTabs["LogConsole"] = (self.LogConsole, _("Console")) andrej@1662: self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"]) andrej@1662: #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT) andrej@1662: andrej@1662: self.LogViewer = LogViewer(self.BottomNoteBook, self) andrej@1662: self.MainTabs["LogViewer"] = (self.LogViewer, _("PLC Log")) andrej@1662: self.BottomNoteBook.AddPage(*self.MainTabs["LogViewer"]) andrej@1662: #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT) andrej@1662: andrej@1662: StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, andrej@1662: wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) andrej@1662: StatusToolBar.SetToolBitmapSize(wx.Size(25, 25)) andrej@1662: StatusToolBar.Realize() andrej@1662: self.Panes["StatusToolBar"] = StatusToolBar andrej@1662: self.AUIManager.AddPane(StatusToolBar, wx.aui.AuiPaneInfo(). andrej@1662: Name("StatusToolBar").Caption(_("Status ToolBar")). andrej@1662: ToolbarPane().Top().Position(1). andrej@1662: LeftDockable(False).RightDockable(False)) andrej@1662: andrej@1662: self.AUIManager.Update() andrej@1662: andrej@1662: self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.ST_SIZEGRIP) andrej@1662: self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) andrej@1662: self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range = 100) andrej@1662: self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2) andrej@1662: self.ProgressStatusBar.Hide() andrej@1662: self.SetStatusBar(self.ConnectionStatusBar) andrej@1662: andrej@1662: def __init_execute_path(self): andrej@1662: if os.name == 'nt': andrej@1662: # on windows, desktop shortcut launches Beremiz.py andrej@1662: # with working dir set to mingw/bin. andrej@1662: # then we prefix CWD to PATH in order to ensure that andrej@1662: # commands invoked by build process by default are andrej@1662: # found here. andrej@1662: os.environ["PATH"] = os.getcwd()+';'+os.environ["PATH"] andrej@1662: andrej@1662: andrej@1662: def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): andrej@1662: # Add beremiz's icon in top left corner of the frame andrej@1662: self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO) andrej@1662: self.__init_execute_path() andrej@1662: andrej@1662: IDEFrame.__init__(self, parent, debug) andrej@1662: self.Log = LogPseudoFile(self.LogConsole,self.SelectTab) andrej@1662: andrej@1662: self.local_runtime = None andrej@1662: self.runtime_port = None andrej@1662: self.local_runtime_tmpdir = None andrej@1662: andrej@1662: self.LastPanelSelected = None andrej@1662: andrej@1662: # Define Tree item icon list andrej@1662: self.LocationImageList = wx.ImageList(16, 16) andrej@1662: self.LocationImageDict = {} andrej@1662: andrej@1662: # Icons for location items andrej@1662: for imgname, itemtype in [ andrej@1662: ("CONFIGURATION", LOCATION_CONFNODE), andrej@1662: ("RESOURCE", LOCATION_MODULE), andrej@1662: ("PROGRAM", LOCATION_GROUP), andrej@1662: ("VAR_INPUT", LOCATION_VAR_INPUT), andrej@1662: ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), andrej@1662: ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: andrej@1662: self.LocationImageDict[itemtype] = self.LocationImageList.Add(GetBitmap(imgname)) andrej@1662: andrej@1662: # Icons for other items andrej@1662: for imgname, itemtype in [ andrej@1662: ("Extension", ITEM_CONFNODE)]: andrej@1662: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname)) andrej@1662: andrej@1662: if projectOpen is not None: andrej@1662: projectOpen = DecodeFileSystemPath(projectOpen, False) andrej@1662: andrej@1662: if projectOpen is not None and os.path.isdir(projectOpen): andrej@1662: self.CTR = ProjectController(self, self.Log) andrej@1662: self.Controler = self.CTR andrej@1662: result, err = self.CTR.LoadProject(projectOpen, buildpath) andrej@1662: if not result: andrej@1662: self.LibraryPanel.SetController(self.Controler) andrej@1662: self.ProjectTree.Enable(True) andrej@1662: self.PouInstanceVariablesPanel.SetController(self.Controler) andrej@1662: self.RefreshConfigRecentProjects(os.path.abspath(projectOpen)) andrej@1662: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) andrej@1662: else: andrej@1662: self.ResetView() andrej@1662: self.ShowErrorMessage(result) andrej@1662: else: andrej@1662: self.CTR = ctr andrej@1662: self.Controler = ctr andrej@1662: if ctr is not None: andrej@1662: self.LibraryPanel.SetController(self.Controler) andrej@1662: self.ProjectTree.Enable(True) andrej@1662: self.PouInstanceVariablesPanel.SetController(self.Controler) andrej@1662: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) andrej@1662: if self.EnableDebug: andrej@1662: self.DebugVariablePanel.SetDataProducer(self.CTR) andrej@1662: andrej@1662: self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) andrej@1662: andrej@1662: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) andrej@1662: self.RefreshAll() andrej@1662: self.LogConsole.SetFocus() andrej@1662: andrej@1662: def RefreshTitle(self): andrej@1662: name = _("Beremiz") andrej@1662: if self.CTR is not None: andrej@1662: projectname = self.CTR.GetProjectName() andrej@1662: if self.CTR.ProjectTestModified(): andrej@1662: projectname = "~%s~" % projectname andrej@1662: self.SetTitle("%s - %s" % (name, projectname)) andrej@1662: else: andrej@1662: self.SetTitle(name) andrej@1662: andrej@1662: def StartLocalRuntime(self, taskbaricon = True): andrej@1662: if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): andrej@1662: # create temporary directory for runtime working directory andrej@1662: self.local_runtime_tmpdir = tempfile.mkdtemp() andrej@1662: # choose an arbitrary random port for runtime andrej@1662: self.runtime_port = int(random.random() * 1000) + 61131 andrej@1662: # launch local runtime andrej@1662: self.local_runtime = ProcessLogger(self.Log, andrej@1662: "\"%s\" \"%s\" -p %s -i localhost %s %s"%( andrej@1662: sys.executable, andrej@1662: Bpath("Beremiz_service.py"), andrej@1662: self.runtime_port, andrej@1662: {False : "-x 0", True :"-x 1"}[taskbaricon], andrej@1662: self.local_runtime_tmpdir), andrej@1662: no_gui=False, andrej@1662: timeout=500, keyword = self.local_runtime_tmpdir, andrej@1662: cwd = self.local_runtime_tmpdir) andrej@1662: self.local_runtime.spin() andrej@1662: return self.runtime_port andrej@1662: andrej@1662: def KillLocalRuntime(self): andrej@1662: if self.local_runtime is not None: andrej@1662: # shutdown local runtime andrej@1662: self.local_runtime.kill(gently=False) andrej@1662: # clear temp dir andrej@1662: shutil.rmtree(self.local_runtime_tmpdir) andrej@1662: andrej@1662: self.local_runtime = None andrej@1662: andrej@1662: def OnOpenWidgetInspector(self, evt): andrej@1662: # Activate the widget inspection tool andrej@1662: from wx.lib.inspection import InspectionTool andrej@1662: if not InspectionTool().initialized: andrej@1662: InspectionTool().Init() andrej@1662: andrej@1662: # Find a widget to be selected in the tree. Use either the andrej@1662: # one under the cursor, if any, or this frame. andrej@1662: wnd = wx.FindWindowAtPointer() andrej@1662: if not wnd: andrej@1662: wnd = self andrej@1662: InspectionTool().Show(wnd, True) andrej@1662: andrej@1662: def OnLogConsoleFocusChanged(self, event): andrej@1662: self.RefreshEditMenu() andrej@1662: event.Skip() andrej@1662: andrej@1662: def OnLogConsoleUpdateUI(self, event): andrej@1662: self.SetCopyBuffer(self.LogConsole.GetSelectedText(), True) andrej@1662: event.Skip() andrej@1662: andrej@1662: def OnLogConsoleMarginClick(self, event): andrej@1662: line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) andrej@1662: wx.CallAfter(self.SearchLineForError, self.LogConsole.GetLine(line_idx)) andrej@1662: event.Skip() andrej@1662: andrej@1662: def OnLogConsoleModified(self, event): andrej@1662: line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) andrej@1662: line = self.LogConsole.GetLine(line_idx) andrej@1662: if line: andrej@1662: result = MATIEC_ERROR_MODEL.match(line) andrej@1662: if result is not None: andrej@1662: self.LogConsole.MarkerAdd(line_idx, 0) andrej@1662: event.Skip() andrej@1662: andrej@1662: def SearchLineForError(self, line): andrej@1662: if self.CTR is not None: andrej@1662: result = MATIEC_ERROR_MODEL.match(line) andrej@1662: if result is not None: andrej@1662: first_line, first_column, last_line, last_column, error = result.groups() andrej@1662: infos = self.CTR.ShowError(self.Log, andrej@1662: (int(first_line), int(first_column)), andrej@1662: (int(last_line), int(last_column))) andrej@1662: andrej@1662: ## Function displaying an Error dialog in PLCOpenEditor. andrej@1662: # @return False if closing cancelled. andrej@1662: def CheckSaveBeforeClosing(self, title=_("Close Project")): andrej@1662: if self.CTR.ProjectTestModified(): andrej@1662: dialog = wx.MessageDialog(self, andrej@1662: _("There are changes, do you want to save?"), andrej@1662: title, andrej@1662: wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) andrej@1662: answer = dialog.ShowModal() andrej@1662: dialog.Destroy() andrej@1662: if answer == wx.ID_YES: andrej@1662: self.CTR.SaveProject() andrej@1662: elif answer == wx.ID_CANCEL: andrej@1662: return False andrej@1662: andrej@1662: for idx in xrange(self.TabsOpened.GetPageCount()): andrej@1662: window = self.TabsOpened.GetPage(idx) andrej@1662: if not window.CheckSaveBeforeClosing(): andrej@1662: return False andrej@1662: andrej@1662: return True andrej@1662: andrej@1662: def GetTabInfos(self, tab): andrej@1662: if (isinstance(tab, EditorPanel) and andrej@1662: not isinstance(tab, (Viewer, andrej@1662: TextViewer, andrej@1662: ResourceEditor, andrej@1662: ConfigurationEditor, andrej@1662: DataTypeEditor))): andrej@1662: return ("confnode", tab.Controler.CTNFullName(), tab.GetTagName()) andrej@1662: elif (isinstance(tab, TextViewer) and andrej@1662: (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))): andrej@1662: return ("confnode", None, tab.GetInstancePath()) andrej@1662: else: andrej@1662: return IDEFrame.GetTabInfos(self, tab) andrej@1662: andrej@1662: def LoadTab(self, notebook, page_infos): andrej@1662: if page_infos[0] == "confnode": andrej@1662: if page_infos[1] is None: andrej@1662: confnode = self.CTR andrej@1662: else: andrej@1662: confnode = self.CTR.GetChildByName(page_infos[1]) andrej@1662: return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:])) andrej@1662: else: andrej@1662: return IDEFrame.LoadTab(self, notebook, page_infos) andrej@1662: andrej@1662: # Strange hack required by WAMP connector, using twisted. andrej@1662: # Twisted reactor needs to be stopped only before quit, andrej@1662: # since it cannot be restarted andrej@1662: ToDoBeforeQuit = [] andrej@1662: def AddToDoBeforeQuit(self, Thing): andrej@1662: self.ToDoBeforeQuit.append(Thing) andrej@1662: andrej@1662: def OnCloseFrame(self, event): andrej@1662: for evt_type in [wx.EVT_SET_FOCUS, andrej@1662: wx.EVT_KILL_FOCUS, andrej@1662: wx.stc.EVT_STC_UPDATEUI]: andrej@1662: self.LogConsole.Unbind(evt_type) andrej@1662: if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")): andrej@1662: if self.CTR is not None: andrej@1662: self.CTR.KillDebugThread() andrej@1662: self.KillLocalRuntime() andrej@1662: andrej@1662: self.SaveLastState() andrej@1662: andrej@1662: for Thing in self.ToDoBeforeQuit : andrej@1662: Thing() andrej@1662: self.ToDoBeforeQuit = [] andrej@1662: andrej@1662: event.Skip() andrej@1662: else: andrej@1662: event.Veto() andrej@1662: andrej@1662: def RefreshFileMenu(self): andrej@1662: self.RefreshRecentProjectsMenu() andrej@1662: andrej@1662: MenuToolBar = self.Panes["MenuToolBar"] andrej@1662: if self.CTR is not None: andrej@1662: selected = self.TabsOpened.GetSelection() andrej@1662: if selected >= 0: andrej@1662: window = self.TabsOpened.GetPage(selected) andrej@1662: viewer_is_modified = window.IsModified() andrej@1662: is_viewer = isinstance(window, Viewer) andrej@1662: else: andrej@1662: viewer_is_modified = is_viewer = False andrej@1662: if self.TabsOpened.GetPageCount() > 0: andrej@1662: self.FileMenu.Enable(wx.ID_CLOSE, True) andrej@1662: if is_viewer: andrej@1662: self.FileMenu.Enable(wx.ID_PREVIEW, True) andrej@1662: self.FileMenu.Enable(wx.ID_PRINT, True) andrej@1662: MenuToolBar.EnableTool(wx.ID_PRINT, True) andrej@1662: else: andrej@1662: self.FileMenu.Enable(wx.ID_PREVIEW, False) andrej@1662: self.FileMenu.Enable(wx.ID_PRINT, False) andrej@1662: MenuToolBar.EnableTool(wx.ID_PRINT, False) andrej@1662: else: andrej@1662: self.FileMenu.Enable(wx.ID_CLOSE, False) andrej@1662: self.FileMenu.Enable(wx.ID_PREVIEW, False) andrej@1662: self.FileMenu.Enable(wx.ID_PRINT, False) andrej@1662: MenuToolBar.EnableTool(wx.ID_PRINT, False) andrej@1662: self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) andrej@1662: project_modified = self.CTR.ProjectTestModified() or viewer_is_modified andrej@1662: self.FileMenu.Enable(wx.ID_SAVE, project_modified) andrej@1662: MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) andrej@1662: self.FileMenu.Enable(wx.ID_SAVEAS, True) andrej@1662: MenuToolBar.EnableTool(wx.ID_SAVEAS, True) andrej@1662: self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) andrej@1662: else: andrej@1662: self.FileMenu.Enable(wx.ID_CLOSE, False) andrej@1662: self.FileMenu.Enable(wx.ID_PAGE_SETUP, False) andrej@1662: self.FileMenu.Enable(wx.ID_PREVIEW, False) andrej@1662: self.FileMenu.Enable(wx.ID_PRINT, False) andrej@1662: MenuToolBar.EnableTool(wx.ID_PRINT, False) andrej@1662: self.FileMenu.Enable(wx.ID_SAVE, False) andrej@1662: MenuToolBar.EnableTool(wx.ID_SAVE, False) andrej@1662: self.FileMenu.Enable(wx.ID_SAVEAS, False) andrej@1662: MenuToolBar.EnableTool(wx.ID_SAVEAS, False) andrej@1662: self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) andrej@1662: andrej@1662: def RefreshRecentProjectsMenu(self): andrej@1662: try: andrej@1662: recent_projects = map(DecodeFileSystemPath, andrej@1662: self.GetConfigEntry("RecentProjects", [])) andrej@1662: except: andrej@1662: recent_projects = [] andrej@1662: andrej@1662: while self.RecentProjectsMenu.GetMenuItemCount() > len(recent_projects): andrej@1662: item = self.RecentProjectsMenu.FindItemByPosition(0) andrej@1662: self.RecentProjectsMenu.RemoveItem(item) andrej@1662: andrej@1662: self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) andrej@1662: for idx, projectpath in enumerate(recent_projects): andrej@1662: text = u'&%d: %s' % (idx + 1, projectpath) andrej@1662: andrej@1662: if idx < self.RecentProjectsMenu.GetMenuItemCount(): andrej@1662: item = self.RecentProjectsMenu.FindItemByPosition(idx) andrej@1662: id = item.GetId() andrej@1662: item.SetItemLabel(text) andrej@1662: self.Disconnect(id, id, wx.EVT_BUTTON._getEvtType()) andrej@1662: else: andrej@1662: id = wx.NewId() andrej@1662: AppendMenu(self.RecentProjectsMenu, help='', id=id, andrej@1662: kind=wx.ITEM_NORMAL, text=text) andrej@1662: self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id) andrej@1662: andrej@1662: def GenerateOpenRecentProjectFunction(self, projectpath): andrej@1662: def OpenRecentProject(event): andrej@1662: if self.CTR is not None and not self.CheckSaveBeforeClosing(): andrej@1662: return andrej@1662: andrej@1662: self.OpenProject(projectpath) andrej@1662: return OpenRecentProject andrej@1662: andrej@1662: def GenerateMenuRecursive(self, items, menu): andrej@1662: for kind, infos in items: andrej@1662: if isinstance(kind, ListType): andrej@1662: text, id = infos andrej@1662: submenu = wx.Menu('') andrej@1662: self.GenerateMenuRecursive(kind, submenu) andrej@1662: menu.AppendMenu(id, text, submenu) andrej@1662: elif kind == wx.ITEM_SEPARATOR: andrej@1662: menu.AppendSeparator() andrej@1662: else: andrej@1662: text, id, help, callback = infos andrej@1662: AppendMenu(menu, help='', id=id, kind=kind, text=text) andrej@1662: if callback is not None: andrej@1662: self.Bind(wx.EVT_MENU, callback, id=id) andrej@1662: andrej@1662: def RefreshEditorToolBar(self): andrej@1662: IDEFrame.RefreshEditorToolBar(self) andrej@1662: self.AUIManager.GetPane("EditorToolBar").Position(2) andrej@1662: self.AUIManager.GetPane("StatusToolBar").Position(1) andrej@1662: self.AUIManager.Update() andrej@1662: andrej@1662: def RefreshStatusToolBar(self): andrej@1662: StatusToolBar = self.Panes["StatusToolBar"] andrej@1662: StatusToolBar.ClearTools() andrej@1662: andrej@1662: if self.CTR is not None: andrej@1662: andrej@1662: for confnode_method in self.CTR.StatusMethods: andrej@1662: if "method" in confnode_method and confnode_method.get("shown",True): andrej@1662: id = wx.NewId() andrej@1662: StatusToolBar.AddSimpleTool(id, andrej@1662: GetBitmap(confnode_method.get("bitmap", "Unknown")), andrej@1662: confnode_method["tooltip"]) andrej@1662: self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), id=id) andrej@1662: andrej@1662: StatusToolBar.Realize() andrej@1662: self.AUIManager.GetPane("StatusToolBar").BestSize(StatusToolBar.GetBestSize()).Show() andrej@1662: else: andrej@1662: self.AUIManager.GetPane("StatusToolBar").Hide() andrej@1662: self.AUIManager.GetPane("EditorToolBar").Position(2) andrej@1662: self.AUIManager.GetPane("StatusToolBar").Position(1) andrej@1662: self.AUIManager.Update() andrej@1662: andrej@1662: def RefreshEditMenu(self): andrej@1662: IDEFrame.RefreshEditMenu(self) andrej@1662: if self.FindFocus() == self.LogConsole: andrej@1662: self.EditMenu.Enable(wx.ID_COPY, True) andrej@1662: self.Panes["MenuToolBar"].EnableTool(wx.ID_COPY, True) andrej@1662: andrej@1662: if self.CTR is not None: andrej@1662: selected = self.TabsOpened.GetSelection() andrej@1662: if selected >= 0: andrej@1662: panel = self.TabsOpened.GetPage(selected) andrej@1662: else: andrej@1662: panel = None andrej@1662: if panel != self.LastPanelSelected: andrej@1662: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): andrej@1662: item = self.EditMenu.FindItemByPosition(self.EditMenuSize) andrej@1662: if item is not None: andrej@1662: if item.IsSeparator(): andrej@1662: self.EditMenu.RemoveItem(item) andrej@1662: else: andrej@1662: self.EditMenu.Delete(item.GetId()) andrej@1662: self.LastPanelSelected = panel andrej@1662: if panel is not None: andrej@1662: items = panel.GetConfNodeMenuItems() andrej@1662: else: andrej@1662: items = [] andrej@1662: if len(items) > 0: andrej@1662: self.EditMenu.AppendSeparator() andrej@1662: self.GenerateMenuRecursive(items, self.EditMenu) andrej@1662: if panel is not None: andrej@1662: panel.RefreshConfNodeMenu(self.EditMenu) andrej@1662: else: andrej@1662: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): andrej@1662: item = self.EditMenu.FindItemByPosition(i) andrej@1662: if item is not None: andrej@1662: if item.IsSeparator(): andrej@1662: self.EditMenu.RemoveItem(item) andrej@1662: else: andrej@1662: self.EditMenu.Delete(item.GetId()) andrej@1662: self.LastPanelSelected = None andrej@1662: self.MenuBar.UpdateMenus() andrej@1662: andrej@1662: def RefreshAll(self): andrej@1662: self.RefreshStatusToolBar() andrej@1662: andrej@1662: def GetMenuCallBackFunction(self, method): andrej@1662: """ Generate the callbackfunc for a given CTR method""" andrej@1662: def OnMenu(event): andrej@1662: # Disable button to prevent re-entrant call andrej@1662: event.GetEventObject().Disable() andrej@1662: # Call andrej@1662: getattr(self.CTR, method)() andrej@1662: # Re-enable button andrej@1662: event.GetEventObject().Enable() andrej@1662: return OnMenu andrej@1662: andrej@1662: def GetConfigEntry(self, entry_name, default): andrej@1662: return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default)))) andrej@1662: andrej@1662: def ResetConnectionStatusBar(self): andrej@1662: for field in xrange(self.ConnectionStatusBar.GetFieldsCount()): andrej@1662: self.ConnectionStatusBar.SetStatusText('', field) andrej@1662: andrej@1662: def ResetView(self): andrej@1662: IDEFrame.ResetView(self) andrej@1662: self.ConfNodeInfos = {} andrej@1662: if self.CTR is not None: andrej@1662: self.CTR.CloseProject() andrej@1662: self.CTR = None andrej@1662: self.Log.flush() andrej@1662: if self.EnableDebug: andrej@1662: self.DebugVariablePanel.SetDataProducer(None) andrej@1662: self.ResetConnectionStatusBar() andrej@1662: andrej@1662: def RefreshConfigRecentProjects(self, projectpath, err=False): andrej@1662: try: andrej@1662: recent_projects = map(DecodeFileSystemPath, andrej@1662: self.GetConfigEntry("RecentProjects", [])) andrej@1662: except: andrej@1662: recent_projects = [] andrej@1662: if projectpath in recent_projects: andrej@1662: recent_projects.remove(projectpath) andrej@1662: if not err: andrej@1662: recent_projects.insert(0, projectpath) andrej@1662: self.Config.Write("RecentProjects", cPickle.dumps( andrej@1662: map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS]))) andrej@1662: self.Config.Flush() andrej@1662: andrej@1662: def ResetPerspective(self): andrej@1662: IDEFrame.ResetPerspective(self) andrej@1662: self.RefreshStatusToolBar() andrej@1662: andrej@1662: def OnNewProjectMenu(self, event): andrej@1662: if self.CTR is not None and not self.CheckSaveBeforeClosing(): andrej@1662: return andrej@1662: andrej@1662: try: andrej@1662: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) andrej@1662: except: andrej@1662: defaultpath = os.path.expanduser("~") andrej@1662: andrej@1662: dialog = wx.DirDialog(self , _("Choose a project"), defaultpath) andrej@1662: if dialog.ShowModal() == wx.ID_OK: andrej@1662: projectpath = dialog.GetPath() andrej@1662: self.Config.Write("lastopenedfolder", andrej@1662: EncodeFileSystemPath(os.path.dirname(projectpath))) andrej@1662: self.Config.Flush() andrej@1662: self.ResetView() andrej@1662: ctr = ProjectController(self, self.Log) andrej@1662: result = ctr.NewProject(projectpath) andrej@1662: if not result: andrej@1662: self.CTR = ctr andrej@1662: self.Controler = self.CTR andrej@1662: self.LibraryPanel.SetController(self.Controler) andrej@1662: self.ProjectTree.Enable(True) andrej@1662: self.PouInstanceVariablesPanel.SetController(self.Controler) andrej@1662: self.RefreshConfigRecentProjects(projectpath) andrej@1662: if self.EnableDebug: andrej@1662: self.DebugVariablePanel.SetDataProducer(self.CTR) andrej@1662: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) andrej@1662: else: andrej@1662: self.ResetView() andrej@1662: self.ShowErrorMessage(result) andrej@1662: self.RefreshAll() andrej@1662: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) andrej@1662: dialog.Destroy() andrej@1662: andrej@1662: def OnOpenProjectMenu(self, event): andrej@1662: if self.CTR is not None and not self.CheckSaveBeforeClosing(): andrej@1662: return andrej@1662: andrej@1662: try: andrej@1662: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) andrej@1662: except: andrej@1662: defaultpath = os.path.expanduser("~") andrej@1662: andrej@1662: dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE| andrej@1662: wx.RESIZE_BORDER) andrej@1662: if dialog.ShowModal() == wx.ID_OK: andrej@1662: self.OpenProject(dialog.GetPath()) andrej@1662: dialog.Destroy() andrej@1662: andrej@1662: def OpenProject(self, projectpath): andrej@1662: if os.path.isdir(projectpath): andrej@1662: self.Config.Write("lastopenedfolder", andrej@1662: EncodeFileSystemPath(os.path.dirname(projectpath))) andrej@1662: self.Config.Flush() andrej@1662: self.ResetView() andrej@1662: self.CTR = ProjectController(self, self.Log) andrej@1662: self.Controler = self.CTR andrej@1662: result, err = self.CTR.LoadProject(projectpath) andrej@1662: if not result: andrej@1662: self.LibraryPanel.SetController(self.Controler) andrej@1662: self.ProjectTree.Enable(True) andrej@1662: self.PouInstanceVariablesPanel.SetController(self.Controler) andrej@1662: if self.EnableDebug: andrej@1662: self.DebugVariablePanel.SetDataProducer(self.CTR) andrej@1662: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) andrej@1662: else: andrej@1662: self.ResetView() andrej@1662: self.ShowErrorMessage(result) andrej@1662: self.RefreshAll() andrej@1662: self.SearchResultPanel.ResetSearchResults() andrej@1662: else: andrej@1662: self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath) andrej@1662: err = True andrej@1662: self.RefreshConfigRecentProjects(projectpath, err) andrej@1662: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) andrej@1662: andrej@1662: def OnCloseProjectMenu(self, event): andrej@1662: if self.CTR is not None and not self.CheckSaveBeforeClosing(): andrej@1662: return andrej@1662: andrej@1662: self.ResetView() andrej@1662: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) andrej@1662: self.RefreshAll() andrej@1662: andrej@1662: def OnSaveProjectMenu(self, event): andrej@1662: selected = self.TabsOpened.GetSelection() andrej@1662: if selected != -1: andrej@1662: window = self.TabsOpened.GetPage(selected) andrej@1662: window.Save() andrej@1662: if self.CTR is not None: andrej@1662: self.CTR.SaveProject() andrej@1662: self.RefreshAll() andrej@1662: self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) andrej@1662: andrej@1662: def OnSaveProjectAsMenu(self, event): andrej@1662: selected = self.TabsOpened.GetSelection() andrej@1662: if selected != -1: andrej@1662: window = self.TabsOpened.GetPage(selected) andrej@1662: window.SaveAs() andrej@1662: if self.CTR is not None: andrej@1662: self.CTR.SaveProjectAs() andrej@1662: self.RefreshAll() andrej@1662: self.RefreshConfigRecentProjects(self.CTR.ProjectPath) andrej@1662: self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) andrej@1662: andrej@1662: def OnQuitMenu(self, event): andrej@1662: self.Close() andrej@1662: andrej@1662: def OnAboutMenu(self, event): andrej@1662: info = version.GetAboutDialogInfo() andrej@1662: ShowAboutDialog(self, info) andrej@1662: andrej@1662: def OnProjectTreeItemBeginEdit(self, event): andrej@1662: selected = event.GetItem() andrej@1662: if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFNODE: andrej@1662: event.Veto() andrej@1662: else: andrej@1662: IDEFrame.OnProjectTreeItemBeginEdit(self, event) andrej@1662: andrej@1662: def OnProjectTreeRightUp(self, event): andrej@1662: item = event.GetItem() andrej@1662: item_infos = self.ProjectTree.GetPyData(item) andrej@1662: andrej@1662: if item_infos["type"] == ITEM_CONFNODE: andrej@1662: confnode_menu = wx.Menu(title='') andrej@1662: andrej@1662: confnode = item_infos["confnode"] andrej@1662: if confnode is not None: andrej@1662: menu_items = confnode.GetContextualMenuItems() andrej@1662: if menu_items is not None: andrej@1662: for text, help, callback in menu_items: andrej@1662: new_id = wx.NewId() andrej@1662: confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=text) andrej@1662: self.Bind(wx.EVT_MENU, callback, id=new_id) andrej@1662: else: andrej@1662: for name, XSDClass, help in confnode.CTNChildrenTypes: surkovsv93@1684: if not hasattr(XSDClass, 'CTNMaxCount') or not confnode.Children.get(name) \ surkovsv93@1684: or len(confnode.Children[name]) < XSDClass.CTNMaxCount: surkovsv93@1684: new_id = wx.NewId() surkovsv93@1684: confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Add") + " " + name) surkovsv93@1684: self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name, confnode), id=new_id) andrej@1662: new_id = wx.NewId() andrej@1662: AppendMenu(confnode_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) andrej@1662: self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), id=new_id) andrej@1662: andrej@1662: self.PopupMenu(confnode_menu) andrej@1662: confnode_menu.Destroy() andrej@1662: andrej@1662: event.Skip() andrej@1662: elif item_infos["type"] == ITEM_RESOURCE: andrej@1662: # prevent last resource to be delted andrej@1662: parent = self.ProjectTree.GetItemParent(item) andrej@1662: parent_name = self.ProjectTree.GetItemText(parent) andrej@1662: if parent_name == _("Resources"): andrej@1662: IDEFrame.OnProjectTreeRightUp(self, event) andrej@1662: else: andrej@1662: IDEFrame.OnProjectTreeRightUp(self, event) andrej@1662: andrej@1662: def OnProjectTreeItemActivated(self, event): andrej@1662: selected = event.GetItem() andrej@1662: name = self.ProjectTree.GetItemText(selected) andrej@1662: item_infos = self.ProjectTree.GetPyData(selected) andrej@1662: if item_infos["type"] == ITEM_CONFNODE: andrej@1662: item_infos["confnode"]._OpenView() andrej@1662: event.Skip() andrej@1662: elif item_infos["type"] == ITEM_PROJECT: andrej@1662: self.CTR._OpenView() andrej@1662: else: andrej@1662: IDEFrame.OnProjectTreeItemActivated(self, event) andrej@1662: andrej@1662: def ProjectTreeItemSelect(self, select_item): andrej@1662: if select_item is not None and select_item.IsOk(): andrej@1662: name = self.ProjectTree.GetItemText(select_item) andrej@1662: item_infos = self.ProjectTree.GetPyData(select_item) andrej@1662: if item_infos["type"] == ITEM_CONFNODE: andrej@1662: item_infos["confnode"]._OpenView(onlyopened=True) andrej@1662: elif item_infos["type"] == ITEM_PROJECT: andrej@1662: self.CTR._OpenView(onlyopened=True) andrej@1662: else: andrej@1662: IDEFrame.ProjectTreeItemSelect(self, select_item) andrej@1662: andrej@1662: def SelectProjectTreeItem(self, tagname): andrej@1662: if self.ProjectTree is not None: andrej@1662: root = self.ProjectTree.GetRootItem() andrej@1662: if root.IsOk(): andrej@1662: words = tagname.split("::") andrej@1662: if len(words) == 1: andrej@1662: if tagname == "Project": andrej@1662: self.SelectedItem = root andrej@1662: self.ProjectTree.SelectItem(root) andrej@1662: self.ResetSelectedItem() andrej@1662: else: andrej@1662: return self.RecursiveProjectTreeItemSelection(root, andrej@1662: [(word, ITEM_CONFNODE) for word in tagname.split(".")]) andrej@1662: elif words[0] == "R": andrej@1662: return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)]) andrej@1662: elif not os.path.exists(words[0]): andrej@1662: IDEFrame.SelectProjectTreeItem(self, tagname) andrej@1662: andrej@1662: def GetAddConfNodeFunction(self, name, confnode=None): andrej@1662: def AddConfNodeMenuFunction(event): andrej@1662: wx.CallAfter(self.AddConfNode, name, confnode) andrej@1662: return AddConfNodeMenuFunction andrej@1662: andrej@1662: def GetDeleteMenuFunction(self, confnode): andrej@1662: def DeleteMenuFunction(event): andrej@1662: wx.CallAfter(self.DeleteConfNode, confnode) andrej@1662: return DeleteMenuFunction andrej@1662: andrej@1662: def AddConfNode(self, ConfNodeType, confnode=None): andrej@1662: if self.CTR.CheckProjectPathPerm(): andrej@1662: ConfNodeName = "%s_0" % ConfNodeType andrej@1662: if confnode is not None: andrej@1662: confnode.CTNAddChild(ConfNodeName, ConfNodeType) andrej@1662: else: andrej@1662: self.CTR.CTNAddChild(ConfNodeName, ConfNodeType) andrej@1662: self._Refresh(TITLE, FILEMENU, PROJECTTREE) andrej@1662: andrej@1662: def DeleteConfNode(self, confnode): andrej@1662: if self.CTR.CheckProjectPathPerm(): andrej@1662: dialog = wx.MessageDialog(self, andrej@1662: _("Really delete node '%s'?") % confnode.CTNName(), andrej@1662: _("Remove %s node") % confnode.CTNType, andrej@1662: wx.YES_NO|wx.NO_DEFAULT) andrej@1662: if dialog.ShowModal() == wx.ID_YES: andrej@1662: confnode.CTNRemove() andrej@1662: del confnode andrej@1662: self._Refresh(TITLE, FILEMENU, PROJECTTREE) andrej@1662: dialog.Destroy() andrej@1662: andrej@1662: #------------------------------------------------------------------------------- andrej@1662: # Highlights showing functions andrej@1662: #------------------------------------------------------------------------------- andrej@1662: andrej@1662: def ShowHighlight(self, infos, start, end, highlight_type): andrej@1662: config_name = self.Controler.GetProjectMainConfigurationName() andrej@1662: if config_name is not None and infos[0] == self.Controler.ComputeConfigurationName(config_name): andrej@1662: self.CTR._OpenView() andrej@1662: selected = self.TabsOpened.GetSelection() andrej@1662: if selected != -1: andrej@1662: viewer = self.TabsOpened.GetPage(selected) andrej@1662: viewer.AddHighlight(infos[1:], start, end, highlight_type) andrej@1662: else: andrej@1662: IDEFrame.ShowHighlight(self, infos, start, end, highlight_type) andrej@1662: andrej@1662: #------------------------------------------------------------------------------- andrej@1662: # Exception Handler andrej@1662: #------------------------------------------------------------------------------- andrej@1662: import threading, traceback andrej@1662: andrej@1662: Max_Traceback_List_Size = 20 andrej@1662: andrej@1662: def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path): andrej@1662: trcbck_lst = [] andrej@1662: for i,line in enumerate(traceback.extract_tb(e_tb)): andrej@1662: trcbck = " " + str(i+1) + ". " andrej@1662: if line[0].find(os.getcwd()) == -1: andrej@1662: trcbck += "file : " + str(line[0]) + ", " andrej@1662: else: andrej@1662: trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ", " andrej@1662: trcbck += "line : " + str(line[1]) + ", " + "function : " + str(line[2]) andrej@1662: trcbck_lst.append(trcbck) andrej@1662: andrej@1662: # Allow clicking.... andrej@1662: cap = wx.Window_GetCapture() andrej@1662: if cap: andrej@1662: cap.ReleaseMouse() andrej@1662: andrej@1662: dlg = wx.SingleChoiceDialog(None, andrej@1662: _(""" andrej@1662: An unhandled exception (bug) occured. Bug report saved at : andrej@1662: (%s) andrej@1662: andrej@1662: Please be kind enough to send this file to: andrej@1662: beremiz-devel@lists.sourceforge.net andrej@1662: andrej@1662: You should now restart program. andrej@1662: andrej@1662: Traceback: andrej@1662: """) % bug_report_path + andrej@1662: repr(e_type) + " : " + repr(e_value), andrej@1662: _("Error"), andrej@1662: trcbck_lst) andrej@1662: try: andrej@1662: res = (dlg.ShowModal() == wx.ID_OK) andrej@1662: finally: andrej@1662: dlg.Destroy() andrej@1662: andrej@1662: return res andrej@1662: andrej@1662: def get_last_traceback(tb): andrej@1662: while tb.tb_next: andrej@1662: tb = tb.tb_next andrej@1662: return tb andrej@1662: andrej@1662: andrej@1662: def format_namespace(d, indent=' '): andrej@1662: return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()]) andrej@1662: andrej@1662: andrej@1662: ignored_exceptions = [] # a problem with a line in a module is only reported once per session andrej@1662: andrej@1662: def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]): andrej@1662: andrej@1662: def save_bug_report(e_type, e_value, e_traceback, bug_report_path,date): andrej@1662: info = { andrej@1662: 'app-title': wx.GetApp().GetAppName(), # app_title andrej@1662: 'app-version': app_version, andrej@1662: 'wx-version': wx.VERSION_STRING, andrej@1662: 'wx-platform': wx.Platform, andrej@1662: 'python-version': platform.python_version(), # sys.version.split()[0], andrej@1662: 'platform': platform.platform(), andrej@1662: 'e-type': e_type, andrej@1662: 'e-value': e_value, andrej@1662: 'date': date, andrej@1662: 'cwd': os.getcwd(), andrej@1662: } andrej@1662: if e_traceback: andrej@1662: info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value) andrej@1662: last_tb = get_last_traceback(e_traceback) andrej@1662: exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred andrej@1662: info['locals'] = format_namespace(exception_locals) andrej@1662: if 'self' in exception_locals: andrej@1662: try: andrej@1662: info['self'] = format_namespace(exception_locals['self'].__dict__) andrej@1662: except: andrej@1662: pass andrej@1662: if not os.path.exists(path): andrej@1662: os.mkdir(path) andrej@1662: output = open(bug_report_path, 'w') andrej@1662: lst = info.keys() andrej@1662: lst.sort() andrej@1662: for a in lst: andrej@1662: output.write(a + ":\n" + str(info[a]) + "\n\n") andrej@1662: output.close() andrej@1662: andrej@1662: def handle_exception(e_type, e_value, e_traceback): andrej@1662: traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func andrej@1662: last_tb = get_last_traceback(e_traceback) andrej@1662: ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno) andrej@1662: if ex not in ignored_exceptions: andrej@1662: ignored_exceptions.append(ex) andrej@1662: date = time.ctime() andrej@1662: bug_report_path = path + os.sep + "bug_report_" + date.replace(':', '-').replace(' ', '_') + ".txt" andrej@1662: save_bug_report(e_type, e_value, e_traceback, bug_report_path, date) andrej@1662: Display_Exception_Dialog(e_type, e_value, e_traceback, bug_report_path) andrej@1662: #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args) andrej@1662: sys.excepthook = handle_exception andrej@1662: andrej@1662: init_old = threading.Thread.__init__ andrej@1662: def init(self, *args, **kwargs): andrej@1662: init_old(self, *args, **kwargs) andrej@1662: run_old = self.run andrej@1662: def run_with_except_hook(*args, **kw): andrej@1662: try: andrej@1662: run_old(*args, **kw) andrej@1662: except (KeyboardInterrupt, SystemExit): andrej@1662: raise andrej@1662: except: andrej@1662: sys.excepthook(*sys.exc_info()) andrej@1662: self.run = run_with_except_hook andrej@1662: threading.Thread.__init__ = init