Merged modifications from the 2.6 branch
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@36607 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,3 +1,81 @@
|
||||
0.9.5 (12/23/2005)
|
||||
-------------------
|
||||
|
||||
Applied a series of enhancments by Franz Steinaeusler, Adi Sieker, and
|
||||
Sebastian Haase, up until their 7-31-2005 version. (Their next
|
||||
version broke some existing functionality, and added some confusing
|
||||
hacks, and I didn't feel that the incremental gains were worth the
|
||||
loss at that point so I stopped at 7-31-2005.)
|
||||
|
||||
Their changes include the following:
|
||||
|
||||
* The Autocomplete and Calltip windows can now be opened manually with
|
||||
Ctrl-Space and Ctrl-Shift-Space.
|
||||
|
||||
* In the stand alone PyCrust app the various option settings, window
|
||||
size and position, and etc. are saved and restored at the next run.
|
||||
|
||||
* Added a help dialog bound to the F1 key that shows the key bindings.
|
||||
|
||||
* Added a new text completion function that suggests words from the
|
||||
history. Bound to Shift-Return.
|
||||
|
||||
* F11 will toggle the maximized state of the frame.
|
||||
|
||||
* switched to Bind() from wx.EVT_*().
|
||||
|
||||
* Display of line numbers can be toggled.
|
||||
|
||||
* F12 toggles a "free edit" mode of the shell buffer. This mode is
|
||||
useful, for example, if you would like to remove some output or
|
||||
errors or etc. from the buffer before doing a copy/paste. The free
|
||||
edit mode is designated by the use of a red, non-flashing caret.
|
||||
|
||||
* Ctrl-H will fold/unfold (hide/show) the selected lines.
|
||||
|
||||
|
||||
|
||||
On top of these changes I (Robin Dunn) added the following:
|
||||
|
||||
* General code cleanup and fixes.
|
||||
|
||||
* Use wx.StandardPaths to determine the location of the config files.
|
||||
|
||||
* Remove Orbtech attributions from the UI, they've been there long
|
||||
enough.
|
||||
|
||||
* Use wx.SP_LIVE_UPDATE on crust and filling windows.
|
||||
|
||||
* Extended the saving of the config info and other new features to the
|
||||
PyShell app too. Additionally, other apps that embed a PyCrust or a
|
||||
PyShell can pass their own wx.Config object and have the Py code
|
||||
save/restore its settings to/from there.
|
||||
|
||||
* All of the classes with config info get an opportunity to save/load
|
||||
their own settings instead of putting all the save/load code in one
|
||||
place that then has to reach all over the place to do anything.
|
||||
|
||||
* Enable editing of the startup python code, which will either be the
|
||||
file pointed to by PYTHONSTARTUP or a file in the config dir if
|
||||
PYTHONSTARTUP is not set in the environment.
|
||||
|
||||
* Added an option to skip the running of the startup code when
|
||||
PyShell or PyCrust starts.
|
||||
|
||||
* PyCrust adds a pp(item) function to the shell's namespace that
|
||||
pretty prints the item in the Display tab of the notebook. Added
|
||||
code to raise that tab when pp() is called.
|
||||
|
||||
* Added an option for whether to insert text for function parameters
|
||||
when popping up the call tip.
|
||||
|
||||
* Added Find and Find-Next functions that use the wx.FindReplaceDialog.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
0.9.4 (1/25/2004 to //2004)
|
||||
------------------------------
|
||||
|
||||
|
@@ -17,15 +17,26 @@ class App(wx.App):
|
||||
"""PyCrust standalone application."""
|
||||
|
||||
def OnInit(self):
|
||||
import os
|
||||
import wx
|
||||
from wx import py
|
||||
wx.InitAllImageHandlers()
|
||||
self.frame = py.crust.CrustFrame()
|
||||
self.frame.SetSize((800, 600))
|
||||
|
||||
self.SetAppName("pycrust")
|
||||
confDir = wx.StandardPaths.Get().GetUserDataDir()
|
||||
if not os.path.exists(confDir):
|
||||
os.mkdir(confDir)
|
||||
fileName = os.path.join(confDir, 'config')
|
||||
self.config = wx.FileConfig(localFilename=fileName)
|
||||
self.config.SetRecordDefaults(True)
|
||||
|
||||
self.frame = py.crust.CrustFrame(config=self.config, dataDir=confDir)
|
||||
## self.frame.startupFileName = os.path.join(confDir,'pycrust_startup')
|
||||
## self.frame.historyFileName = os.path.join(confDir,'pycrust_history')
|
||||
self.frame.Show()
|
||||
self.SetTopWindow(self.frame)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
'''
|
||||
The main() function needs to handle being imported, such as with the
|
||||
pycrust script that wxPython installs:
|
||||
|
@@ -17,14 +17,21 @@ class App(wx.App):
|
||||
"""PyShell standalone application."""
|
||||
|
||||
def OnInit(self):
|
||||
import os
|
||||
import wx
|
||||
from wx import py
|
||||
wx.InitAllImageHandlers()
|
||||
self.frame = py.shell.ShellFrame()
|
||||
self.frame.SetSize((750, 525))
|
||||
|
||||
self.SetAppName("pyshell")
|
||||
confDir = wx.StandardPaths.Get().GetUserDataDir()
|
||||
if not os.path.exists(confDir):
|
||||
os.mkdir(confDir)
|
||||
fileName = os.path.join(confDir, 'config')
|
||||
self.config = wx.FileConfig(localFilename=fileName)
|
||||
self.config.SetRecordDefaults(True)
|
||||
|
||||
self.frame = py.shell.ShellFrame(config=self.config, dataDir=confDir)
|
||||
self.frame.Show()
|
||||
self.SetTopWindow(self.frame)
|
||||
self.frame.shell.SetFocus()
|
||||
return True
|
||||
|
||||
'''
|
||||
|
@@ -8,6 +8,7 @@ import wx
|
||||
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
import sys
|
||||
|
||||
import dispatcher
|
||||
@@ -23,55 +24,95 @@ class Crust(wx.SplitterWindow):
|
||||
|
||||
name = 'Crust'
|
||||
revision = __revision__
|
||||
sashoffset = 300
|
||||
|
||||
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
|
||||
size=wx.DefaultSize, style=wx.SP_3D,
|
||||
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
|
||||
size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
|
||||
name='Crust Window', rootObject=None, rootLabel=None,
|
||||
rootIsNamespace=True, intro='', locals=None,
|
||||
InterpClass=None, *args, **kwds):
|
||||
rootIsNamespace=True, intro='', locals=None,
|
||||
InterpClass=None,
|
||||
startupScript=None, execStartupScript=True,
|
||||
*args, **kwds):
|
||||
"""Create Crust instance."""
|
||||
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
|
||||
self.shell = Shell(parent=self, introText=intro,
|
||||
locals=locals, InterpClass=InterpClass,
|
||||
self.shell = Shell(parent=self, introText=intro,
|
||||
locals=locals, InterpClass=InterpClass,
|
||||
startupScript=startupScript,
|
||||
execStartupScript=execStartupScript,
|
||||
*args, **kwds)
|
||||
self.editor = self.shell
|
||||
if rootObject is None:
|
||||
rootObject = self.shell.interp.locals
|
||||
self.notebook = wx.Notebook(parent=self, id=-1)
|
||||
self.shell.interp.locals['notebook'] = self.notebook
|
||||
self.filling = Filling(parent=self.notebook,
|
||||
rootObject=rootObject,
|
||||
rootLabel=rootLabel,
|
||||
self.filling = Filling(parent=self.notebook,
|
||||
rootObject=rootObject,
|
||||
rootLabel=rootLabel,
|
||||
rootIsNamespace=rootIsNamespace)
|
||||
# Add 'filling' to the interpreter's locals.
|
||||
self.shell.interp.locals['filling'] = self.filling
|
||||
self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
|
||||
|
||||
self.display = Display(parent=self.notebook)
|
||||
self.notebook.AddPage(page=self.display, text='Display')
|
||||
# Add 'pp' (pretty print) to the interpreter's locals.
|
||||
self.shell.interp.locals['pp'] = self.display.setItem
|
||||
self.display.nbTab = self.notebook.GetPageCount()-1
|
||||
|
||||
self.calltip = Calltip(parent=self.notebook)
|
||||
self.notebook.AddPage(page=self.calltip, text='Calltip')
|
||||
|
||||
self.sessionlisting = SessionListing(parent=self.notebook)
|
||||
self.notebook.AddPage(page=self.sessionlisting, text='Session')
|
||||
|
||||
self.dispatcherlisting = DispatcherListing(parent=self.notebook)
|
||||
self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
|
||||
## from wxd import wx_
|
||||
## self.wxdocs = Filling(parent=self.notebook,
|
||||
## rootObject=wx_,
|
||||
## rootLabel='wx',
|
||||
## rootIsNamespace=False,
|
||||
## static=True)
|
||||
## self.notebook.AddPage(page=self.wxdocs, text='wxPython Docs')
|
||||
## from wxd import stc_
|
||||
## self.stcdocs = Filling(parent=self.notebook,
|
||||
## rootObject=stc_.StyledTextCtrl,
|
||||
## rootLabel='StyledTextCtrl',
|
||||
## rootIsNamespace=False,
|
||||
## static=True)
|
||||
## self.notebook.AddPage(page=self.stcdocs, text='StyledTextCtrl Docs')
|
||||
self.SplitHorizontally(self.shell, self.notebook, 300)
|
||||
self.SetMinimumPaneSize(1)
|
||||
|
||||
self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
|
||||
self.SetMinimumPaneSize(100)
|
||||
|
||||
self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
|
||||
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
|
||||
|
||||
|
||||
def OnChanged(self, event):
|
||||
"""update sash offset from the bottom of the window"""
|
||||
self.sashoffset = self.GetSize().height - event.GetSashPosition()
|
||||
event.Skip()
|
||||
|
||||
|
||||
# Make the splitter expand the top window when resized
|
||||
def SplitterOnSize(self, event):
|
||||
splitter = event.GetEventObject()
|
||||
sz = splitter.GetSize()
|
||||
splitter.SetSashPosition(sz.height - self.sashoffset, True)
|
||||
event.Skip()
|
||||
|
||||
|
||||
def LoadSettings(self, config):
|
||||
self.shell.LoadSettings(config)
|
||||
self.filling.LoadSettings(config)
|
||||
|
||||
pos = config.ReadInt('Sash/CrustPos', 400)
|
||||
wx.CallAfter(self.SetSashPosition, pos)
|
||||
def _updateSashPosValue():
|
||||
sz = self.GetSize()
|
||||
self.sashoffset = sz.height - self.GetSashPosition()
|
||||
wx.CallAfter(_updateSashPosValue)
|
||||
zoom = config.ReadInt('View/Zoom/Display', -99)
|
||||
if zoom != -99:
|
||||
self.display.SetZoom(zoom)
|
||||
|
||||
|
||||
def SaveSettings(self, config):
|
||||
self.shell.SaveSettings(config)
|
||||
self.filling.SaveSettings(config)
|
||||
|
||||
config.WriteInt('Sash/CrustPos', self.GetSashPosition())
|
||||
config.WriteInt('View/Zoom/Display', self.display.GetZoom())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Display(editwindow.EditWindow):
|
||||
@@ -105,15 +146,20 @@ class Display(editwindow.EditWindow):
|
||||
"""Set item to pretty print in the notebook Display tab."""
|
||||
self.item = item
|
||||
self.Refresh()
|
||||
if self.GetParent().GetSelection() != self.nbTab:
|
||||
focus = wx.Window.FindFocus()
|
||||
self.GetParent().SetSelection(self.nbTab)
|
||||
wx.CallAfter(focus.SetFocus)
|
||||
|
||||
|
||||
|
||||
# TODO: Switch this to a editwindow.EditWindow
|
||||
class Calltip(wx.TextCtrl):
|
||||
"""Text control containing the most recent shell calltip."""
|
||||
|
||||
def __init__(self, parent=None, id=-1):
|
||||
style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
|
||||
wx.TextCtrl.__init__(self, parent, id, style=style)
|
||||
self.SetBackgroundColour(wx.Colour(255, 255, 232))
|
||||
self.SetBackgroundColour(wx.Colour(255, 255, 208))
|
||||
dispatcher.connect(receiver=self.display, signal='Shell.calltip')
|
||||
|
||||
def display(self, calltip):
|
||||
@@ -123,6 +169,7 @@ class Calltip(wx.TextCtrl):
|
||||
self.AppendText(calltip)
|
||||
|
||||
|
||||
# TODO: Switch this to a editwindow.EditWindow
|
||||
class SessionListing(wx.TextCtrl):
|
||||
"""Text control containing all commands for session."""
|
||||
|
||||
@@ -161,44 +208,58 @@ class DispatcherListing(wx.TextCtrl):
|
||||
self.AppendText(text + '\n')
|
||||
|
||||
|
||||
class CrustFrame(frame.Frame):
|
||||
|
||||
class CrustFrame(frame.Frame, frame.ShellFrameMixin):
|
||||
"""Frame containing all the PyCrust components."""
|
||||
|
||||
name = 'CrustFrame'
|
||||
revision = __revision__
|
||||
|
||||
|
||||
def __init__(self, parent=None, id=-1, title='PyCrust',
|
||||
pos=wx.DefaultPosition, size=wx.DefaultSize,
|
||||
style=wx.DEFAULT_FRAME_STYLE,
|
||||
rootObject=None, rootLabel=None, rootIsNamespace=True,
|
||||
locals=None, InterpClass=None, *args, **kwds):
|
||||
locals=None, InterpClass=None,
|
||||
config=None, dataDir=None,
|
||||
*args, **kwds):
|
||||
"""Create CrustFrame instance."""
|
||||
frame.Frame.__init__(self, parent, id, title, pos, size, style)
|
||||
frame.ShellFrameMixin.__init__(self, config, dataDir)
|
||||
|
||||
if size == wx.DefaultSize:
|
||||
self.SetSize((800, 600))
|
||||
|
||||
intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
|
||||
intro += '\nSponsored by Orbtech - '
|
||||
intro += 'Your source for Python programming expertise.'
|
||||
self.SetStatusText(intro.replace('\n', ', '))
|
||||
self.crust = Crust(parent=self, intro=intro,
|
||||
rootObject=rootObject,
|
||||
rootLabel=rootLabel,
|
||||
rootIsNamespace=rootIsNamespace,
|
||||
locals=locals,
|
||||
InterpClass=InterpClass, *args, **kwds)
|
||||
InterpClass=InterpClass,
|
||||
startupScript=self.startupScript,
|
||||
execStartupScript=self.execStartupScript,
|
||||
*args, **kwds)
|
||||
self.shell = self.crust.shell
|
||||
|
||||
# Override the filling so that status messages go to the status bar.
|
||||
self.crust.filling.tree.setStatusText = self.SetStatusText
|
||||
|
||||
# Override the shell so that status messages go to the status bar.
|
||||
self.shell.setStatusText = self.SetStatusText
|
||||
# Fix a problem with the sash shrinking to nothing.
|
||||
self.crust.filling.SetSashPosition(200)
|
||||
# Set focus to the shell editor.
|
||||
|
||||
self.shell.SetFocus()
|
||||
self.LoadSettings()
|
||||
|
||||
|
||||
def OnClose(self, event):
|
||||
"""Event handler for closing."""
|
||||
self.SaveSettings()
|
||||
self.crust.shell.destroy()
|
||||
self.Destroy()
|
||||
|
||||
|
||||
def OnAbout(self, event):
|
||||
"""Display an About window."""
|
||||
title = 'About PyCrust'
|
||||
@@ -211,8 +272,33 @@ class CrustFrame(frame.Frame):
|
||||
'Platform: %s\n' % sys.platform + \
|
||||
'Python Version: %s\n' % sys.version.split()[0] + \
|
||||
'wxPython Version: %s\n' % wx.VERSION_STRING + \
|
||||
('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
|
||||
('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
|
||||
dialog = wx.MessageDialog(self, text, title,
|
||||
wx.OK | wx.ICON_INFORMATION)
|
||||
dialog.ShowModal()
|
||||
dialog.Destroy()
|
||||
|
||||
|
||||
|
||||
def LoadSettings(self):
|
||||
if self.config is not None:
|
||||
frame.ShellFrameMixin.LoadSettings(self)
|
||||
frame.Frame.LoadSettings(self, self.config)
|
||||
self.crust.LoadSettings(self.config)
|
||||
|
||||
|
||||
def SaveSettings(self):
|
||||
if self.config is not None:
|
||||
frame.ShellFrameMixin.SaveSettings(self)
|
||||
if self.autoSaveSettings:
|
||||
frame.Frame.SaveSettings(self, self.config)
|
||||
self.crust.SaveSettings(self.config)
|
||||
|
||||
|
||||
def DoSaveSettings(self):
|
||||
if self.config is not None:
|
||||
self.SaveSettings()
|
||||
self.config.Flush()
|
||||
|
||||
|
||||
|
||||
|
@@ -30,7 +30,7 @@ class EditorFrame(frame.Frame):
|
||||
self._defaultText = title + ' - the tastiest Python editor.'
|
||||
self._statusText = self._defaultText
|
||||
self.SetStatusText(self._statusText)
|
||||
wx.EVT_IDLE(self, self.OnIdle)
|
||||
self.Bind(wx.EVT_IDLE, self.OnIdle)
|
||||
self._setup()
|
||||
if filename:
|
||||
self.bufferCreate(filename)
|
||||
@@ -137,7 +137,7 @@ class EditorFrame(frame.Frame):
|
||||
self.bufferDestroy()
|
||||
buffer = Buffer()
|
||||
self.panel = panel = wx.Panel(parent=self, id=-1)
|
||||
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
|
||||
panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
|
||||
editor = Editor(parent=panel)
|
||||
panel.editor = editor
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
@@ -318,7 +318,7 @@ class EditorNotebookFrame(EditorFrame):
|
||||
"""Create new buffer."""
|
||||
buffer = Buffer()
|
||||
panel = wx.Panel(parent=self.notebook, id=-1)
|
||||
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
|
||||
panel.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: x)
|
||||
editor = Editor(parent=panel)
|
||||
panel.editor = editor
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
@@ -366,11 +366,9 @@ class EditorNotebook(wx.Notebook):
|
||||
def __init__(self, parent):
|
||||
"""Create EditorNotebook instance."""
|
||||
wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
|
||||
wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
|
||||
self.OnPageChanging)
|
||||
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
|
||||
self.OnPageChanged)
|
||||
wx.EVT_IDLE(self, self.OnIdle)
|
||||
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging, id=self.GetId())
|
||||
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
|
||||
self.Bind(wx.EVT_IDLE, self.OnIdle)
|
||||
|
||||
def OnIdle(self, event):
|
||||
"""Event handler for idle time."""
|
||||
@@ -552,7 +550,7 @@ class EditorShellNotebook(wx.Notebook):
|
||||
self.AddPage(page=self.editor.window, text='Editor', select=True)
|
||||
self.AddPage(page=self.shell, text='Shell')
|
||||
self.editor.setFocus()
|
||||
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
|
||||
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
|
||||
|
||||
def OnPageChanged(self, event):
|
||||
"""Page changed event handler."""
|
||||
@@ -583,8 +581,8 @@ class Editor:
|
||||
self.id = self.window.GetId()
|
||||
self.buffer = None
|
||||
# Assign handlers for keyboard events.
|
||||
wx.EVT_CHAR(self.window, self.OnChar)
|
||||
wx.EVT_KEY_DOWN(self.window, self.OnKeyDown)
|
||||
self.window.Bind(wx.EVT_CHAR, self.OnChar)
|
||||
self.window.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
|
||||
|
||||
def _setBuffer(self, buffer, text):
|
||||
"""Set the editor to a buffer. Private callback called by buffer."""
|
||||
|
@@ -92,11 +92,10 @@ class EditWindow(stc.StyledTextCtrl):
|
||||
size = 0
|
||||
self.SetZoom(size)
|
||||
|
||||
def __config(self):
|
||||
"""Configure shell based on user preferences."""
|
||||
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
|
||||
self.SetMarginWidth(1, 40)
|
||||
|
||||
def __config(self):
|
||||
self.setDisplayLineNumbers(False)
|
||||
|
||||
self.SetLexer(stc.STC_LEX_PYTHON)
|
||||
self.SetKeyWords(0, ' '.join(keyword.kwlist))
|
||||
|
||||
@@ -116,6 +115,7 @@ class EditWindow(stc.StyledTextCtrl):
|
||||
self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
|
||||
# Do we want to automatically pop up command argument help?
|
||||
self.autoCallTip = True
|
||||
self.callTipInsert = True
|
||||
self.CallTipSetBackground(FACES['calltipbg'])
|
||||
self.CallTipSetForeground(FACES['calltipfg'])
|
||||
self.SetWrapMode(False)
|
||||
@@ -124,6 +124,16 @@ class EditWindow(stc.StyledTextCtrl):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def setDisplayLineNumbers(self, state):
|
||||
self.lineNumbers = state
|
||||
if state:
|
||||
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
|
||||
self.SetMarginWidth(1, 40)
|
||||
else:
|
||||
# Leave a small margin so the feature hidden lines marker can be seen
|
||||
self.SetMarginType(1, 0)
|
||||
self.SetMarginWidth(1, 10)
|
||||
|
||||
def setStyles(self, faces):
|
||||
"""Configure font size, typeface and color for lexer."""
|
||||
|
||||
@@ -136,7 +146,7 @@ class EditWindow(stc.StyledTextCtrl):
|
||||
|
||||
# Built in styles
|
||||
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,
|
||||
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
|
||||
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % FACES)
|
||||
self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR,
|
||||
"face:%(mono)s" % faces)
|
||||
self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
|
||||
@@ -223,3 +233,65 @@ class EditWindow(stc.StyledTextCtrl):
|
||||
def CanPaste(self):
|
||||
"""Return True if pasting should succeed."""
|
||||
return stc.StyledTextCtrl.CanPaste(self) and self.CanEdit()
|
||||
|
||||
|
||||
def GetLastPosition(self):
|
||||
return self.GetLength()
|
||||
|
||||
def GetRange(self, start, end):
|
||||
return self.GetTextRange(start, end)
|
||||
|
||||
def GetSelection(self):
|
||||
return self.GetAnchor(), self.GetCurrentPos()
|
||||
|
||||
def SetSelection(self, start, end):
|
||||
self.SetSelectionStart(start)
|
||||
self.SetSelectionEnd(end)
|
||||
|
||||
def ShowPosition(self, pos):
|
||||
line = self.LineFromPosition(pos)
|
||||
#self.EnsureVisible(line)
|
||||
self.GotoLine(line)
|
||||
|
||||
def DoFindNext(self, findData, findDlg=None):
|
||||
backward = not (findData.GetFlags() & wx.FR_DOWN)
|
||||
matchcase = findData.GetFlags() & wx.FR_MATCHCASE
|
||||
end = self.GetLastPosition()
|
||||
textstring = self.GetRange(0, end)
|
||||
findstring = findData.GetFindString()
|
||||
if not matchcase:
|
||||
textstring.lower()
|
||||
findstring.lower()
|
||||
if backward:
|
||||
start = self.GetSelection()[0]
|
||||
loc = textstring.rfind(findstring, 0, start)
|
||||
else:
|
||||
start = self.GetSelection()[1]
|
||||
loc = textstring.find(findstring, start)
|
||||
|
||||
# if it wasn't found then restart at begining
|
||||
if loc == -1 and start != 0:
|
||||
if backward:
|
||||
start = end
|
||||
loc = textstring.rfind(findstring, 0, start)
|
||||
else:
|
||||
start = 0
|
||||
loc = textstring.find(findstring, start)
|
||||
|
||||
# was it still not found?
|
||||
if loc == -1:
|
||||
dlg = wx.MessageDialog(self, 'Unable to find the search text.',
|
||||
'Not found!',
|
||||
wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
if findDlg:
|
||||
if loc == -1:
|
||||
wx.CallAfter(findDlg.SetFocus)
|
||||
return
|
||||
else:
|
||||
findDlg.Close()
|
||||
|
||||
# show and select the found text
|
||||
self.ShowPosition(loc)
|
||||
self.SetSelection(loc, loc + len(findstring))
|
||||
|
@@ -61,10 +61,10 @@ class FillingTree(wx.TreeCtrl):
|
||||
rootData = wx.TreeItemData(rootObject)
|
||||
self.item = self.root = self.AddRoot(rootLabel, -1, -1, rootData)
|
||||
self.SetItemHasChildren(self.root, self.objHasChildren(rootObject))
|
||||
wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
|
||||
wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
|
||||
wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
|
||||
wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
|
||||
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding, id=self.GetId())
|
||||
self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=self.GetId())
|
||||
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=self.GetId())
|
||||
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated, id=self.GetId())
|
||||
if not static:
|
||||
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
|
||||
|
||||
@@ -277,24 +277,49 @@ class Filling(wx.SplitterWindow):
|
||||
revision = __revision__
|
||||
|
||||
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
|
||||
size=wx.DefaultSize, style=wx.SP_3D,
|
||||
size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
|
||||
name='Filling Window', rootObject=None,
|
||||
rootLabel=None, rootIsNamespace=False, static=False):
|
||||
"""Create a Filling instance."""
|
||||
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
|
||||
|
||||
self.tree = FillingTree(parent=self, rootObject=rootObject,
|
||||
rootLabel=rootLabel,
|
||||
rootIsNamespace=rootIsNamespace,
|
||||
static=static)
|
||||
self.text = FillingText(parent=self, static=static)
|
||||
self.SplitVertically(self.tree, self.text, 130)
|
||||
|
||||
wx.FutureCall(1, self.SplitVertically, self.tree, self.text, 200)
|
||||
|
||||
self.SetMinimumPaneSize(1)
|
||||
|
||||
# Override the filling so that descriptions go to FillingText.
|
||||
self.tree.setText = self.text.SetText
|
||||
|
||||
# Display the root item.
|
||||
## self.tree.SelectItem(self.tree.root)
|
||||
self.tree.SelectItem(self.tree.root)
|
||||
self.tree.display()
|
||||
|
||||
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
|
||||
|
||||
def OnChanged(self, event):
|
||||
#this is important: do not evaluate this event=> otherwise, splitterwindow behaves strange
|
||||
#event.Skip()
|
||||
pass
|
||||
|
||||
|
||||
def LoadSettings(self, config):
|
||||
pos = config.ReadInt('Sash/FillingPos', 200)
|
||||
wx.FutureCall(250, self.SetSashPosition, pos)
|
||||
zoom = config.ReadInt('View/Zoom/Filling', -99)
|
||||
if zoom != -99:
|
||||
self.text.SetZoom(zoom)
|
||||
|
||||
def SaveSettings(self, config):
|
||||
config.WriteInt('Sash/FillingPos', self.GetSashPosition())
|
||||
config.WriteInt('View/Zoom/Filling', self.text.GetZoom())
|
||||
|
||||
|
||||
|
||||
class FillingFrame(wx.Frame):
|
||||
"""Frame containing the namespace tree component."""
|
||||
|
@@ -5,8 +5,9 @@ __cvsid__ = "$Id$"
|
||||
__revision__ = "$Revision$"[11:-2]
|
||||
|
||||
import wx
|
||||
import os
|
||||
from version import VERSION
|
||||
|
||||
import editwindow
|
||||
|
||||
ID_NEW = wx.ID_NEW
|
||||
ID_OPEN = wx.ID_OPEN
|
||||
@@ -23,7 +24,9 @@ ID_COPY = wx.ID_COPY
|
||||
ID_PASTE = wx.ID_PASTE
|
||||
ID_CLEAR = wx.ID_CLEAR
|
||||
ID_SELECTALL = wx.ID_SELECTALL
|
||||
ID_EMPTYBUFFER = wx.NewId()
|
||||
ID_ABOUT = wx.ID_ABOUT
|
||||
ID_HELP = wx.NewId()
|
||||
ID_AUTOCOMP = wx.NewId()
|
||||
ID_AUTOCOMP_SHOW = wx.NewId()
|
||||
ID_AUTOCOMP_MAGIC = wx.NewId()
|
||||
@@ -31,11 +34,25 @@ ID_AUTOCOMP_SINGLE = wx.NewId()
|
||||
ID_AUTOCOMP_DOUBLE = wx.NewId()
|
||||
ID_CALLTIPS = wx.NewId()
|
||||
ID_CALLTIPS_SHOW = wx.NewId()
|
||||
ID_CALLTIPS_INSERT = wx.NewId()
|
||||
ID_COPY_PLUS = wx.NewId()
|
||||
ID_NAMESPACE = wx.NewId()
|
||||
ID_PASTE_PLUS = wx.NewId()
|
||||
ID_WRAP = wx.NewId()
|
||||
ID_TOGGLE_MAXIMIZE = wx.NewId()
|
||||
ID_USEAA = wx.NewId()
|
||||
ID_SHOW_LINENUMBERS = wx.NewId()
|
||||
ID_AUTO_SAVESETTINGS = wx.NewId()
|
||||
ID_SAVEHISTORY = wx.NewId()
|
||||
ID_SAVESETTINGS = wx.NewId()
|
||||
ID_DELSETTINGSFILE = wx.NewId()
|
||||
ID_EDITSTARTUPSCRIPT = wx.NewId()
|
||||
ID_EXECSTARTUPSCRIPT = wx.NewId()
|
||||
ID_STARTUP = wx.NewId()
|
||||
ID_SETTINGS = wx.NewId()
|
||||
ID_FIND = wx.ID_FIND
|
||||
ID_FINDNEXT = wx.NewId()
|
||||
|
||||
|
||||
|
||||
class Frame(wx.Frame):
|
||||
@@ -53,13 +70,28 @@ class Frame(wx.Frame):
|
||||
import images
|
||||
self.SetIcon(images.getPyIcon())
|
||||
self.__createMenus()
|
||||
wx.EVT_CLOSE(self, self.OnClose)
|
||||
|
||||
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.Iconized()
|
||||
|
||||
|
||||
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')
|
||||
@@ -73,17 +105,18 @@ class Frame(wx.Frame):
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_SAVE, '&Save... \tCtrl+S',
|
||||
'Save file')
|
||||
m.Append(ID_SAVEAS, 'Save &As \tShift+Ctrl+S',
|
||||
m.Append(ID_SAVEAS, 'Save &As \tCtrl+Shift+S',
|
||||
'Save file with new name')
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_PRINT, '&Print... \tCtrl+P',
|
||||
'Print file')
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_NAMESPACE, '&Update Namespace \tShift+Ctrl+N',
|
||||
m.Append(ID_NAMESPACE, '&Update Namespace \tCtrl+Shift+N',
|
||||
'Update namespace for autocompletion and calltips')
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_EXIT, 'E&xit', 'Exit Program')
|
||||
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')
|
||||
@@ -94,105 +127,175 @@ class Frame(wx.Frame):
|
||||
'Cut the selection')
|
||||
m.Append(ID_COPY, '&Copy \tCtrl+C',
|
||||
'Copy the selection')
|
||||
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tShift+Ctrl+C',
|
||||
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 \tShift+Ctrl+V',
|
||||
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 \tF3',
|
||||
'Find next/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')
|
||||
|
||||
# Options
|
||||
m = self.autocompMenu = wx.Menu()
|
||||
m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu,
|
||||
'Auto Completion Options')
|
||||
m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu,
|
||||
'Call Tip Options')
|
||||
m.Append(ID_WRAP, '&Wrap Lines',
|
||||
'Wrap lines at right edge', wx.ITEM_CHECK)
|
||||
|
||||
if wx.Platform == "__WXMAC__":
|
||||
m.Append(ID_USEAA, '&Use AntiAliasing',
|
||||
m.Append(ID_USEAA, '&Use AntiAliasing\tCtrl+Shift+A',
|
||||
'Use anti-aliased fonts', wx.ITEM_CHECK)
|
||||
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_SAVEHISTORY, '&Save History\tAlt+Ctrl+A', 'Automatically save history on close', wx.ITEM_CHECK)
|
||||
self.startupMenu = wx.Menu()
|
||||
self.startupMenu.Append(ID_EXECSTARTUPSCRIPT, 'E&xecute Startup Script\tAlt+Ctrl+X', 'Execute Startup Script', wx.ITEM_CHECK)
|
||||
self.startupMenu.Append(ID_EDITSTARTUPSCRIPT, '&Edit Startup Script\tAlt+Ctrl+E', 'Edit Startup Script')
|
||||
m.AppendMenu(ID_STARTUP, '&Startup', self.startupMenu, 'Startup Options')
|
||||
|
||||
self.settingsMenu = wx.Menu()
|
||||
self.settingsMenu.Append(ID_AUTO_SAVESETTINGS, '&Auto Save Settings\tAlt+Ctrl+A', 'Automatically save settings on close', wx.ITEM_CHECK)
|
||||
self.settingsMenu.Append(ID_SAVESETTINGS, '&Save Settings\tAlt+Ctrl+S', 'Save settings now')
|
||||
self.settingsMenu.Append(ID_DELSETTINGSFILE, '&Revert to default\tAlt+Ctrl+R', 'Revert to the default settings')
|
||||
m.AppendMenu(ID_SETTINGS, '&Settings', self.settingsMenu, 'Settings Options')
|
||||
|
||||
m = self.helpMenu = wx.Menu()
|
||||
m.Append(ID_HELP, '&Help\tF1', 'Help!')
|
||||
m.AppendSeparator()
|
||||
m.Append(ID_ABOUT, '&About...', 'About this program')
|
||||
m.Append(ID_ABOUT, '&About...\tAlt+A', '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)
|
||||
|
||||
wx.EVT_MENU(self, ID_NEW, self.OnFileNew)
|
||||
wx.EVT_MENU(self, ID_OPEN, self.OnFileOpen)
|
||||
wx.EVT_MENU(self, ID_REVERT, self.OnFileRevert)
|
||||
wx.EVT_MENU(self, ID_CLOSE, self.OnFileClose)
|
||||
wx.EVT_MENU(self, ID_SAVE, self.OnFileSave)
|
||||
wx.EVT_MENU(self, ID_SAVEAS, self.OnFileSaveAs)
|
||||
wx.EVT_MENU(self, ID_NAMESPACE, self.OnFileUpdateNamespace)
|
||||
wx.EVT_MENU(self, ID_PRINT, self.OnFilePrint)
|
||||
wx.EVT_MENU(self, ID_EXIT, self.OnExit)
|
||||
wx.EVT_MENU(self, ID_UNDO, self.OnUndo)
|
||||
wx.EVT_MENU(self, ID_REDO, self.OnRedo)
|
||||
wx.EVT_MENU(self, ID_CUT, self.OnCut)
|
||||
wx.EVT_MENU(self, ID_COPY, self.OnCopy)
|
||||
wx.EVT_MENU(self, ID_COPY_PLUS, self.OnCopyPlus)
|
||||
wx.EVT_MENU(self, ID_PASTE, self.OnPaste)
|
||||
wx.EVT_MENU(self, ID_PASTE_PLUS, self.OnPastePlus)
|
||||
wx.EVT_MENU(self, ID_CLEAR, self.OnClear)
|
||||
wx.EVT_MENU(self, ID_SELECTALL, self.OnSelectAll)
|
||||
wx.EVT_MENU(self, ID_ABOUT, self.OnAbout)
|
||||
wx.EVT_MENU(self, ID_AUTOCOMP_SHOW, self.OnAutoCompleteShow)
|
||||
wx.EVT_MENU(self, ID_AUTOCOMP_MAGIC, self.OnAutoCompleteMagic)
|
||||
wx.EVT_MENU(self, ID_AUTOCOMP_SINGLE, self.OnAutoCompleteSingle)
|
||||
wx.EVT_MENU(self, ID_AUTOCOMP_DOUBLE, self.OnAutoCompleteDouble)
|
||||
wx.EVT_MENU(self, ID_CALLTIPS_SHOW, self.OnCallTipsShow)
|
||||
wx.EVT_MENU(self, ID_WRAP, self.OnWrap)
|
||||
wx.EVT_MENU(self, ID_USEAA, self.OnUseAA)
|
||||
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.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.OnUseAA, id=ID_USEAA)
|
||||
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.OnAutoSaveSettings, id=ID_AUTO_SAVESETTINGS)
|
||||
self.Bind(wx.EVT_MENU, self.OnSaveHistory, id=ID_SAVEHISTORY)
|
||||
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.OnFindText, id=ID_FIND)
|
||||
self.Bind(wx.EVT_MENU, self.OnFindNext, id=ID_FINDNEXT)
|
||||
|
||||
wx.EVT_UPDATE_UI(self, ID_NEW, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_OPEN, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_REVERT, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_CLOSE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_SAVE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_SAVEAS, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_NAMESPACE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_PRINT, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_UNDO, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_REDO, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_CUT, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_COPY, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_COPY_PLUS, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_PASTE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_PASTE_PLUS, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_CLEAR, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_SELECTALL, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_MAGIC, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SINGLE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_DOUBLE, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_WRAP, self.OnUpdateMenu)
|
||||
wx.EVT_UPDATE_UI(self, ID_USEAA, self.OnUpdateMenu)
|
||||
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_USEAA)
|
||||
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SHOW_LINENUMBERS)
|
||||
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_SAVEHISTORY)
|
||||
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_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()
|
||||
@@ -222,39 +325,52 @@ class Frame(wx.Frame):
|
||||
self.Close(False)
|
||||
|
||||
def OnUndo(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.Undo()
|
||||
|
||||
def OnRedo(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.Redo()
|
||||
|
||||
def OnCut(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.Cut()
|
||||
|
||||
def OnCopy(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.Copy()
|
||||
|
||||
def OnCopyPlus(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.CopyWithPrompts()
|
||||
|
||||
def OnPaste(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.Paste()
|
||||
|
||||
def OnPastePlus(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.PasteAndRun()
|
||||
|
||||
def OnClear(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
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 = wx.Window.FindFocus()
|
||||
win.SelectAll()
|
||||
|
||||
def OnAbout(self, event):
|
||||
@@ -266,38 +382,102 @@ class Frame(wx.Frame):
|
||||
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 = wx.Window.FindFocus()
|
||||
win.autoComplete = event.IsChecked()
|
||||
|
||||
def OnAutoCompleteMagic(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.autoCompleteIncludeMagic = event.IsChecked()
|
||||
|
||||
def OnAutoCompleteSingle(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.autoCompleteIncludeSingle = event.IsChecked()
|
||||
|
||||
def OnAutoCompleteDouble(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.autoCompleteIncludeDouble = event.IsChecked()
|
||||
|
||||
def OnCallTipsShow(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
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 = wx.Window.FindFocus()
|
||||
win.SetWrapMode(event.IsChecked())
|
||||
wx.FutureCall(1, self.shell.EnsureCaretVisible)
|
||||
|
||||
def OnUseAA(self, event):
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
win.SetUseAntiAliasing(event.IsChecked())
|
||||
|
||||
def OnSaveHistory(self, event):
|
||||
self.saveHistory = 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()
|
||||
|
||||
|
||||
def OnFindText(self, event):
|
||||
if self.findDlg is not None:
|
||||
return
|
||||
win = wx.Window.FindFocus()
|
||||
self.findDlg = wx.FindReplaceDialog(win, self.findData, "Find",
|
||||
wx.FR_NOWHOLEWORD)
|
||||
self.findDlg.Show()
|
||||
|
||||
def OnFindNext(self, event):
|
||||
if isinstance(event, wx.FindDialogEvent):
|
||||
win = self.findDlg.GetParent()
|
||||
else:
|
||||
win = wx.Window.FindFocus()
|
||||
win.DoFindNext(self.findData, self.findDlg)
|
||||
|
||||
def OnFindClose(self, event):
|
||||
self.findDlg.Destroy()
|
||||
self.findDlg = None
|
||||
|
||||
|
||||
|
||||
def OnUpdateMenu(self, event):
|
||||
"""Update menu items based on current status and context."""
|
||||
win = wx.Window_FindFocus()
|
||||
win = wx.Window.FindFocus()
|
||||
id = event.GetId()
|
||||
event.Enable(True)
|
||||
try:
|
||||
@@ -341,6 +521,8 @@ class Frame(wx.Frame):
|
||||
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:
|
||||
@@ -351,12 +533,273 @@ class Frame(wx.Frame):
|
||||
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_USEAA:
|
||||
event.Check(win.GetUseAntiAliasing())
|
||||
|
||||
elif id == ID_SHOW_LINENUMBERS:
|
||||
event.Check(win.lineNumbers)
|
||||
elif id == ID_AUTO_SAVESETTINGS:
|
||||
event.Check(self.autoSaveSettings)
|
||||
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)
|
||||
|
||||
elif id == ID_SAVEHISTORY:
|
||||
event.Check(self.saveHistory and self.dataDir is not None)
|
||||
elif id == ID_EDITSTARTUPSCRIPT:
|
||||
event.Enable(hasattr(self, 'EditStartupScript'))
|
||||
|
||||
elif id == ID_FIND:
|
||||
event.Enable(hasattr(win, 'DoFindNext'))
|
||||
elif id == ID_FINDNEXT:
|
||||
event.Enable(hasattr(win, 'DoFindNext') and
|
||||
self.findData.GetFindString() != '')
|
||||
|
||||
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 be 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.saveHistory = False
|
||||
|
||||
# We need this one before we have a chance to load the settings...
|
||||
self.execStartupScript = True
|
||||
if self.config:
|
||||
self.execStartupScript = self.config.ReadBool('Options/ExecStartupScript', 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.TELETYPE, wx.NORMAL, wx.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.saveHistory = self.config.ReadBool('Options/SaveHistory', False)
|
||||
self.LoadHistory()
|
||||
|
||||
|
||||
def SaveSettings(self):
|
||||
if self.config is not None:
|
||||
# always save this one
|
||||
self.config.WriteBool('Options/AutoSaveSettings', self.autoSaveSettings)
|
||||
if self.autoSaveSettings:
|
||||
self.config.WriteBool('Options/SaveHistory', self.saveHistory)
|
||||
self.config.WriteBool('Options/ExecStartupScript', self.execStartupScript)
|
||||
self.SaveHistory()
|
||||
|
||||
|
||||
|
||||
def SaveHistory(self):
|
||||
if self.dataDir:
|
||||
try:
|
||||
# always open the file so that when we are not
|
||||
# saving the history, the old file is emptied.
|
||||
name = os.path.join(self.dataDir, 'history')
|
||||
f = file(name, 'w')
|
||||
if self.saveHistory:
|
||||
hist = '\n'.join(self.shell.history)
|
||||
f.write(hist)
|
||||
f.close()
|
||||
except:
|
||||
d = wx.MessageDialog(self, "Error saving history file.",
|
||||
"Error", wx.ICON_EXCLAMATION)
|
||||
d.ShowModal()
|
||||
d.Destroy()
|
||||
|
||||
|
||||
def LoadHistory(self):
|
||||
if self.dataDir:
|
||||
name = os.path.join(self.dataDir, 'history')
|
||||
if os.path.exists(name):
|
||||
try:
|
||||
f = file(name, 'U')
|
||||
hist = f.read()
|
||||
f.close()
|
||||
self.shell.history = hist.split('\n')
|
||||
except:
|
||||
d = wx.MessageDialog(self, "Error loading history file.",
|
||||
"Error", wx.ICON_EXCLAMATION)
|
||||
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?\nAnswering 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:
|
||||
f = open(fileName, "w")
|
||||
f.write(text)
|
||||
f.close()
|
||||
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):
|
||||
text = file(self.startupScript, 'U').read()
|
||||
else:
|
||||
text = ''
|
||||
|
||||
dlg = EditStartupScriptDialog(self, self.startupScript, text)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
text = dlg.GetText()
|
||||
try:
|
||||
f = file(self.startupScript, 'w')
|
||||
f.write(text)
|
||||
f.close()
|
||||
except:
|
||||
d = wx.MessageDialog(self, "Error saving startup file.",
|
||||
"Error", wx.ICON_EXCLAMATION)
|
||||
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()
|
||||
|
@@ -42,7 +42,8 @@ class Interpreter(InteractiveInterpreter):
|
||||
self.more = 0
|
||||
# List of lists to support recursive push().
|
||||
self.commandBuffer = []
|
||||
self.startupScript = os.environ.get('PYTHONSTARTUP')
|
||||
self.startupScript = None
|
||||
|
||||
|
||||
def push(self, command):
|
||||
"""Send command to the interpreter to be executed.
|
||||
|
@@ -31,7 +31,7 @@ NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
|
||||
wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
|
||||
|
||||
|
||||
class ShellFrame(frame.Frame):
|
||||
class ShellFrame(frame.Frame, frame.ShellFrameMixin):
|
||||
"""Frame containing the shell component."""
|
||||
|
||||
name = 'Shell Frame'
|
||||
@@ -40,19 +40,31 @@ class ShellFrame(frame.Frame):
|
||||
def __init__(self, parent=None, id=-1, title='PyShell',
|
||||
pos=wx.DefaultPosition, size=wx.DefaultSize,
|
||||
style=wx.DEFAULT_FRAME_STYLE, locals=None,
|
||||
InterpClass=None, *args, **kwds):
|
||||
InterpClass=None,
|
||||
config=None, dataDir=None,
|
||||
*args, **kwds):
|
||||
"""Create ShellFrame instance."""
|
||||
frame.Frame.__init__(self, parent, id, title, pos, size, style)
|
||||
frame.ShellFrameMixin.__init__(self, config, dataDir)
|
||||
|
||||
if size == wx.DefaultSize:
|
||||
self.SetSize((750, 525))
|
||||
|
||||
intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
|
||||
intro += '\nSponsored by Orbtech - ' + \
|
||||
'Your source for Python programming expertise.'
|
||||
self.SetStatusText(intro.replace('\n', ', '))
|
||||
self.shell = Shell(parent=self, id=-1, introText=intro,
|
||||
locals=locals, InterpClass=InterpClass,
|
||||
startupScript=self.startupScript,
|
||||
execStartupScript=self.execStartupScript,
|
||||
*args, **kwds)
|
||||
|
||||
# Override the shell so that status messages go to the status bar.
|
||||
self.shell.setStatusText = self.SetStatusText
|
||||
|
||||
self.shell.SetFocus()
|
||||
self.LoadSettings()
|
||||
|
||||
|
||||
def OnClose(self, event):
|
||||
"""Event handler for closing."""
|
||||
# This isn't working the way I want, but I'll leave it for now.
|
||||
@@ -60,6 +72,7 @@ class ShellFrame(frame.Frame):
|
||||
if event.CanVeto():
|
||||
event.Veto(True)
|
||||
else:
|
||||
self.SaveSettings()
|
||||
self.shell.destroy()
|
||||
self.Destroy()
|
||||
|
||||
@@ -82,21 +95,28 @@ class ShellFrame(frame.Frame):
|
||||
dialog.Destroy()
|
||||
|
||||
|
||||
class ShellFacade:
|
||||
"""Simplified interface to all shell-related functionality.
|
||||
def LoadSettings(self):
|
||||
if self.config is not None:
|
||||
frame.ShellFrameMixin.LoadSettings(self)
|
||||
frame.Frame.LoadSettings(self, self.config)
|
||||
self.shell.LoadSettings(self.config)
|
||||
|
||||
This is a semi-transparent facade, in that all attributes of other
|
||||
are accessible, even though only some are visible to the user."""
|
||||
def SaveSettings(self):
|
||||
if self.config is not None:
|
||||
frame.ShellFrameMixin.SaveSettings(self)
|
||||
if self.autoSaveSettings:
|
||||
frame.Frame.SaveSettings(self, self.config)
|
||||
self.shell.SaveSettings(self.config)
|
||||
|
||||
name = 'Shell Interface'
|
||||
revision = __revision__
|
||||
def DoSaveSettings(self):
|
||||
if self.config is not None:
|
||||
self.SaveSettings()
|
||||
self.config.Flush()
|
||||
|
||||
|
||||
def __init__(self, other):
|
||||
"""Create a ShellFacade instance."""
|
||||
d = self.__dict__
|
||||
d['other'] = other
|
||||
d['helpText'] = \
|
||||
"""
|
||||
|
||||
|
||||
HELP_TEXT = """\
|
||||
* Key bindings:
|
||||
Home Go to the beginning of the command or line.
|
||||
Shift+Home Select to the beginning of the command or line.
|
||||
@@ -104,6 +124,7 @@ Shift+End Select to the end of the line.
|
||||
End Go to the end of the line.
|
||||
Ctrl+C Copy selected text, removing prompts.
|
||||
Ctrl+Shift+C Copy selected text, retaining prompts.
|
||||
Alt+C Copy to the clipboard, including prefixed prompts.
|
||||
Ctrl+X Cut selected text.
|
||||
Ctrl+V Paste from clipboard.
|
||||
Ctrl+Shift+V Paste and run multiple commands from clipboard.
|
||||
@@ -119,8 +140,31 @@ Ctrl+Enter Insert new line into multiline command.
|
||||
Ctrl+] Increase font size.
|
||||
Ctrl+[ Decrease font size.
|
||||
Ctrl+= Default font size.
|
||||
Ctrl-Space Show Auto Completion.
|
||||
Ctrl-Alt-Space Show Call Tip.
|
||||
Alt+Shift+C Clear Screen.
|
||||
Shift+Enter Complete Text from History.
|
||||
Ctrl+F Search (backwards) TODO: regexp-wholeWords-...
|
||||
Ctrl+G Search next
|
||||
Ctrl+H "hide" lines containing selection / "unhide"
|
||||
F12 on/off "free-edit" mode
|
||||
"""
|
||||
|
||||
class ShellFacade:
|
||||
"""Simplified interface to all shell-related functionality.
|
||||
|
||||
This is a semi-transparent facade, in that all attributes of other
|
||||
are accessible, even though only some are visible to the user."""
|
||||
|
||||
name = 'Shell Interface'
|
||||
revision = __revision__
|
||||
|
||||
def __init__(self, other):
|
||||
"""Create a ShellFacade instance."""
|
||||
d = self.__dict__
|
||||
d['other'] = other
|
||||
d['helpText'] = HELP_TEXT
|
||||
|
||||
def help(self):
|
||||
"""Display some useful information about how to use the shell."""
|
||||
self.write(self.helpText)
|
||||
@@ -151,6 +195,7 @@ Ctrl+= Default font size.
|
||||
'autoCompleteIncludeDouble',
|
||||
'autoCompleteIncludeMagic',
|
||||
'autoCompleteIncludeSingle',
|
||||
'callTipInsert',
|
||||
'clear',
|
||||
'pause',
|
||||
'prompt',
|
||||
@@ -167,6 +212,7 @@ Ctrl+= Default font size.
|
||||
return list
|
||||
|
||||
|
||||
|
||||
class Shell(editwindow.EditWindow):
|
||||
"""Shell based on StyledTextCtrl."""
|
||||
|
||||
@@ -175,26 +221,32 @@ class Shell(editwindow.EditWindow):
|
||||
|
||||
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
|
||||
size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
|
||||
introText='', locals=None, InterpClass=None, *args, **kwds):
|
||||
introText='', locals=None, InterpClass=None,
|
||||
startupScript=None, execStartupScript=True,
|
||||
*args, **kwds):
|
||||
"""Create Shell instance."""
|
||||
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
|
||||
self.wrap()
|
||||
if locals is None:
|
||||
import __main__
|
||||
locals = __main__.__dict__
|
||||
|
||||
# Grab these so they can be restored by self.redirect* methods.
|
||||
self.stdin = sys.stdin
|
||||
self.stdout = sys.stdout
|
||||
self.stderr = sys.stderr
|
||||
|
||||
# Import a default interpreter class if one isn't provided.
|
||||
if InterpClass == None:
|
||||
from interpreter import Interpreter
|
||||
else:
|
||||
Interpreter = InterpClass
|
||||
|
||||
# Create a replacement for stdin.
|
||||
self.reader = PseudoFileIn(self.readline, self.readlines)
|
||||
self.reader.input = ''
|
||||
self.reader.isreading = False
|
||||
|
||||
# Set up the interpreter.
|
||||
self.interp = Interpreter(locals=locals,
|
||||
rawin=self.raw_input,
|
||||
@@ -202,15 +254,20 @@ class Shell(editwindow.EditWindow):
|
||||
stdout=PseudoFileOut(self.writeOut),
|
||||
stderr=PseudoFileErr(self.writeErr),
|
||||
*args, **kwds)
|
||||
|
||||
# Set up the buffer.
|
||||
self.buffer = Buffer()
|
||||
|
||||
# Find out for which keycodes the interpreter will autocomplete.
|
||||
self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
|
||||
|
||||
# Keep track of the last non-continuation prompt positions.
|
||||
self.promptPosStart = 0
|
||||
self.promptPosEnd = 0
|
||||
|
||||
# Keep track of multi-line commands.
|
||||
self.more = False
|
||||
|
||||
# Create the command history. Commands are added into the
|
||||
# front of the list (ie. at index 0) as they are entered.
|
||||
# self.historyIndex is the current position in the history; it
|
||||
@@ -220,23 +277,46 @@ class Shell(editwindow.EditWindow):
|
||||
# command, not in the history.
|
||||
self.history = []
|
||||
self.historyIndex = -1
|
||||
|
||||
#seb add mode for "free edit"
|
||||
self.noteMode = 0
|
||||
self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
|
||||
self.searchTxt = ""
|
||||
|
||||
# Assign handlers for keyboard events.
|
||||
wx.EVT_CHAR(self, self.OnChar)
|
||||
wx.EVT_KEY_DOWN(self, self.OnKeyDown)
|
||||
self.Bind(wx.EVT_CHAR, self.OnChar)
|
||||
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
|
||||
|
||||
# Assign handler for idle time.
|
||||
self.waiting = False
|
||||
wx.EVT_IDLE(self, self.OnIdle)
|
||||
self.Bind(wx.EVT_IDLE, self.OnIdle)
|
||||
|
||||
# Display the introductory banner information.
|
||||
self.showIntro(introText)
|
||||
|
||||
# Assign some pseudo keywords to the interpreter's namespace.
|
||||
self.setBuiltinKeywords()
|
||||
|
||||
# Add 'shell' to the interpreter's local namespace.
|
||||
self.setLocalShell()
|
||||
|
||||
## NOTE: See note at bottom of this file...
|
||||
## #seb: File drag and drop
|
||||
## self.SetDropTarget( FileDropTarget(self) )
|
||||
|
||||
# Do this last so the user has complete control over their
|
||||
# environment. They can override anything they want.
|
||||
self.execStartupScript(self.interp.startupScript)
|
||||
if execStartupScript:
|
||||
if startupScript is None:
|
||||
startupScript = os.environ.get('PYTHONSTARTUP')
|
||||
self.execStartupScript(startupScript)
|
||||
else:
|
||||
self.prompt()
|
||||
|
||||
wx.CallAfter(self.ScrollToLine, 0)
|
||||
|
||||
|
||||
|
||||
def destroy(self):
|
||||
del self.interp
|
||||
|
||||
@@ -270,29 +350,32 @@ class Shell(editwindow.EditWindow):
|
||||
__builtin__.close = __builtin__.exit = __builtin__.quit = \
|
||||
'Click on the close button to leave the application.'
|
||||
|
||||
|
||||
def quit(self):
|
||||
"""Quit the application."""
|
||||
|
||||
# XXX Good enough for now but later we want to send a close event.
|
||||
|
||||
# In the close event handler we can make sure they want to
|
||||
# quit. Other applications, like PythonCard, may choose to
|
||||
# hide rather than quit so we should just post the event and
|
||||
# let the surrounding app decide what it wants to do.
|
||||
self.write('Click on the close button to leave the application.')
|
||||
|
||||
|
||||
def setLocalShell(self):
|
||||
"""Add 'shell' to locals as reference to ShellFacade instance."""
|
||||
self.interp.locals['shell'] = ShellFacade(other=self)
|
||||
|
||||
|
||||
def execStartupScript(self, startupScript):
|
||||
"""Execute the user's PYTHONSTARTUP script if they have one."""
|
||||
if startupScript and os.path.isfile(startupScript):
|
||||
text = 'Startup script executed: ' + startupScript
|
||||
self.push('print %r; execfile(%r)' % (text, startupScript))
|
||||
self.interp.startupScript = startupScript
|
||||
else:
|
||||
self.push('')
|
||||
|
||||
|
||||
def about(self):
|
||||
"""Display information about Py."""
|
||||
text = """
|
||||
@@ -302,17 +385,24 @@ Py Shell Revision: %s
|
||||
Py Interpreter Revision: %s
|
||||
Python Version: %s
|
||||
wxPython Version: %s
|
||||
wxPython PlatformInfo: %s
|
||||
Platform: %s""" % \
|
||||
(__author__, VERSION, self.revision, self.interp.revision,
|
||||
sys.version.split()[0], wx.VERSION_STRING, sys.platform)
|
||||
sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
|
||||
sys.platform)
|
||||
self.write(text.strip())
|
||||
|
||||
|
||||
def OnChar(self, event):
|
||||
"""Keypress event handler.
|
||||
|
||||
Only receives an event if OnKeyDown calls event.Skip() for the
|
||||
corresponding event."""
|
||||
|
||||
if self.noteMode:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
# Prevent modification of previously submitted
|
||||
# commands/responses.
|
||||
if not self.CanEdit():
|
||||
@@ -343,11 +433,12 @@ Platform: %s""" % \
|
||||
self.ReplaceSelection('')
|
||||
command = self.GetTextRange(stoppos, currpos) + '('
|
||||
self.write('(')
|
||||
self.autoCallTipShow(command)
|
||||
self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
|
||||
else:
|
||||
# Allow the normal event handling to take place.
|
||||
event.Skip()
|
||||
|
||||
|
||||
def OnKeyDown(self, event):
|
||||
"""Key down event handler."""
|
||||
|
||||
@@ -364,12 +455,64 @@ Platform: %s""" % \
|
||||
currpos = self.GetCurrentPos()
|
||||
endpos = self.GetTextLength()
|
||||
selecting = self.GetSelectionStart() != self.GetSelectionEnd()
|
||||
|
||||
if controlDown and key in (ord('H'), ord('h')):
|
||||
li = self.GetCurrentLine()
|
||||
m = self.MarkerGet(li)
|
||||
if m & 1<<0:
|
||||
startP = self.PositionFromLine(li)
|
||||
self.MarkerDelete(li, 0)
|
||||
maxli = self.GetLineCount()
|
||||
li += 1 # li stayed visible as header-line
|
||||
li0 = li
|
||||
while li<maxli and self.GetLineVisible(li) == 0:
|
||||
li += 1
|
||||
endP = self.GetLineEndPosition(li-1)
|
||||
self.ShowLines(li0, li-1)
|
||||
self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
|
||||
return
|
||||
startP,endP = self.GetSelection()
|
||||
endP-=1
|
||||
startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
|
||||
|
||||
if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
|
||||
endL -= 1
|
||||
|
||||
m = self.MarkerGet(startL)
|
||||
self.MarkerAdd(startL, 0)
|
||||
self.HideLines(startL+1,endL)
|
||||
self.SetCurrentPos( startP ) # to ensure caret stays visible !
|
||||
|
||||
if key == wx.WXK_F12: #seb
|
||||
if self.noteMode:
|
||||
# self.promptPosStart not used anyway - or ?
|
||||
self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
|
||||
self.GotoLine(self.GetLineCount())
|
||||
self.GotoPos(self.promptPosEnd)
|
||||
self.prompt() #make sure we have a prompt
|
||||
self.SetCaretForeground("black")
|
||||
self.SetCaretWidth(1) #default
|
||||
self.SetCaretPeriod(500) #default
|
||||
else:
|
||||
self.SetCaretForeground("red")
|
||||
self.SetCaretWidth(4)
|
||||
self.SetCaretPeriod(0) #steady
|
||||
|
||||
self.noteMode = not self.noteMode
|
||||
return
|
||||
if self.noteMode:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
# Return (Enter) is used to submit a command to the
|
||||
# interpreter.
|
||||
if not controlDown and key == wx.WXK_RETURN:
|
||||
if (not controlDown and not shiftDown and not altDown) and key == wx.WXK_RETURN:
|
||||
if self.CallTipActive():
|
||||
self.CallTipCancel()
|
||||
self.processLine()
|
||||
#Complete Text (from already typed words)
|
||||
elif shiftDown and key == wx.WXK_RETURN:
|
||||
self.OnShowCompHistory()
|
||||
# Ctrl+Return (Cntrl+Enter) is used to insert a line break.
|
||||
elif controlDown and key == wx.WXK_RETURN:
|
||||
if self.CallTipActive():
|
||||
@@ -433,6 +576,9 @@ Platform: %s""" % \
|
||||
elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
|
||||
or (shiftDown and not controlDown and key == wx.WXK_INSERT):
|
||||
self.Paste()
|
||||
elif controlDown and key == wx.WXK_SPACE:
|
||||
"""AutoComplete and Calltips manually."""
|
||||
self.OnCallTipAutoCompleteManually (shiftDown)
|
||||
# Paste from the clipboard, run commands.
|
||||
elif controlDown and shiftDown and key in (ord('V'), ord('v')):
|
||||
self.PasteAndRun()
|
||||
@@ -481,6 +627,49 @@ Platform: %s""" % \
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def OnShowCompHistory(self):
|
||||
"""Show possible autocompletion Words from already typed words."""
|
||||
|
||||
#copy from history
|
||||
his = self.history[:]
|
||||
|
||||
#put together in one string
|
||||
joined = " ".join (his)
|
||||
import re
|
||||
|
||||
#sort out only "good" words
|
||||
newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
|
||||
|
||||
#length > 1 (mix out "trash")
|
||||
thlist = []
|
||||
for i in newlist:
|
||||
if len (i) > 1:
|
||||
thlist.append (i)
|
||||
|
||||
#unique (no duplicate words
|
||||
#oneliner from german python forum => unique list
|
||||
unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
|
||||
|
||||
#sort lowercase
|
||||
unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
|
||||
|
||||
#this is more convenient, isn't it?
|
||||
self.AutoCompSetIgnoreCase(True)
|
||||
|
||||
#join again together in a string
|
||||
stringlist = " ".join(unlist)
|
||||
|
||||
#pos von 0 noch ausrechnen
|
||||
|
||||
#how big is the offset?
|
||||
cpos = self.GetCurrentPos() - 1
|
||||
while chr (self.GetCharAt (cpos)).isalnum():
|
||||
cpos -= 1
|
||||
|
||||
#the most important part
|
||||
self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
|
||||
|
||||
|
||||
def clearCommand(self):
|
||||
"""Delete the current, unexecuted command."""
|
||||
startpos = self.promptPosEnd
|
||||
@@ -589,6 +778,7 @@ Platform: %s""" % \
|
||||
self.write(os.linesep)
|
||||
else:
|
||||
self.push(command)
|
||||
wx.FutureCall(1, self.EnsureCaretVisible)
|
||||
# Or replace the current command with the other command.
|
||||
else:
|
||||
# If the line contains a command (even an invalid one).
|
||||
@@ -665,9 +855,10 @@ Platform: %s""" % \
|
||||
text = text[ps2size:]
|
||||
return text
|
||||
|
||||
def push(self, command):
|
||||
def push(self, command, silent = False):
|
||||
"""Send command to the interpreter for execution."""
|
||||
self.write(os.linesep)
|
||||
if not silent:
|
||||
self.write(os.linesep)
|
||||
busy = wx.BusyCursor()
|
||||
self.waiting = True
|
||||
self.more = self.interp.push(command)
|
||||
@@ -675,7 +866,8 @@ Platform: %s""" % \
|
||||
del busy
|
||||
if not self.more:
|
||||
self.addHistory(command.rstrip())
|
||||
self.prompt()
|
||||
if not silent:
|
||||
self.prompt()
|
||||
|
||||
def addHistory(self, command):
|
||||
"""Add command to the command history."""
|
||||
@@ -817,7 +1009,7 @@ Platform: %s""" % \
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
def autoCompleteShow(self, command):
|
||||
def autoCompleteShow(self, command, offset = 0):
|
||||
"""Display auto-completion popup list."""
|
||||
self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
|
||||
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
|
||||
@@ -827,19 +1019,19 @@ Platform: %s""" % \
|
||||
includeDouble=self.autoCompleteIncludeDouble)
|
||||
if list:
|
||||
options = ' '.join(list)
|
||||
offset = 0
|
||||
#offset = 0
|
||||
self.AutoCompShow(offset, options)
|
||||
|
||||
def autoCallTipShow(self, command):
|
||||
def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
|
||||
"""Display argument spec and docstring in a popup window."""
|
||||
if self.CallTipActive():
|
||||
self.CallTipCancel()
|
||||
(name, argspec, tip) = self.interp.getCallTip(command)
|
||||
if tip:
|
||||
dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
|
||||
if not self.autoCallTip:
|
||||
if not self.autoCallTip and not forceCallTip:
|
||||
return
|
||||
if argspec:
|
||||
if argspec and insertcalltip and self.callTipInsert:
|
||||
startpos = self.GetCurrentPos()
|
||||
self.write(argspec + ')')
|
||||
endpos = self.GetCurrentPos()
|
||||
@@ -852,6 +1044,53 @@ Platform: %s""" % \
|
||||
# fallback.
|
||||
tippos = max(tippos, fallback)
|
||||
self.CallTipShow(tippos, tip)
|
||||
|
||||
def OnCallTipAutoCompleteManually (self, shiftDown):
|
||||
"""AutoComplete and Calltips manually."""
|
||||
if self.AutoCompActive():
|
||||
self.AutoCompCancel()
|
||||
currpos = self.GetCurrentPos()
|
||||
stoppos = self.promptPosEnd
|
||||
|
||||
cpos = currpos
|
||||
#go back until '.' is found
|
||||
pointavailpos = -1
|
||||
while cpos >= stoppos:
|
||||
if self.GetCharAt(cpos) == ord ('.'):
|
||||
pointavailpos = cpos
|
||||
break
|
||||
cpos -= 1
|
||||
|
||||
#word from non whitespace until '.'
|
||||
if pointavailpos != -1:
|
||||
#look backward for first whitespace char
|
||||
textbehind = self.GetTextRange (pointavailpos + 1, currpos)
|
||||
pointavailpos += 1
|
||||
|
||||
if not shiftDown:
|
||||
#call AutoComplete
|
||||
stoppos = self.promptPosEnd
|
||||
textbefore = self.GetTextRange(stoppos, pointavailpos)
|
||||
self.autoCompleteShow(textbefore, len (textbehind))
|
||||
else:
|
||||
#call CallTips
|
||||
cpos = pointavailpos
|
||||
begpos = -1
|
||||
while cpos > stoppos:
|
||||
if chr(self.GetCharAt(cpos)).isspace():
|
||||
begpos = cpos
|
||||
break
|
||||
cpos -= 1
|
||||
if begpos == -1:
|
||||
begpos = cpos
|
||||
ctips = self.GetTextRange (begpos, currpos)
|
||||
ctindex = ctips.find ('(')
|
||||
if ctindex != -1 and not self.CallTipActive():
|
||||
#insert calltip, if current pos is '(', otherwise show it only
|
||||
self.autoCallTipShow(ctips[:ctindex + 1], \
|
||||
self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),\
|
||||
True)
|
||||
|
||||
|
||||
def writeOut(self, text):
|
||||
"""Replacement for stdout."""
|
||||
@@ -1034,3 +1273,101 @@ Platform: %s""" % \
|
||||
This number of points is added to the size of all fonts. It
|
||||
may be positive to magnify or negative to reduce."""
|
||||
self.SetZoom(points)
|
||||
|
||||
|
||||
|
||||
def LoadSettings(self, config):
|
||||
self.autoComplete = config.ReadBool('Options/AutoComplete', True)
|
||||
self.autoCompleteIncludeMagic = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
|
||||
self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
|
||||
self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
|
||||
|
||||
self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
|
||||
self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
|
||||
self.SetWrapMode(config.ReadBool('View/WrapMode', True))
|
||||
|
||||
useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
|
||||
self.SetUseAntiAliasing(useAA)
|
||||
self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
|
||||
self.setDisplayLineNumbers (self.lineNumbers)
|
||||
zoom = config.ReadInt('View/Zoom/Shell', -99)
|
||||
if zoom != -99:
|
||||
self.SetZoom(zoom)
|
||||
|
||||
|
||||
|
||||
def SaveSettings(self, config):
|
||||
config.WriteBool('Options/AutoComplete', self.autoComplete)
|
||||
config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
|
||||
config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
|
||||
config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
|
||||
config.WriteBool('Options/AutoCallTip', self.autoCallTip)
|
||||
config.WriteBool('Options/CallTipInsert', self.callTipInsert)
|
||||
config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
|
||||
config.WriteBool('View/WrapMode', self.GetWrapMode())
|
||||
config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
|
||||
config.WriteInt('View/Zoom/Shell', self.GetZoom())
|
||||
|
||||
|
||||
|
||||
## NOTE: The DnD of file names is disabled until I can figure out how
|
||||
## best to still allow DnD of text.
|
||||
|
||||
|
||||
## #seb : File drag and drop
|
||||
## class FileDropTarget(wx.FileDropTarget):
|
||||
## def __init__(self, obj):
|
||||
## wx.FileDropTarget.__init__(self)
|
||||
## self.obj = obj
|
||||
## def OnDropFiles(self, x, y, filenames):
|
||||
## if len(filenames) == 1:
|
||||
## txt = 'r\"%s\"' % filenames[0]
|
||||
## else:
|
||||
## txt = '( '
|
||||
## for f in filenames:
|
||||
## txt += 'r\"%s\" , ' % f
|
||||
## txt += ')'
|
||||
## self.obj.AppendText(txt)
|
||||
## pos = self.obj.GetCurrentPos()
|
||||
## self.obj.SetCurrentPos( pos )
|
||||
## self.obj.SetSelection( pos, pos )
|
||||
|
||||
|
||||
|
||||
## class TextAndFileDropTarget(wx.DropTarget):
|
||||
## def __init__(self, shell):
|
||||
## wx.DropTarget.__init__(self)
|
||||
## self.shell = shell
|
||||
## self.compdo = wx.DataObjectComposite()
|
||||
## self.textdo = wx.TextDataObject()
|
||||
## self.filedo = wx.FileDataObject()
|
||||
## self.compdo.Add(self.textdo)
|
||||
## self.compdo.Add(self.filedo, True)
|
||||
|
||||
## self.SetDataObject(self.compdo)
|
||||
|
||||
## def OnDrop(self, x, y):
|
||||
## return True
|
||||
|
||||
## def OnData(self, x, y, result):
|
||||
## self.GetData()
|
||||
## if self.textdo.GetTextLength() > 1:
|
||||
## text = self.textdo.GetText()
|
||||
## # *** Do somethign with the dragged text here...
|
||||
## self.textdo.SetText('')
|
||||
## else:
|
||||
## filenames = str(self.filename.GetFilenames())
|
||||
## if len(filenames) == 1:
|
||||
## txt = 'r\"%s\"' % filenames[0]
|
||||
## else:
|
||||
## txt = '( '
|
||||
## for f in filenames:
|
||||
## txt += 'r\"%s\" , ' % f
|
||||
## txt += ')'
|
||||
## self.shell.AppendText(txt)
|
||||
## pos = self.shell.GetCurrentPos()
|
||||
## self.shell.SetCurrentPos( pos )
|
||||
## self.shell.SetSelection( pos, pos )
|
||||
|
||||
## return result
|
||||
|
||||
|
@@ -6,4 +6,4 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
|
||||
__cvsid__ = "$Id$"
|
||||
__revision__ = "$Revision$"[11:-2]
|
||||
|
||||
VERSION = '0.9.4'
|
||||
VERSION = '0.9.5'
|
||||
|
Reference in New Issue
Block a user