Files
Phoenix/wx/py/frame.py
Per A. Brodtkorb 05ac589e2d Fixes issue 1555
Replace open-close statements by the use of "with"-blocks.

With the "With" statement, you get better syntax and exceptions handling.

"The with statement simplifies exception handling by encapsulating common
preparation and cleanup tasks."

In addition, it will automatically close the file. The with statement provides
a way for ensuring that a clean-up is always used.
2020-03-20 15:03:09 +01:00

979 lines
38 KiB
Python

"""Base frame with menu."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
import wx
import os
from .version import VERSION
from . import editwindow
from . import dispatcher
ID_NEW = wx.ID_NEW
ID_OPEN = wx.ID_OPEN
ID_REVERT = wx.ID_REVERT
ID_CLOSE = wx.ID_CLOSE
ID_SAVE = wx.ID_SAVE
ID_SAVEAS = wx.ID_SAVEAS
ID_PRINT = wx.ID_PRINT
ID_EXIT = wx.ID_EXIT
ID_UNDO = wx.ID_UNDO
ID_REDO = wx.ID_REDO
ID_CUT = wx.ID_CUT
ID_COPY = wx.ID_COPY
ID_PASTE = wx.ID_PASTE
ID_CLEAR = wx.ID_CLEAR
ID_SELECTALL = wx.ID_SELECTALL
ID_EMPTYBUFFER = wx.NewIdRef()
ID_ABOUT = wx.ID_ABOUT
ID_HELP = wx.NewIdRef()
ID_AUTOCOMP_SHOW = wx.NewIdRef()
ID_AUTOCOMP_MAGIC = wx.NewIdRef()
ID_AUTOCOMP_SINGLE = wx.NewIdRef()
ID_AUTOCOMP_DOUBLE = wx.NewIdRef()
ID_CALLTIPS_SHOW = wx.NewIdRef()
ID_CALLTIPS_INSERT = wx.NewIdRef()
ID_COPY_PLUS = wx.NewIdRef()
ID_NAMESPACE = wx.NewIdRef()
ID_PASTE_PLUS = wx.NewIdRef()
ID_WRAP = wx.NewIdRef()
ID_TOGGLE_MAXIMIZE = wx.NewIdRef()
ID_SHOW_LINENUMBERS = wx.NewIdRef()
ID_ENABLESHELLMODE = wx.NewIdRef()
ID_ENABLEAUTOSYMPY = wx.NewIdRef()
ID_AUTO_SAVESETTINGS = wx.NewIdRef()
ID_SAVEACOPY = wx.NewIdRef()
ID_SAVEHISTORY = wx.NewIdRef()
ID_SAVEHISTORYNOW = wx.NewIdRef()
ID_CLEARHISTORY = wx.NewIdRef()
ID_SAVESETTINGS = wx.NewIdRef()
ID_DELSETTINGSFILE = wx.NewIdRef()
ID_EDITSTARTUPSCRIPT = wx.NewIdRef()
ID_EXECSTARTUPSCRIPT = wx.NewIdRef()
ID_SHOWPYSLICESTUTORIAL = wx.NewIdRef()
ID_FIND = wx.ID_FIND
ID_FINDNEXT = wx.NewIdRef()
ID_FINDPREVIOUS = wx.NewIdRef()
ID_SHOWTOOLS = wx.NewIdRef()
ID_HIDEFOLDINGMARGIN = wx.NewIdRef()
class Frame(wx.Frame):
"""Frame with standard menu items."""
def __init__(self, parent=None, id=-1, title='Editor',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE,shellName='PyCrust'):
"""Create a Frame instance."""
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.CreateStatusBar()
self.SetStatusText('Frame')
self.shellName=shellName
from . import images
self.SetIcon(images.getPyIcon(shellName=shellName))
self.__createMenus()
self.iconized = False
self.findDlg = None
self.findData = wx.FindReplaceData()
self.findData.SetFlags(wx.FR_DOWN)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_ICONIZE, self.OnIconize)
def OnIconize(self, event):
"""Event handler for Iconize."""
self.iconized = event.IsIconized()
def OnClose(self, event):
"""Event handler for closing."""
self.Destroy()
def __createMenus(self):
# File Menu
m = self.fileMenu = wx.Menu()
m.Append(ID_NEW, '&New \tCtrl+N',
'New file')
m.Append(ID_OPEN, '&Open... \tCtrl+O',
'Open file')
m.AppendSeparator()
m.Append(ID_REVERT, '&Revert \tCtrl+R',
'Revert to last saved version')
m.Append(ID_CLOSE, '&Close \tCtrl+W',
'Close file')
m.AppendSeparator()
m.Append(ID_SAVE, '&Save... \tCtrl+S',
'Save file')
m.Append(ID_SAVEAS, 'Save &As \tCtrl+Shift+S',
'Save file with new name')
if self.shellName in ['PySlices','SymPySlices']:
m.Append(ID_SAVEACOPY, 'Save A Cop&y',
'Save a copy of the file without changing the current file')
m.AppendSeparator()
m.Append(ID_PRINT, '&Print... \tCtrl+P',
'Print file')
m.AppendSeparator()
m.Append(ID_NAMESPACE, '&Update Namespace \tCtrl+Shift+N',
'Update namespace for autocompletion and calltips')
m.AppendSeparator()
m.Append(ID_EXIT, 'E&xit\tCtrl+Q', 'Exit Program')
# Edit
m = self.editMenu = wx.Menu()
m.Append(ID_UNDO, '&Undo \tCtrl+Z',
'Undo the last action')
m.Append(ID_REDO, '&Redo \tCtrl+Y',
'Redo the last undone action')
m.AppendSeparator()
m.Append(ID_CUT, 'Cu&t \tCtrl+X',
'Cut the selection')
m.Append(ID_COPY, '&Copy \tCtrl+C',
'Copy the selection')
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tCtrl+Shift+C',
'Copy the selection - retaining prompts')
m.Append(ID_PASTE, '&Paste \tCtrl+V', 'Paste from clipboard')
m.Append(ID_PASTE_PLUS, 'Past&e Plus \tCtrl+Shift+V',
'Paste and run commands')
m.AppendSeparator()
m.Append(ID_CLEAR, 'Cle&ar',
'Delete the selection')
m.Append(ID_SELECTALL, 'Select A&ll \tCtrl+A',
'Select all text')
m.AppendSeparator()
m.Append(ID_EMPTYBUFFER, 'E&mpty Buffer...',
'Delete all the contents of the edit buffer')
m.Append(ID_FIND, '&Find Text... \tCtrl+F',
'Search for text in the edit buffer')
m.Append(ID_FINDNEXT, 'Find &Next \tCtrl+G',
'Find next instance of the search text')
m.Append(ID_FINDPREVIOUS, 'Find Pre&vious \tCtrl+Shift+G',
'Find previous instance of the search text')
# View
m = self.viewMenu = wx.Menu()
m.Append(ID_WRAP, '&Wrap Lines\tCtrl+Shift+W',
'Wrap lines at right edge', wx.ITEM_CHECK)
m.Append(ID_SHOW_LINENUMBERS, '&Show Line Numbers\tCtrl+Shift+L',
'Show Line Numbers', wx.ITEM_CHECK)
m.Append(ID_TOGGLE_MAXIMIZE, '&Toggle Maximize\tF11',
'Maximize/Restore Application')
if hasattr(self, 'ToggleTools'):
m.Append(ID_SHOWTOOLS,
'Show &Tools\tF4',
'Show the filling and other tools', wx.ITEM_CHECK)
if self.shellName==['PySlices','SymPySlices']:
m.Append(ID_HIDEFOLDINGMARGIN,
'&Hide Folding Margin',
'Hide Folding Margin', wx.ITEM_CHECK)
# Options
m = self.autocompMenu = wx.Menu()
m.Append(ID_AUTOCOMP_SHOW, 'Show &Auto Completion\tCtrl+Shift+A',
'Show auto completion list', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_MAGIC, 'Include &Magic Attributes\tCtrl+Shift+M',
'Include attributes visible to __getattr__ and __setattr__',
wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_SINGLE, 'Include Single &Underscores\tCtrl+Shift+U',
'Include attibutes prefixed by a single underscore', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_DOUBLE, 'Include &Double Underscores\tCtrl+Shift+D',
'Include attibutes prefixed by a double underscore', wx.ITEM_CHECK)
m = self.calltipsMenu = wx.Menu()
m.Append(ID_CALLTIPS_SHOW, 'Show Call &Tips\tCtrl+Shift+T',
'Show call tips with argument signature and docstring', wx.ITEM_CHECK)
m.Append(ID_CALLTIPS_INSERT, '&Insert Call Tips\tCtrl+Shift+I',
'&Insert Call Tips', wx.ITEM_CHECK)
m = self.optionsMenu = wx.Menu()
m.AppendSubMenu(self.autocompMenu, '&Auto Completion',
'Auto Completion Options')
m.AppendSubMenu(self.calltipsMenu, '&Call Tips', 'Call Tip Options')
m.AppendSeparator()
self.historyMenu = wx.Menu()
self.historyMenu.Append(ID_SAVEHISTORY, '&Autosave History',
'Automatically save history on close', wx.ITEM_CHECK)
self.historyMenu.Append(ID_SAVEHISTORYNOW, '&Save History Now',
'Save history')
self.historyMenu.Append(ID_CLEARHISTORY, '&Clear History ',
'Clear history')
m.AppendSubMenu(self.historyMenu, "&History", "History Options")
self.startupMenu = wx.Menu()
self.startupMenu.Append(ID_EXECSTARTUPSCRIPT,
'E&xecute Startup Script',
'Execute Startup Script', wx.ITEM_CHECK)
self.startupMenu.Append(ID_EDITSTARTUPSCRIPT,
'&Edit Startup Script...',
'Edit Startup Script')
if self.shellName in ['PySlices','SymPySlices']:
self.startupMenu.Append(ID_SHOWPYSLICESTUTORIAL,
'&Show PySlices Tutorial',
'Show PySlices Tutorial', wx.ITEM_CHECK)
m.AppendSubMenu(self.startupMenu, '&Startup', 'Startup Options')
self.settingsMenu = wx.Menu()
if self.shellName in ['PySlices','SymPySlices']:
self.settingsMenu.Append(ID_ENABLESHELLMODE,
'&Enable Shell Mode',
'Enable Shell Mode', wx.ITEM_CHECK)
if self.shellName == 'SymPySlices':
self.settingsMenu.Append(ID_ENABLEAUTOSYMPY,
'&Enable "Auto-Sympy" Conversions for Undefined Variables',
'Enable "Auto-Sympy" Conversions', wx.ITEM_CHECK)
self.settingsMenu.Append(ID_AUTO_SAVESETTINGS,
'&Auto Save Settings',
'Automatically save settings on close', wx.ITEM_CHECK)
self.settingsMenu.Append(ID_SAVESETTINGS,
'&Save Settings',
'Save settings now')
self.settingsMenu.Append(ID_DELSETTINGSFILE,
'&Revert to default',
'Revert to the default settings')
m.AppendSubMenu(self.settingsMenu, '&Settings', 'Settings Options')
m = self.helpMenu = wx.Menu()
m.Append(ID_HELP, '&Help\tF1', 'Help!')
m.AppendSeparator()
m.Append(ID_ABOUT, '&About...', 'About this program')
b = self.menuBar = wx.MenuBar()
b.Append(self.fileMenu, '&File')
b.Append(self.editMenu, '&Edit')
b.Append(self.viewMenu, '&View')
b.Append(self.optionsMenu, '&Options')
b.Append(self.helpMenu, '&Help')
self.SetMenuBar(b)
self.Bind(wx.EVT_MENU, self.OnFileNew, id=ID_NEW)
self.Bind(wx.EVT_MENU, self.OnFileOpen, id=ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnFileRevert, id=ID_REVERT)
self.Bind(wx.EVT_MENU, self.OnFileClose, id=ID_CLOSE)
self.Bind(wx.EVT_MENU, self.OnFileSave, id=ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnFileSaveAs, id=ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnFileSaveACopy, id=ID_SAVEACOPY)
self.Bind(wx.EVT_MENU, self.OnFileUpdateNamespace, id=ID_NAMESPACE)
self.Bind(wx.EVT_MENU, self.OnFilePrint, id=ID_PRINT)
self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
self.Bind(wx.EVT_MENU, self.OnUndo, id=ID_UNDO)
self.Bind(wx.EVT_MENU, self.OnRedo, id=ID_REDO)
self.Bind(wx.EVT_MENU, self.OnCut, id=ID_CUT)
self.Bind(wx.EVT_MENU, self.OnCopy, id=ID_COPY)
self.Bind(wx.EVT_MENU, self.OnCopyPlus, id=ID_COPY_PLUS)
self.Bind(wx.EVT_MENU, self.OnPaste, id=ID_PASTE)
self.Bind(wx.EVT_MENU, self.OnPastePlus, id=ID_PASTE_PLUS)
self.Bind(wx.EVT_MENU, self.OnClear, id=ID_CLEAR)
self.Bind(wx.EVT_MENU, self.OnSelectAll, id=ID_SELECTALL)
self.Bind(wx.EVT_MENU, self.OnEmptyBuffer, id=ID_EMPTYBUFFER)
self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_ABOUT)
self.Bind(wx.EVT_MENU, self.OnHelp, id=ID_HELP)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteShow, id=ID_AUTOCOMP_SHOW)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteMagic, id=ID_AUTOCOMP_MAGIC)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteSingle, id=ID_AUTOCOMP_SINGLE)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteDouble, id=ID_AUTOCOMP_DOUBLE)
self.Bind(wx.EVT_MENU, self.OnCallTipsShow, id=ID_CALLTIPS_SHOW)
self.Bind(wx.EVT_MENU, self.OnCallTipsInsert, id=ID_CALLTIPS_INSERT)
self.Bind(wx.EVT_MENU, self.OnWrap, id=ID_WRAP)
self.Bind(wx.EVT_MENU, self.OnToggleMaximize, id=ID_TOGGLE_MAXIMIZE)
self.Bind(wx.EVT_MENU, self.OnShowLineNumbers, id=ID_SHOW_LINENUMBERS)
self.Bind(wx.EVT_MENU, self.OnEnableShellMode, id=ID_ENABLESHELLMODE)
self.Bind(wx.EVT_MENU, self.OnEnableAutoSympy, id=ID_ENABLEAUTOSYMPY)
self.Bind(wx.EVT_MENU, self.OnAutoSaveSettings, id=ID_AUTO_SAVESETTINGS)
self.Bind(wx.EVT_MENU, self.OnSaveHistory, id=ID_SAVEHISTORY)
self.Bind(wx.EVT_MENU, self.OnSaveHistoryNow, id=ID_SAVEHISTORYNOW)
self.Bind(wx.EVT_MENU, self.OnClearHistory, id=ID_CLEARHISTORY)
self.Bind(wx.EVT_MENU, self.OnSaveSettings, id=ID_SAVESETTINGS)
self.Bind(wx.EVT_MENU, self.OnDelSettingsFile, id=ID_DELSETTINGSFILE)
self.Bind(wx.EVT_MENU, self.OnEditStartupScript, id=ID_EDITSTARTUPSCRIPT)
self.Bind(wx.EVT_MENU, self.OnExecStartupScript, id=ID_EXECSTARTUPSCRIPT)
self.Bind(wx.EVT_MENU, self.OnShowPySlicesTutorial, id=ID_SHOWPYSLICESTUTORIAL)
self.Bind(wx.EVT_MENU, self.OnFindText, id=ID_FIND)
self.Bind(wx.EVT_MENU, self.OnFindNext, id=ID_FINDNEXT)
self.Bind(wx.EVT_MENU, self.OnFindPrevious, id=ID_FINDPREVIOUS)
self.Bind(wx.EVT_MENU, self.OnToggleTools, id=ID_SHOWTOOLS)
self.Bind(wx.EVT_MENU, self.OnHideFoldingMargin, id=ID_HIDEFOLDINGMARGIN)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_NEW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_OPEN)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_REVERT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CLOSE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVEAS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_NAMESPACE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PRINT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_UNDO)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_REDO)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CUT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_COPY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_COPY_PLUS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PASTE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PASTE_PLUS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CLEAR)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SELECTALL)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EMPTYBUFFER)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_SHOW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_MAGIC)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_SINGLE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_DOUBLE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CALLTIPS_SHOW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CALLTIPS_INSERT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_WRAP)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SHOW_LINENUMBERS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_ENABLESHELLMODE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_ENABLEAUTOSYMPY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTO_SAVESETTINGS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVESETTINGS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_DELSETTINGSFILE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EXECSTARTUPSCRIPT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SHOWPYSLICESTUTORIAL)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVEHISTORY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVEHISTORYNOW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CLEARHISTORY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EDITSTARTUPSCRIPT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_FIND)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_FINDNEXT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_FINDPREVIOUS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SHOWTOOLS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_HIDEFOLDINGMARGIN)
self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
self.Bind(wx.EVT_FIND, self.OnFindNext)
self.Bind(wx.EVT_FIND_NEXT, self.OnFindNext)
self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
def OnShowLineNumbers(self, event):
win = wx.Window.FindFocus()
if hasattr(win, 'lineNumbers'):
win.lineNumbers = event.IsChecked()
win.setDisplayLineNumbers(win.lineNumbers)
def OnToggleMaximize(self, event):
self.Maximize(not self.IsMaximized())
def OnFileNew(self, event):
self.bufferNew()
def OnFileOpen(self, event):
self.bufferOpen()
def OnFileRevert(self, event):
self.bufferRevert()
def OnFileClose(self, event):
self.bufferClose()
def OnFileSave(self, event):
self.bufferSave()
def OnFileSaveAs(self, event):
self.bufferSaveAs()
def OnFileSaveACopy(self, event):
self.bufferSaveACopy()
def OnFileUpdateNamespace(self, event):
self.updateNamespace()
def OnFilePrint(self, event):
self.bufferPrint()
def OnExit(self, event):
self.Close(False)
def OnUndo(self, event):
win = wx.Window.FindFocus()
win.Undo()
def OnRedo(self, event):
win = wx.Window.FindFocus()
win.Redo()
def OnCut(self, event):
win = wx.Window.FindFocus()
win.Cut()
def OnCopy(self, event):
win = wx.Window.FindFocus()
win.Copy()
def OnCopyPlus(self, event):
win = wx.Window.FindFocus()
win.CopyWithPrompts()
def OnPaste(self, event):
win = wx.Window.FindFocus()
win.Paste()
def OnPastePlus(self, event):
win = wx.Window.FindFocus()
win.PasteAndRun()
def OnClear(self, event):
win = wx.Window.FindFocus()
win.Clear()
def OnEmptyBuffer(self, event):
win = wx.Window.FindFocus()
d = wx.MessageDialog(self,
"Are you sure you want to clear the edit buffer,\n"
"deleting all the text?",
"Empty Buffer", wx.OK | wx.CANCEL | wx.ICON_QUESTION)
answer = d.ShowModal()
d.Destroy()
if (answer == wx.ID_OK):
win.ClearAll()
if hasattr(win,'prompt'):
win.prompt()
def OnSelectAll(self, event):
win = wx.Window.FindFocus()
win.SelectAll()
def OnAbout(self, event):
"""Display an About window."""
title = 'About'
text = 'Your message here.'
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def OnHelp(self, event):
"""Display a Help window."""
title = 'Help'
text = "Type 'shell.help()' in the shell window."
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def OnAutoCompleteShow(self, event):
win = wx.Window.FindFocus()
win.autoComplete = event.IsChecked()
def OnAutoCompleteMagic(self, event):
win = wx.Window.FindFocus()
win.autoCompleteIncludeMagic = event.IsChecked()
def OnAutoCompleteSingle(self, event):
win = wx.Window.FindFocus()
win.autoCompleteIncludeSingle = event.IsChecked()
def OnAutoCompleteDouble(self, event):
win = wx.Window.FindFocus()
win.autoCompleteIncludeDouble = event.IsChecked()
def OnCallTipsShow(self, event):
win = wx.Window.FindFocus()
win.autoCallTip = event.IsChecked()
def OnCallTipsInsert(self, event):
win = wx.Window.FindFocus()
win.callTipInsert = event.IsChecked()
def OnWrap(self, event):
win = wx.Window.FindFocus()
win.SetWrapMode(event.IsChecked())
wx.CallLater(1, self.shell.EnsureCaretVisible)
def OnSaveHistory(self, event):
self.autoSaveHistory = event.IsChecked()
def OnSaveHistoryNow(self, event):
self.SaveHistory()
def OnClearHistory(self, event):
self.shell.clearHistory()
def OnEnableShellMode(self, event):
self.enableShellMode = event.IsChecked()
def OnEnableAutoSympy(self, event):
self.enableAutoSympy = event.IsChecked()
def OnHideFoldingMargin(self, event):
self.hideFoldingMargin = event.IsChecked()
def OnAutoSaveSettings(self, event):
self.autoSaveSettings = event.IsChecked()
def OnSaveSettings(self, event):
self.DoSaveSettings()
def OnDelSettingsFile(self, event):
if self.config is not None:
d = wx.MessageDialog(
self, "Do you want to revert to the default settings?\n" +
"A restart is needed for the change to take effect",
"Warning", wx.OK | wx.CANCEL | wx.ICON_QUESTION)
answer = d.ShowModal()
d.Destroy()
if (answer == wx.ID_OK):
self.config.DeleteAll()
self.LoadSettings()
def OnEditStartupScript(self, event):
if hasattr(self, 'EditStartupScript'):
self.EditStartupScript()
def OnExecStartupScript(self, event):
self.execStartupScript = event.IsChecked()
self.SaveSettings(force=True)
def OnShowPySlicesTutorial(self,event):
self.showPySlicesTutorial = event.IsChecked()
self.SaveSettings(force=True)
def OnFindText(self, event):
if self.findDlg is not None:
return
win = wx.Window.FindFocus()
if self.shellName == 'PyCrust':
self.findDlg = wx.FindReplaceDialog(win, self.findData,
"Find",wx.FR_NOWHOLEWORD)
else:
self.findDlg = wx.FindReplaceDialog(win, self.findData,
"Find & Replace", wx.FR_NOWHOLEWORD|wx.FR_REPLACEDIALOG)
self.findDlg.Show()
def OnFindNext(self, event,backward=False):
if backward and (self.findData.GetFlags() & wx.FR_DOWN):
self.findData.SetFlags( self.findData.GetFlags() ^ wx.FR_DOWN )
elif not backward and not (self.findData.GetFlags() & wx.FR_DOWN):
self.findData.SetFlags( self.findData.GetFlags() ^ wx.FR_DOWN )
if not self.findData.GetFindString():
self.OnFindText(event)
return
if isinstance(event, wx.FindDialogEvent):
win = self.findDlg.GetParent()
else:
win = wx.Window.FindFocus()
win.DoFindNext(self.findData, self.findDlg)
if self.findDlg is not None:
self.OnFindClose(None)
def OnFindPrevious(self, event):
self.OnFindNext(event,backward=True)
def OnFindClose(self, event):
self.findDlg.Destroy()
self.findDlg = None
def OnToggleTools(self, event):
self.ToggleTools()
def OnUpdateMenu(self, event):
"""Update menu items based on current status and context."""
win = wx.Window.FindFocus()
id = event.GetId()
event.Enable(True)
try:
if id == ID_NEW:
event.Enable(hasattr(self, 'bufferNew'))
elif id == ID_OPEN:
event.Enable(hasattr(self, 'bufferOpen'))
elif id == ID_REVERT:
event.Enable(hasattr(self, 'bufferRevert')
and self.hasBuffer())
elif id == ID_CLOSE:
event.Enable(hasattr(self, 'bufferClose')
and self.hasBuffer())
elif id == ID_SAVE:
event.Enable(hasattr(self, 'bufferSave')
and self.bufferHasChanged())
elif id == ID_SAVEAS:
event.Enable(hasattr(self, 'bufferSaveAs')
and self.hasBuffer())
elif id == ID_SAVEACOPY:
event.Enable(hasattr(self, 'bufferSaveACopy')
and self.hasBuffer())
elif id == ID_NAMESPACE:
event.Enable(hasattr(self, 'updateNamespace')
and self.hasBuffer())
elif id == ID_PRINT:
event.Enable(hasattr(self, 'bufferPrint')
and self.hasBuffer())
elif id == ID_UNDO:
event.Enable(win.CanUndo())
elif id == ID_REDO:
event.Enable(win.CanRedo())
elif id == ID_CUT:
event.Enable(win.CanCut())
elif id == ID_COPY:
event.Enable(win.CanCopy())
elif id == ID_COPY_PLUS:
event.Enable(win.CanCopy() and hasattr(win, 'CopyWithPrompts'))
elif id == ID_PASTE:
event.Enable(win.CanPaste())
elif id == ID_PASTE_PLUS:
event.Enable(win.CanPaste() and hasattr(win, 'PasteAndRun'))
elif id == ID_CLEAR:
event.Enable(win.CanCut())
elif id == ID_SELECTALL:
event.Enable(hasattr(win, 'SelectAll'))
elif id == ID_EMPTYBUFFER:
event.Enable(hasattr(win, 'ClearAll') and not win.GetReadOnly())
elif id == ID_AUTOCOMP_SHOW:
event.Check(win.autoComplete)
elif id == ID_AUTOCOMP_MAGIC:
event.Check(win.autoCompleteIncludeMagic)
elif id == ID_AUTOCOMP_SINGLE:
event.Check(win.autoCompleteIncludeSingle)
elif id == ID_AUTOCOMP_DOUBLE:
event.Check(win.autoCompleteIncludeDouble)
elif id == ID_CALLTIPS_SHOW:
event.Check(win.autoCallTip)
elif id == ID_CALLTIPS_INSERT:
event.Check(win.callTipInsert)
elif id == ID_WRAP:
event.Check(win.GetWrapMode())
elif id == ID_SHOW_LINENUMBERS:
event.Check(win.lineNumbers)
elif id == ID_ENABLESHELLMODE:
event.Check(self.enableShellMode)
event.Enable(self.config is not None)
elif id == ID_ENABLEAUTOSYMPY:
event.Check(self.enableAutoSympy)
event.Enable(self.config is not None)
elif id == ID_AUTO_SAVESETTINGS:
event.Check(self.autoSaveSettings)
event.Enable(self.config is not None)
elif id == ID_SAVESETTINGS:
event.Enable(self.config is not None and
hasattr(self, 'DoSaveSettings'))
elif id == ID_DELSETTINGSFILE:
event.Enable(self.config is not None)
elif id == ID_EXECSTARTUPSCRIPT:
event.Check(self.execStartupScript)
event.Enable(self.config is not None)
elif id == ID_SHOWPYSLICESTUTORIAL:
event.Check(self.showPySlicesTutorial)
event.Enable(self.config is not None)
elif id == ID_SAVEHISTORY:
event.Check(self.autoSaveHistory)
event.Enable(self.dataDir is not None)
elif id == ID_SAVEHISTORYNOW:
event.Enable(self.dataDir is not None and
hasattr(self, 'SaveHistory'))
elif id == ID_CLEARHISTORY:
event.Enable(self.dataDir is not None)
elif id == ID_EDITSTARTUPSCRIPT:
event.Enable(hasattr(self, 'EditStartupScript'))
event.Enable(self.dataDir is not None)
elif id == ID_FIND:
event.Enable(hasattr(win, 'DoFindNext'))
elif id == ID_FINDNEXT:
event.Enable(hasattr(win, 'DoFindNext'))
elif id == ID_FINDPREVIOUS:
event.Enable(hasattr(win, 'DoFindNext'))
elif id == ID_SHOWTOOLS:
event.Check(self.ToolsShown())
elif id == ID_HIDEFOLDINGMARGIN:
event.Check(self.hideFoldingMargin)
event.Enable(self.config is not None)
else:
event.Enable(False)
except AttributeError:
# This menu option is not supported in the current context.
event.Enable(False)
def OnActivate(self, event):
"""
Event Handler for losing the focus of the Frame. Should close
Autocomplete listbox, if shown.
"""
if not event.GetActive():
# If autocomplete active, cancel it. Otherwise, the
# autocomplete list will stay visible on top of the
# z-order after switching to another application
win = wx.Window.FindFocus()
if hasattr(win, 'AutoCompActive') and win.AutoCompActive():
win.AutoCompCancel()
event.Skip()
def LoadSettings(self, config):
"""Called by derived classes to load settings specific to the Frame"""
pos = wx.Point(config.ReadInt('Window/PosX', -1),
config.ReadInt('Window/PosY', -1))
size = wx.Size(config.ReadInt('Window/Width', -1),
config.ReadInt('Window/Height', -1))
self.SetSize(size)
self.Move(pos)
def SaveSettings(self, config):
"""Called by derived classes to save Frame settings to a wx.Config object"""
# TODO: track position/size so we can save it even if the
# frame is maximized or iconized.
if not self.iconized and not self.IsMaximized():
w, h = self.GetSize()
config.WriteInt('Window/Width', w)
config.WriteInt('Window/Height', h)
px, py = self.GetPosition()
config.WriteInt('Window/PosX', px)
config.WriteInt('Window/PosY', py)
class ShellFrameMixin:
"""
A mix-in class for frames that will have a Shell or a Crust window
and that want to add history, startupScript and other common
functionality.
"""
def __init__(self, config, dataDir):
self.config = config
self.dataDir = dataDir
self.startupScript = os.environ.get('PYTHONSTARTUP')
if not self.startupScript and self.dataDir:
self.startupScript = os.path.join(self.dataDir, 'startup')
self.autoSaveSettings = False
self.autoSaveHistory = False
# We need this one before we have a chance to load the settings...
self.execStartupScript = True
self.showPySlicesTutorial = True
self.enableShellMode = False
self.enableAutoSympy = True
self.hideFoldingMargin = False
if self.config:
self.execStartupScript = \
self.config.ReadBool('Options/ExecStartupScript', True)
self.showPySlicesTutorial = \
self.config.ReadBool('Options/ShowPySlicesTutorial', True)
self.enableShellMode = \
self.config.ReadBool('Options/EnableShellMode', False)
self.enableAutoSympy = \
self.config.ReadBool('Options/EnableAutoSympy', True)
self.hideFoldingMargin = \
self.config.ReadBool('Options/HideFoldingMargin', True)
def OnHelp(self, event):
"""Display a Help window."""
import wx.lib.dialogs
title = 'Help on key bindings'
text = wx.py.shell.HELP_TEXT
dlg = wx.lib.dialogs.ScrolledMessageDialog(self, text, title,
size = ((700, 540)))
fnt = wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
dlg.GetChildren()[0].SetFont(fnt)
dlg.GetChildren()[0].SetInsertionPoint(0)
dlg.ShowModal()
dlg.Destroy()
def LoadSettings(self):
if self.config is not None:
self.autoSaveSettings = \
self.config.ReadBool('Options/AutoSaveSettings', False)
self.execStartupScript = \
self.config.ReadBool('Options/ExecStartupScript', True)
self.autoSaveHistory = \
self.config.ReadBool('Options/AutoSaveHistory', False)
self.showPySlicesTutorial = \
self.config.ReadBool('Options/ShowPySlicesTutorial', True)
self.enableShellMode = \
self.config.ReadBool('Options/EnableShellMode', False)
self.enableAutoSympy = \
self.config.ReadBool('Options/EnableAutoSympy', True)
self.hideFoldingMargin = \
self.config.ReadBool('Options/HideFoldingMargin', True)
self.LoadHistory()
def SaveSettings(self, force=False):
if self.config is not None:
# always save these
self.config.WriteBool('Options/AutoSaveSettings',
self.autoSaveSettings)
if self.autoSaveSettings or force:
self.config.WriteBool('Options/AutoSaveHistory',
self.autoSaveHistory)
self.config.WriteBool('Options/ExecStartupScript',
self.execStartupScript)
self.config.WriteBool('Options/ShowPySlicesTutorial',
self.showPySlicesTutorial)
self.config.WriteBool('Options/EnableShellMode',
self.enableShellMode)
self.config.WriteBool('Options/EnableAutoSympy',
self.enableAutoSympy)
self.config.WriteBool('Options/HideFoldingMargin',
self.hideFoldingMargin)
if self.autoSaveHistory:
self.SaveHistory()
def SaveHistory(self):
if self.dataDir:
try:
enc = 'utf-8'
hist = b'\x00\n'.join([h.encode(enc)
for h in self.shell.history])
name = os.path.join(self.dataDir, 'history')
with open(name, 'wb') as f:
f.write(hist)
except:
d = wx.MessageDialog(self, "Error saving history file.",
"Error", wx.ICON_EXCLAMATION|wx.OK)
d.ShowModal()
d.Destroy()
raise
def LoadHistory(self):
if self.dataDir:
name = os.path.join(self.dataDir, 'history')
if os.path.exists(name):
try:
with open(name, 'rb') as f:
hist = f.read()
enc = 'utf-8'
hist = [h.decode(enc) for h in hist.split(b'\x00\n')]
self.shell.history = hist
dispatcher.send(signal="Shell.loadHistory",
history=self.shell.history)
except:
import traceback
traceback.print_exc()
d = wx.MessageDialog(self, "Error loading history file.",
"Error", wx.ICON_EXCLAMATION|wx.OK)
d.ShowModal()
d.Destroy()
def bufferHasChanged(self):
# the shell buffers can always be saved
return True
def bufferSave(self):
import time
appname = wx.GetApp().GetAppName()
default = appname + '-' + time.strftime("%Y%m%d-%H%M.py")
fileName = wx.FileSelector("Save File As", "Saving",
default_filename=default,
default_extension="py",
wildcard="*.py",
flags = wx.SAVE | wx.OVERWRITE_PROMPT)
if not fileName:
return
text = self.shell.GetText()
## This isn't working currently...
## d = wx.MessageDialog(self,u'Save source code only?\n' + \
## 'Answering yes will only save lines starting with >>> and ...',
## u'Question', wx.YES_NO | wx.ICON_QUESTION)
## yes_no = d.ShowModal()
## if yes_no == wx.ID_YES:
## m = re.findall('^[>\.]{3,3} (.*)\r', text, re.MULTILINE | re.LOCALE)
## text = '\n'.join(m)
## d.Destroy()
try:
with open(fileName, "w") as f:
f.write(text)
except:
d = wx.MessageDialog(self, u'Error saving session',u'Error',
wx.OK | wx.ICON_ERROR)
d.ShowModal()
d.Destroy()
def EditStartupScript(self):
if os.path.exists(self.startupScript):
import io
# Use newline=None to translate \n \r \r\n to \n on read. The
# old-style mode='U' is deprecated.
with io.open(self.startupScript, 'r', newline=None, encoding='utf-8') as fid:
text = fid.read()
else:
text = ''
dlg = EditStartupScriptDialog(self, self.startupScript, text)
if dlg.ShowModal() == wx.ID_OK:
text = dlg.GetText()
try:
with open(self.startupScript, 'wb') as f:
f.write(text.encode('utf-8'))
except:
d = wx.MessageDialog(self, "Error saving startup file.",
"Error", wx.ICON_EXCLAMATION|wx.OK)
d.ShowModal()
d.Destroy()
class EditStartupScriptDialog(wx.Dialog):
def __init__(self, parent, fileName, text):
wx.Dialog.__init__(self, parent, size=(425,350),
title="Edit Startup Script",
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
pst = wx.StaticText(self, -1, "Path:")
ptx = wx.TextCtrl(self, -1, fileName, style=wx.TE_READONLY)
self.editor = editwindow.EditWindow(self)
self.editor.SetText(text)
wx.CallAfter(self.editor.SetFocus)
ok = wx.Button(self, wx.ID_OK)
cancel = wx.Button(self, wx.ID_CANCEL)
mainSizer = wx.BoxSizer(wx.VERTICAL)
pthSizer = wx.BoxSizer(wx.HORIZONTAL)
pthSizer.Add(pst, flag=wx.ALIGN_CENTER_VERTICAL)
pthSizer.Add((5,5))
pthSizer.Add(ptx, 1)
mainSizer.Add(pthSizer, 0, wx.EXPAND|wx.ALL, 10)
mainSizer.Add(self.editor, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add((5,5), 1)
btnSizer.Add(ok)
btnSizer.Add((5,5), 1)
btnSizer.Add(cancel)
btnSizer.Add((5,5), 1)
mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.ALL, 10)
self.SetSizer(mainSizer)
self.Layout()
def GetText(self):
return self.editor.GetText()