summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/wx-3.0-msw/wx/py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/wx-3.0-msw/wx/py')
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/CHANGES.txt796
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/Py.icobin0 -> 4710 bytes
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaCarte.py37
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaMode.py37
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaModeTest.py36
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.icobin0 -> 4710 bytes
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.py82
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyFilling.py36
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyShell.py80
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.icobin0 -> 6502 bytes
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.py100
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlicesShell.py96
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyWrap.py49
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/README.txt83
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/__init__.py22
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/buffer.py138
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/crust.py379
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/crustslices.py416
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/dispatcher.py262
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/document.py43
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/editor.py838
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/editwindow.py297
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/filling.py360
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/frame.py984
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/images.py215
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/interpreter.py170
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/introspect.py389
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/magic.py92
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/parse.py128
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/path.py36
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/pseudo.py101
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/shell.py1575
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/sliceshell.py3789
-rw-r--r--lib/python2.7/site-packages/wx-3.0-msw/wx/py/version.py9
34 files changed, 11675 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/CHANGES.txt b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/CHANGES.txt
new file mode 100644
index 0000000..501c091
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/CHANGES.txt
@@ -0,0 +1,796 @@
+0.9.7.9 (9/8/09)
+-------------------
+Finalized the naming convention so that references to shell in the new "slices"
+shell are renamed to "sliceshell" (likewise, Shell becomes SlicesShell)
+
+Also, renamed the file "slices.py" to "sliceshell.py".
+Since my goal is to keep PySlices.py as the equivalent to PyCrust.py,
+ I think this new convention makes the most sense...
+
+Now (Finally):
+ shell.py contains the classes: Shell, ShellFacade, and ShellFrame
+ sliceshell.py contains the classes: SlicesShell, SlicesShellFacade,
+ and SlicesShellFrame
+ crust.py contains: Crust and CrustFrame
+ crustslices.py contains: CrustSlices and CrustSlicesFrame
+ PyShell.py and PySlicesShell.py are the respective standalone shell apps
+ PyCrust.py and PySlices.py are the respective apps that also include Filling
+
+ frame.py etc. still continue to service both PyCrust and PySlices.
+
+0.9.7.8 (9/8/09)
+-------------------
+Added open/save abilities to PySlices (PyCrust remains the same).
+ This uses a special format with extension .pyslices.
+ A file, *.pyslices will contain a text header and
+ also a line denoting the beginning of each new slice,
+ naming the type of slice as well (grouping, input, output)
+ All output is commented with a single '#' which is removed upon loading.
+ This ensures that a well contstucted .pyslices file is also
+ a valid python script!
+
+Added the ability to load an entire python file into a new Input slice
+ with Ctrl-L
+Added the ability to load pyslices files from the command line.
+
+Split the functionality of crust.py (functioning for both PyCrust and PySlices)
+ into crust.py (only PyCrust) and crustslices.py (only for PySlices).
+
+After revising the naming conventions:
+ shell.py contains the classes: Shell, ShellFacade, and ShellFrame
+ slice.py contains the classes: Shell, ShellFacade, and ShellFrame
+ crust.py contains: Crust and CrustFrame
+ crustslices.py contains: CrustSlices and CrustSlicesFrame
+ PyShell.py and PySlicesShell.py are the respective standalone shell apps
+ PyCrust.py and PySlices.py are the respective apps that also include Filling
+
+ frame.py etc. still continue to service both PyCrust and PySlices.
+
+0.9.7.7 (8/25/2009) (Current--Still Need to SVNAdd the new file PySlicesShell.py)
+-------------------
+Added code to introspect.py to check for Enthought's "Traits" attributes.
+Added PySlicesShell.py. PySlices shell is PySlices without Filling
+ and other crust attributes.
+Fixed a bug with Output_BG
+
+0.9.7.6 (7/18/2009)
+-------------------
+Made output have a slight-blue background
+Added a tutorial that can be disabled in Options->Startup.
+Added "Shell Mode" which uses >>> and ... markers for input slices and uses two returns for command execution
+Changed manual completion keybindings.
+Cleaned up keybinding help.
+Made Items in Options->Startup menu automatically save to the config file (since they don't affect anything until startup)
+Major code cleanup, removal of much dead code, shortening of very long lines, etc...
+
+0.9.6.9 (7/9/2009)
+-------------------
+Fixed Undo marker issues and a bug in selection overwrite.
+
+0.9.6.8 (7/1/2009)
+-------------------
+Merged changes with SVN trunk.
+
+0.9.6.4 thru 0.9.6.6 (10/22/2008-4/27/2009)
+-------------------
+Added magic.py to handle some very simple "magic" commands:
+
+Now the command:
+"f 1"
+will be re-interpreted as:
+"f(1)"
+
+The command:
+"f 1,2,3,4"
+will be interpreted as:
+f(1,2,3,4)
+
+Special commands "ls","cd", and "pwd" are interpreted separately
+
+Works with slices.py and shell.py
+
+Also fixed auto-indent magic.
+
+0.9.6.1 thru 0.9.6.3 (10/21/2008)
+---------------------------------
+Added PySlices (slices.py and PySlices.py), a modified version of PyCrust.
+PySlices is a "notebook interface" multi-line shell, ala Sage or Mathematica.
+It uses Scintilla markers extensively, with red for input and blue for output.
+
+Modified crust.py to use a switch so it can load either a Shell or a Slices_Shell
+
+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-Shift-F 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)
+------------------------------
+
+Removed wxd decorators in favor of new SWIG-generated docstrings.
+
+Removed docs tabs from crust interface:
+* wxPython Docs
+* wxSTC Docs
+
+Fixed Calltip tab refresh problem on Windows.
+
+shell.autoCompleteAutoHide added with default of False.
+
+Changed default namespace of Shell to __main__.__dict__, instead of an
+empty dictionary.
+
+
+0.9.3 (9/25/2003 to 1/24/2004)
+------------------------------
+
+Fun and games with dynamic renaming. Details of any other changes
+were lost in the confusion. I'll try to do better in the future.
+
+
+0.9.2 (5/3/2003 to 9/25/2003)
+-----------------------------
+
+Changed to the new prefix-less "wx" package::
+
+ import wx
+
+instead of::
+
+ from wxPython import wx
+
+Fixed typo in ``PyWrap.py``::
+
+ if __name__ == '__main__':
+ main(sys.argv)
+
+should have been::
+
+ if __name__ == '__main__':
+ main()
+
+Added pretty-print Display tab to Crust, based on suggestion from
+Jason Whitlark.
+
+Improved ``Can*`` checks in ``EditWindow``, since STC is too lenient,
+particularly when it is set to read-only but returns True for
+CanPaste() (seems like an STC bug to me)::
+
+ def CanCopy(self):
+ """Return True if text is selected and can be copied."""
+ return self.GetSelectionStart() != self.GetSelectionEnd()
+
+ def CanCut(self):
+ """Return True if text is selected and can be cut."""
+ return self.CanCopy() and self.CanEdit()
+
+ def CanEdit(self):
+ """Return True if editing should succeed."""
+ return not self.GetReadOnly()
+
+ def CanPaste(self):
+ """Return True if pasting should succeed."""
+ return stc.StyledTextCtrl.CanPaste(self) and self.CanEdit()
+
+
+0.9.1 (3/21/2003 to 5/2/2003)
+-----------------------------
+
+PyCrust is dead! Long live Py!
+
+* Renamed ``PyCrust`` package to ``py``.
+* Moved code to wxPython's CVS repository.
+
+Fixed bug in ``introspect.py`` on introspecting objects occurring
+immediately after a secondary prompt, like this::
+
+ >>> l = [1, 2, 3]
+ >>> for n in range(3):
+ ... l. <-- failed to popup autocomplete list
+
+Added documentation files:
+
+* PyManual.txt
+* wxPythonManual.txt
+* wxPythonPackage.txt
+* wxPythonExamples.txt
+
+Added PyAlaMode and PyAlaCarte code editors.
+
+Major refactoring to support ``editor`` and ``shell`` from the same
+base.
+
+Renamed program files:
+
+* ``PyCrustApp.py`` to ``PyCrust.py``
+* ``PyFillingApp.py`` to ``PyFilling.py``
+* ``PyShellApp.py`` to ``PyShell.py``
+* ``wrap.py`` to ``PyWrap.py``
+
+Removed disabling of autocomplete for lists of 2000 items or more.
+The current implementation of wxSTC can now handle lists this big.
+
+Improved handling of ``sys.path`` to mimic the standard Python shell.
+
+
+0.9 (2/27/2003 to 3/20/2003)
+----------------------------
+
+Added fontIncrease, fontDecrease, fontDefault signals, receivers and
+keybindings::
+
+ Ctrl+] Increase font size.
+ Ctrl+[ Decrease font size.
+ Ctrl+= Default font size.
+
+Continued enhancement of the decorator capability to provide better
+documentation and docstrings for wxPython classes and functions.
+
+Introduced new tabbed interface:
+
+* Namespace
+* Calltip
+* Session
+* Dispatcher
+* wxPython Docs
+* wxSTC Docs
+
+``Filling.tree`` now expands tuples as well as lists. (It should have
+done this all along, I just never noticed this omission before.)
+
+Added this True/False test to all modules::
+
+ try:
+ True
+ except NameError:
+ True = 1==1
+ False = 1==0
+
+Added ``wxd`` directory with decoration classes.
+
+
+0.8.2 (1/5/2003 to 2/26/2003)
+-----------------------------
+
+Wrapped ``sys.ps1``, ``sys.ps2``, and ``sys.ps3`` in ``str()``.
+(Thanks, Kieran Holland.)
+
+Fixed minor things found by PyChecker.
+
+Changed locals to use ``__main__.__dict__`` and added code to clean up
+the namespace, making it as close to the regular Python environment as
+possible. This solves the problem of pickling and unpickling
+instances of classes defined in the shell.
+
+Made ``shell.PasteAndRun()`` a little more forgiving when it finds a
+ps2 prompt line with no trailing space, such when you copy code from a
+web page.
+
+Improved autocomplete behavior by adding these to shell::
+
+ self.AutoCompSetAutoHide(False)
+ self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
+
+Added ``decor`` directory, ``decorator.py``, ``stcDecor.py``, and
+``stcConstants.py``. These all serve the purpose of adding docstrings
+to existing wxPython classes, in particular the ``wxStyledTextCtrl``.
+
+Added ``wrap.py``, a command line utility for running a wxPython app
+with additional runtime-tools loaded, such as PyCrust (the only tool
+at this point).
+
+Flushed the clipboard Cut/Copy operations so that selections will
+exist in the clipboard even after PyCrust has been closed.
+
+Improved the suppression of docstrings for simple data types appearing
+in the namespace viewer.
+
+Better handling of autocompletion with numeric types; no
+autocompletion when typing a dot after an integer. If the
+autocompletion is desired, type a space before the dot::
+
+ func = 3 .
+
+More Filling!!! The namespace tree is now dynamically updated.
+
+
+0.8.1 (12/20/2002 to 12/25/2002)
+--------------------------------
+
+Improved keyboard handling with Autocomplete active. You can now use
+Enter as well as Tab to select an item from the list.
+
+Disabled autocomplete for lists of 2000 items or more. The current
+implementation of wxSTC can't handle lists this big.
+
+Changed ``filling`` to always display docstrings for objects. This is
+useful for objects whose docstrings have been decorated, rather than
+coming directly from the source code. (Hmmm. Sounds like someone is
+doing some decorating. I wonder where that would be helpful? <wink>)
+
+Fixed handling of icon. Added ``images.py`` file.
+
+
+0.8 (10/29/2002 to 12/16/2002)
+------------------------------
+
+Added "help" to startup banner info.
+
+Made all ``wx`` and ``stc`` imports explicit. No more ``import *``.
+
+Replaced use of the ``wx`` module's ``true`` and ``false`` with
+Python's ``True`` and ``False``.
+
+Changed ``introspect.getRoot()`` to use ``tokenize`` module. This
+does a slightly better job than the previous parsing routine and the
+code is clearer.
+
+Improved handling of whitespace and empty types during introspection.
+
+Fixed cut/copy clipboard problem under Linux. (Robin Dunn rocks!!!)
+
+Added shell.about() which works like this::
+
+ >>> shell.about()
+ PyCrust Version: 0.8
+ Shell Revision: 1.80
+ Interpreter Revision: 1.15
+ Python Version: 2.2.2
+ wxPython Version: 2.3.3.1
+ Platform: linux2
+
+Added copy plus and paste plus to shell menu.
+
+Moved shell menu from ``shell.py`` to ``shellmenu.py``.
+
+Added ``sys.stdin.readlines()`` support.
+
+Added ``time.sleep()`` in ``readline()`` and ``OnIdle()`` event
+handler to free up the CPU.
+
+
+0.7.2 (2/22/2002 to 8/27/2002)
+------------------------------
+
+Tweaked ``getAttributeNames()`` to pick up a few more attributes::
+
+ '__bases__', '__class__', '__dict__', '__name__', 'func_closure',
+ 'func_code', 'func_defaults', 'func_dict', 'func_doc',
+ 'func_globals', 'func_name'
+
+Added a tests directory and unit tests.
+
+Improved support for empty types in the shell: ``[]``, ``()`` and
+``{}`` as far as when call tips and autocompletion are available.
+
+Added support for the other triple string - ``''''''``.
+
+Refactored ``introspect.py`` to improve testability.
+
+Improved call tips for unbound methods by leaving the "self"
+parameter, since unbound methods require an instance be passed.
+
+Fixed call tip bug where a tip was displayed when a "(" was typed
+after an object that wasn't callable.
+
+Fixed ``getAllAttributeNames`` when ``str(object)`` fails.
+
+Added brace highlighting. (Thank you, Kevin Altis.)
+
+Fixed problem displaying unicode objects in ``PyFilling``.
+
+Changed how ``filling.py`` checks for expandable objects. Lists are
+now expandable objects.
+
+Made the key handling more robust when there is an active text
+selection that includes text prior to the last primary prompt. Thanks
+to Raul Cota for pointing this out.
+
+Fixed wxSTC problem with brace highlighting and non-us keyboards.
+(Thank you for the patch, Jean-Michel Fauth.)
+
+Added ``busy = wxBusyCursor()`` to key points in ``shell`` and
+``filling``.
+
+Added ``OnCloseWindow`` handler to ``ShellFrame`` and ``CrustFrame``.
+
+Default to ``SetWrapMode(1)`` for shell and namespace viewer.
+
+Added ``shell.wrap()`` and ``shell.zoom()``.
+
+Added autoCompleteKeys hooks for Raul Cota.
+
+Cleaned up various little key handling bugs.
+
+Changed input methods to get values from shell, rather than dialog
+boxes. Renamed ``readIn`` to ``readline`` and ``readRaw`` to
+``raw_input``.
+
+
+0.7.1 (12/12/2001 to 2/21/2002)
+-------------------------------
+
+Fixed ``OnChar()`` issues effecting European keyboards, as reported by
+Jean-Michel Fauth.
+
+Fixed ``introspect.py`` issue with xmlrpc objects reported by Kevin
+Altis.
+
+Fixed some introspect/PyFilling issues with regard to Python 2.2.
+
+Fixed font background color as reported by Keith J. Farmer. (Thanks)
+
+Fixed problem with call tips and autocompletion inside multiline
+commands as report by Kevin Altis.
+
+Improved ``OnKeyDown`` handling of cut/copy/paste operations based on
+feedback from Syver Enstad. (Thanks)
+
+Added a ``shell.help()`` method to display some help info.
+
+Changed sort of items in the namespace viewer to case insensitive.
+
+Changed ``attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))`` in
+advance of an upcoming fix to an autocompletion matching bug in wxSTC.
+
+Improved support for ZODB by allowing namespace drilldown into BTrees.
+
+Added ``shell.PasteAndRun()`` to support pasting multiple commands into
+the shell from the clipboard. Ctrl+Shift+V or v.
+
+Enter now always processes a command (or copies down a previous one.)
+To insert a line break, press Ctrl+Enter.
+
+Escape key clears the current, unexecuted command.
+
+History retrieval changed to replace current command. Added new keys
+to insert from history - Shift+Up and Shift+Down.
+
+Better call tips on objects with ``__call__`` methods.
+
+Improved call tip positioning calculation.
+
+
+0.7 (10/15/2001 to 12/11/2001)
+------------------------------
+
+Changed how command history retrieval functions work. Added Alt-P,
+Alt-N as keybindings for Retrieve-Previous, Retrieve-Next.
+
+Added full support for multi-line commands, similar to IDLE.
+
+Changed ``introspect.getAttributeNames()`` to do a case insensitive
+sort.
+
+Changed Cut/Copy/Paste to deal with prompts intelligently. Cut and
+Copy remove all prompts. Paste can handle prompted or not-prompted
+text.
+
+Added ``CopyWithPrompts()`` method attached to Ctrl-Shift-C for those
+times when you really do want all the prompts left intact.
+
+Improved handling of the shell's read-only zone.
+
+Changed ``CrustFrame.__init__`` parameter spec to include all
+parameters allowed by a ``wxFrame``.
+
+Changed ``FillingText`` to be read-only.
+
+Renamed ``PyCrust.py`` to ``PyCrustApp.py`` to eliminate
+package/module name conflicts that kept you from doing ``from PyCrust
+import shell`` inside files located in the ``PyCrust`` directory.
+
+Renamed ``PyFilling.py`` to ``PyFillingApp.py`` and ``PyShell.py`` to
+``PyShellApp.py`` to maintain consistency.
+
+Removed the ``__date__`` property from all modules.
+
+Fixed bug in ``introspect.getCallTip()``, reported by Kevin Altis.
+
+
+0.6.1 (9/19/2001 to 10/12/2001)
+-------------------------------
+
+Changed ``Shell.run()`` to always position to the end of existing
+text, as suggested by Raul Cota.
+
+Changed ``introspect.getAllAttributeNames()`` to break circular
+references in ``object.__class__``, which occurs in Zope/ZODB
+extension classes.
+
+Changed ``filling.FillingTree.getChildren()`` to introspect extension
+classes.
+
+Fixed minor bugs in ``introspect.getCallTip()`` that were interfering
+with call tips for Zope/ZODB extension class methods.
+
+In preparation for wxPython 2.3.2, added code to fix a font sizing
+problem. Versions of wxPython prior to 2.3.2 had a sizing bug on Win
+platform where the font was 2 points larger than what was specified.
+
+Added a hack to ``introspect.getAllAttributeNames()`` to "wake up"
+ZODB objects that are asleep - in a "ghost" state. Otherwise it
+returns incomplete info.
+
+
+0.6 (8/21/2001 to 9/12/2001)
+----------------------------
+
+Added ``PyFilling.py`` and ``filling.py``.
+
+``PyShell.py`` and ``PyFilling.py`` can now be run standalone, as well
+as ``PyCrust.py``.
+
+Added ``crust.py`` and moved some code from ``PyCrust.py`` to it.
+
+Added command history retrieval features submitted by Richie Hindle.
+
+Changed ``shell.write()`` to replace line endings with OS-specific
+endings. Changed ``shell.py`` and ``interpreter.py`` to use
+``os.linesep`` in strings having hardcoded line endings.
+
+Added ``shell.redirectStdin()``, ``shell.redirectStdout()`` and
+``shell.redirectStderr()`` to allow the surrounding app to toggle
+requests that the specified ``sys.std*`` be redirected to the shell.
+These can also be run from within the shell itself, of course.
+
+The shell now adds the current working directory "." to the search
+path::
+
+ sys.path.insert(0, os.curdir)
+
+Added support for distutils installations.
+
+
+0.5.4 (8/17/2001 to 8/20/2001)
+------------------------------
+
+Changed default font size under Linux to::
+
+ 'size' : 12,
+ 'lnsize' : 10,
+
+Changed ``Shell`` to expect a parameter referencing an Interpreter
+class, rather than an intepreter instance, to facilitate subclassing
+of Interpreter, which effectively broke when the Editor class was
+eliminated.
+
+Fixed ``PyCrustAlaCarte.py``, which had been broken by previous
+changes.
+
+Created ``InterpreterAlaCarte`` class as an example for use in the
+demo.
+
+Split ``PyCrust.py`` into ``PyCrust.py`` and ``PyShell.py`` in
+anticipation of ``PyFilling.py``.
+
+
+0.5.3 (8/16/2001)
+-----------------
+
+Added patch to ``PyCrust.py`` to fix wxPython bug::
+
+ wxID_SELECTALL = NewId() # This *should* be defined by wxPython.
+
+
+0.5.2 (8/14/2001 to 8/15/2001)
+------------------------------
+
+Shortened module names by dropping "PyCrust" as a prefix.
+
+Changed ``version`` to ``VERSION`` in ``version`` module.
+
+Added Options menu to PyCrust application.
+
+Eliminated the Editor class (and editor module) by merging with Shell.
+This means that Shell "is a" wxStyledTextCtrl rather than "has a".
+There just wasn't enough non-gui code to justify the separation.
+Plus, Shell will be much easier for gui toolkits/designers to deal
+with now.
+
+
+0.5.1 (8/10/2001 to 8/14/2001)
+------------------------------
+
+Added ``introspect`` module.
+
+Moved some functionality from ``PyCrustInterp`` to ``introspect``.
+
+Changed ``introspect.getRoot()`` to no longer remove whitespace from
+the command. This was a remnant of a previous approach that, when
+left as part of the current approach, turned out to be a really bad
+thing.
+
+Changed ``introspect.getRoot()`` to allow commands of ``''``, ``""``,
+``""""""``, ``[]``, ``()``, and ``{}`` to pass through. This allows
+you to type them, followed by a dot, and get autocomplete options on
+them.
+
+Changed ``introspect.getRoot()`` to identify some situations where
+strings shouldn't be considered roots. For example::
+
+ >>> import PyCrust # To illustrate the potential problem.
+ >>> len('PyCrust.py')
+
+Typing the dot at the end of "PyCrust" in the second line above should
+NOT result in an autocompletion list because "PyCrust" is part of a
+string in this context, not a reference to the PyCrust module object.
+Similar reasoning applies to call tips. For example::
+
+ >>> len('dir(')
+
+Typing the left paren at the end of "dir" should NOT result in a call
+tip.
+
+Both features now behave properly in the examples given. However,
+there is still the case where whitespace precedes the potential root
+and that is NOT handled properly. For example::
+
+ >>> len('this is a dir(')
+
+and::
+
+ >>> len('This is PyCrust.py')
+
+More code needs to be written to handle more complex situations.
+
+Added ``locals=None`` parameter to ``Shell.__init__()``.
+
+Added support for magic attribute retrieval. Users can change this
+with::
+
+ >>> shell.editor.autoCompleteIncludeMagic = 0
+
+Added the ability to set filters on auto completion to exclude
+attributes prefixed with a single or double underscore. Users can
+exclude one or the other or both with::
+
+ >>> shell.editor.autoCompleteExcludeSingle = 1
+ >>> shell.editor.autoCompleteExcludeDouble = 1
+
+
+0.5 (8/8/2001)
+--------------
+
+Mostly just a final version change before creating a release.
+
+
+0.4 (8/4/2001 to 8/7/2001)
+--------------------------
+
+Changed version/revision handling.
+
+Fixed bugs.
+
+
+0.3 (8/2/2001 to 8/3/2001)
+--------------------------
+
+Removed lots of cruft.
+
+Added lots of docstrings.
+
+Imported to CVS repository at SourceForge.
+
+Added call tips.
+
+
+0.2 (7/30/2001 to 8/2/2001)
+---------------------------
+
+Renamed several files.
+
+Added command autocompletion.
+
+Added menus to PyCrust.py: File, Edit and Help.
+
+Added sample applications: ``PyCrustAlaCarte.py``,
+``PyCrustAlaMode.py``, and ``PyCrustMinimus.py``.
+
+
+0.1 (7/1/2001 to 7/19/2001)
+---------------------------
+
+Added basic syntax coloring much like Boa.
+
+Added read-only logging much like IDLE.
+
+Can retrieve a previous command by putting the cursor back on that
+line and hitting enter.
+
+Stdin and raw_input operate properly so you can now do ``help()`` and
+``license()`` without hanging.
+
+Redefined "quit", "exit", and "close" to display a better-than-nothing
+response.
+
+Home key honors the prompt.
+
+Created SourceForge account, but nothing was posted.
+
+
+In the beginning, there was pie... (7/1/2001)
+---------------------------------------------
+
+Blame it all on IDLE, Boa and PythonWin. I was using all three, got
+frustrated with their dissimilarities, and began to let everyone know
+how I felt. At the same time, Scintilla looked like an interesting
+tool to build a shell around. And while I didn't receive much in the
+way of positive feedback, let alone encouragement, I just couldn't let
+go of the idea of a Scintilla-based Python shell. Then the PythonCard
+project got to the point where they were talking about including a
+shell in their development environment. That was all the incentive I
+needed. PyCrust had to happen...
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/Py.ico b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/Py.ico
new file mode 100644
index 0000000..eae6180
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/Py.ico
Binary files differ
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaCarte.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaCarte.py
new file mode 100644
index 0000000..53e0282
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaCarte.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python2
+"""PyAlaCarte is a simple programmer's editor."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import py
+
+import os
+import sys
+
+class App(wx.App):
+ """PyAlaCarte standalone application."""
+
+ def __init__(self, filename=None):
+ self.filename = filename
+ wx.App.__init__(self, redirect=False)
+
+ def OnInit(self):
+ wx.InitAllImageHandlers()
+ self.frame = py.editor.EditorFrame(filename=self.filename)
+ self.frame.Show()
+ self.SetTopWindow(self.frame)
+ return True
+
+def main(filename=None):
+ if not filename and len(sys.argv) > 1:
+ filename = sys.argv[1]
+ if filename:
+ filename = os.path.realpath(filename)
+ app = App(filename)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaMode.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaMode.py
new file mode 100644
index 0000000..71c51a7
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaMode.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python2
+"""PyAlaMode is a programmer's editor."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import py
+
+import os
+import sys
+
+class App(wx.App):
+ """PyAlaMode standalone application."""
+
+ def __init__(self, filename=None):
+ self.filename = filename
+ wx.App.__init__(self, redirect=False)
+
+ def OnInit(self):
+ wx.InitAllImageHandlers()
+ self.frame = py.editor.EditorNotebookFrame(filename=self.filename)
+ self.frame.Show()
+ self.SetTopWindow(self.frame)
+ return True
+
+def main(filename=None):
+ if not filename and len(sys.argv) > 1:
+ filename = sys.argv[1]
+ if filename:
+ filename = os.path.realpath(filename)
+ app = App(filename)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaModeTest.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaModeTest.py
new file mode 100644
index 0000000..78cffdf
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyAlaModeTest.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python2
+"""PyAlaModeTest is a programmer's editor."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import py
+
+import os
+import sys
+
+class App(wx.App):
+ """PyAlaModeTest standalone application."""
+
+ def __init__(self, filename=None):
+ self.filename = filename
+ wx.App.__init__(self, redirect=False)
+
+ def OnInit(self):
+ wx.InitAllImageHandlers()
+ self.frame = py.editor.EditorShellNotebookFrame(filename=self.filename)
+ self.frame.Show()
+ self.SetTopWindow(self.frame)
+ return True
+
+def main(filename=None):
+ app = App(filename)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ filename = None
+ if len(sys.argv) > 1:
+ filename = os.path.realpath(sys.argv[1])
+ main(filename)
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.ico b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.ico
new file mode 100644
index 0000000..eae6180
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.ico
Binary files differ
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.py
new file mode 100644
index 0000000..3ecbcc4
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyCrust.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python2
+"""PyCrust is a python shell and namespace browser application."""
+
+# The next two lines, and the other code below that makes use of
+# ``__main__`` and ``original``, serve the purpose of cleaning up the
+# main namespace to look as much as possible like the regular Python
+# shell environment.
+import __main__
+original = __main__.__dict__.keys()
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+
+class App(wx.App):
+ """PyCrust standalone application."""
+
+ def OnInit(self):
+ import os
+ import wx
+ from wx import py
+
+ 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:
+
+ #!/usr/bin/env python2
+
+ from wx.py.PyCrust import main
+ main()
+'''
+
+def main():
+ """The main function for the PyCrust program."""
+ # Cleanup the main namespace, leaving the App class.
+ import __main__
+ md = __main__.__dict__
+ keepers = original
+ keepers.append('App')
+ for key in md.keys():
+ if key not in keepers:
+ del md[key]
+ # Create an application instance.
+ app = App(0)
+ # Mimic the contents of the standard Python shell's sys.path.
+ import sys
+ if sys.path[0]:
+ sys.path[0] = ''
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.app.whatever
+ sys.app = app
+ del sys
+ # Cleanup the main namespace some more.
+ if md.has_key('App') and md['App'] is App:
+ del md['App']
+ if md.has_key('__main__') and md['__main__'] is __main__:
+ del md['__main__']
+ # Start the wxPython event loop.
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyFilling.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyFilling.py
new file mode 100644
index 0000000..d5893c1
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyFilling.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python2
+"""PyFilling is a python namespace inspection application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+# We use this object to get more introspection when run standalone.
+app = None
+
+import filling
+
+# These are imported just to have something interesting to inspect.
+import crust
+import interpreter
+import introspect
+import pseudo
+import shell
+import sys
+import wx
+
+class App(filling.App):
+ def OnInit(self):
+ filling.App.OnInit(self)
+ self.root = self.fillingFrame.filling.tree.root
+ return True
+
+def main():
+ """Create and run the application."""
+ global app
+ app = App(0)
+ app.fillingFrame.filling.tree.Expand(app.root)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyShell.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyShell.py
new file mode 100644
index 0000000..d48409c
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyShell.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python2
+"""PyShell is a python shell application."""
+
+# The next two lines, and the other code below that makes use of
+# ``__main__`` and ``original``, serve the purpose of cleaning up the
+# main namespace to look as much as possible like the regular Python
+# shell environment.
+import __main__
+original = __main__.__dict__.keys()
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+import os
+
+class App(wx.App):
+ """PyShell standalone application."""
+
+ def OnInit(self):
+ import os
+ import wx
+ from wx import py
+
+ 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)
+ return True
+
+'''
+The main() function needs to handle being imported, such as with the
+pyshell script that wxPython installs:
+
+ #!/usr/bin/env python2
+
+ from wx.py.PyShell import main
+ main()
+'''
+
+def main():
+ """The main function for the PyShell program."""
+ # Cleanup the main namespace, leaving the App class.
+ import __main__
+ md = __main__.__dict__
+ keepers = original
+ keepers.append('App')
+ for key in md.keys():
+ if key not in keepers:
+ del md[key]
+ # Create an application instance.
+ app = App(0)
+ # Cleanup the main namespace some more.
+ if md.has_key('App') and md['App'] is App:
+ del md['App']
+ if md.has_key('__main__') and md['__main__'] is __main__:
+ del md['__main__']
+ # Mimic the contents of the standard Python shell's sys.path.
+ import sys
+ if sys.path[0]:
+ sys.path[0] = ''
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.app.whatever
+ sys.app = app
+ del sys
+ # Start the wxPython event loop.
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.ico b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.ico
new file mode 100644
index 0000000..b237a84
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.ico
Binary files differ
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.py
new file mode 100644
index 0000000..d47c900
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlices.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python2
+"""PySlices is a python block code editor / shell and namespace browser application."""
+
+# The next two lines, and the other code below that makes use of
+# ``__main__`` and ``original``, serve the purpose of cleaning up the
+# main namespace to look as much as possible like the regular Python
+# shell environment.
+import __main__
+original = __main__.__dict__.keys()
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com> / "
+__author__ += "David N. Mashburn <david.n.mashburn@gmail.com>"
+__cvsid__ = "$Id: PySlices.py 36607 2005-12-30 23:02:03Z RD $" # Hmmm...
+__revision__ = "$Revision: 36607 $"[11:-2] #Hmmm...
+
+import wx
+import os
+
+class App(wx.App):
+ """PySlices standalone application."""
+
+ def __init__(self, filename=None):
+ self.filename = filename
+ import wx
+ wx.App.__init__(self, redirect=False)
+
+
+ def OnInit(self):
+ import os
+ import wx
+ from wx import py
+
+ self.SetAppName("pyslices")
+ 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.crustslices.CrustSlicesFrame(config=self.config, dataDir=confDir,
+ filename=self.filename)
+## 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:
+
+ #!/usr/bin/env python2
+
+ from wx.py.PySlices import main
+ main()
+'''
+
+def main(filename=None):
+ """The main function for the PySlices program."""
+ # Cleanup the main namespace, leaving the App class.
+ import sys
+ if not filename and len(sys.argv) > 1:
+ filename = sys.argv[1]
+ if filename:
+ filename = os.path.realpath(filename)
+
+ import __main__
+ md = __main__.__dict__
+ keepers = original
+ keepers.append('App')
+ keepers.append('filename')
+ for key in md.keys():
+ if key not in keepers:
+ del md[key]
+ # Create an application instance.
+ app = App(filename=filename)
+ # Mimic the contents of the standard Python shell's sys.path.
+ import sys
+ if sys.path[0]:
+ sys.path[0] = ''
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.app.whatever
+ sys.app = app
+ del sys
+ # Cleanup the main namespace some more.
+ if md.has_key('App') and md['App'] is App:
+ del md['App']
+ if md.has_key('filename') and md['filename'] is filename:
+ del md['filename']
+ if md.has_key('__main__') and md['__main__'] is __main__:
+ del md['__main__']
+ # Start the wxPython event loop.
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlicesShell.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlicesShell.py
new file mode 100644
index 0000000..28b500e
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PySlicesShell.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python2
+"""PySlicesShell is a python shell application."""
+
+# The next two lines, and the other code below that makes use of
+# ``__main__`` and ``original``, serve the purpose of cleaning up the
+# main namespace to look as much as possible like the regular Python
+# shell environment.
+import __main__
+original = __main__.__dict__.keys()
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id: PySlicesShell.py 41078 2006-09-09 00:38:53Z RD $"
+__revision__ = "$Revision: 41078 $"[11:-2]
+
+import wx
+import os
+
+class App(wx.App):
+ """PySlicesShell standalone application."""
+
+ def __init__(self, filename=None):
+ self.filename = filename
+ import wx
+ wx.App.__init__(self, redirect=False)
+
+ def OnInit(self):
+ import os
+ import wx
+ from wx import py
+
+ self.SetAppName("pysliceshell")
+ 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.sliceshell.SlicesShellFrame(config=self.config,
+ dataDir=confDir,
+ filename=self.filename)
+ self.frame.Show()
+ self.SetTopWindow(self.frame)
+ return True
+
+'''
+The main() function needs to handle being imported, such as with the
+pyshell script that wxPython installs:
+
+ #!/usr/bin/env python2
+
+ from wx.py.PySlicesShell import main
+ main()
+'''
+
+def main(filename=None):
+ """The main function for the PySlicesShell program."""
+ # Cleanup the main namespace, leaving the App class.
+ import sys
+ if not filename and len(sys.argv) > 1:
+ filename = sys.argv[1]
+ if filename:
+ filename = os.path.realpath(filename)
+
+ import __main__
+ md = __main__.__dict__
+ keepers = original
+ keepers.append('App')
+ keepers.append('filename')
+ for key in md.keys():
+ if key not in keepers:
+ del md[key]
+ # Create an application instance.
+ app = App(filename=filename)
+ # Cleanup the main namespace some more.
+ if md.has_key('App') and md['App'] is App:
+ del md['App']
+ if md.has_key('filename') and md['filename'] is filename:
+ del md['filename']
+ if md.has_key('__main__') and md['__main__'] is __main__:
+ del md['__main__']
+ # Mimic the contents of the standard Python shell's sys.path.
+ import sys
+ if sys.path[0]:
+ sys.path[0] = ''
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.app.whatever
+ sys.app = app
+ del sys
+ # Start the wxPython event loop.
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyWrap.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyWrap.py
new file mode 100644
index 0000000..fafa382
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/PyWrap.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python2
+"""PyWrap is a command line utility that runs a wxPython program with
+additional runtime-tools, such as PyCrust."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import py
+
+import os
+import sys
+
+def wrap(app):
+ wx.InitAllImageHandlers()
+ frame = py.crust.CrustFrame()
+ frame.SetSize((750, 525))
+ frame.Show(True)
+ frame.shell.interp.locals['app'] = app
+ app.MainLoop()
+
+def main(modulename=None):
+ sys.path.insert(0, os.curdir)
+ if not modulename:
+ if len(sys.argv) < 2:
+ print "Please specify a module name."
+ raise SystemExit
+ modulename = sys.argv[1]
+ if modulename.endswith('.py'):
+ modulename = modulename[:-3]
+ module = __import__(modulename)
+ # Find the App class.
+ App = None
+ d = module.__dict__
+ for item in d.keys():
+ try:
+ if issubclass(d[item], wx.App):
+ App = d[item]
+ except (NameError, TypeError):
+ pass
+ if App is None:
+ print "No App class was found."
+ raise SystemExit
+ app = App()
+ wrap(app)
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/README.txt b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/README.txt
new file mode 100644
index 0000000..2d70db7
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/README.txt
@@ -0,0 +1,83 @@
+=====================================
+ PyCrust - The Flakiest Python Shell
+=====================================
+
+Half-baked by Patrick K. O'Brien (pobrien@orbtech.com)
+
+Orbtech - "Your source for Python programming expertise."
+Sample all our half-baked Python goods at www.orbtech.com.
+
+
+What is PyCrust?
+----------------
+
+PyCrust is an interactive Python environment written in Python.
+PyCrust components can run standalone or be integrated into other
+development environments and/or other Python applications.
+
+PyCrust comes with an interactive Python shell (PyShell), an
+interactive namespace/object tree control (PyFilling) and an
+integrated, split-window combination of the two (PyCrust).
+
+
+What is PyCrust good for?
+-------------------------
+
+Have you ever tried to bake a pie without one? Well, you shouldn't
+build a Python program without a PyCrust either.
+
+
+What else do I need to use PyCrust?
+-----------------------------------
+
+PyCrust requires Python 2.2 or later, and wxPython 2.4 or later.
+PyCrust uses wxPython and the Scintilla wrapper (wxStyledTextCtrl).
+Python is available at http://www.python.org/. wxPython is available
+at http://www.wxpython.org/.
+
+
+Where can I get the latest version of PyCrust?
+----------------------------------------------
+
+The latest production version ships with wxPython. The latest
+developer version is available in the wxWindows CVS at:
+http://cvs.wxwindows.org/viewcvs.cgi/
+
+
+Where is the PyCrust project hosted?
+------------------------------------
+
+The old answer was "At SourceForge, of course." The SourceForge
+summary page is still available at:
+http://sourceforge.net/projects/pycrust/
+
+The new answer is that there is no longer a need for a separate
+project. Simply install wxPython and you'll have everything you need.
+
+
+I found a bug in PyCrust, what do I do with it?
+-----------------------------------------------
+
+You can send it to me at pobrien@orbtech.com.
+
+
+I want a new feature added to PyCrust. Will you do it?
+------------------------------------------------------
+
+Flattery and money will get you anything. Short of that, you can send
+me a request and I'll see what I can do.
+
+
+Does PyCrust have a mailing list full of wonderful people?
+----------------------------------------------------------
+
+As a matter of fact, we do. Join the PyCrust mailing lists at:
+http://sourceforge.net/mail/?group_id=31263
+
+
+What is the CVS information for this README file?
+-------------------------------------------------
+
+$Date$
+$Revision$
+$Id$
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/__init__.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/__init__.py
new file mode 100644
index 0000000..edf6fb5
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/__init__.py
@@ -0,0 +1,22 @@
+"""The py package, formerly the PyCrust package."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import buffer
+import crust
+import crustslices
+import dispatcher
+import document
+import editor
+import editwindow
+import filling
+import frame
+import images
+import interpreter
+import introspect
+import pseudo
+import shell
+import sliceshell
+import version
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/buffer.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/buffer.py
new file mode 100644
index 0000000..7766694
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/buffer.py
@@ -0,0 +1,138 @@
+"""Buffer class."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+from interpreter import Interpreter
+import imp
+import os
+import sys
+
+import document
+
+
+class Buffer:
+ """Buffer class."""
+
+ id = 0
+
+ def __init__(self, filename=None):
+ """Create a Buffer instance."""
+ Buffer.id += 1
+ self.id = Buffer.id
+ self.interp = Interpreter(locals={})
+ self.name = ''
+ self.editors = {}
+ self.editor = None
+ self.modules = sys.modules.keys()
+ self.syspath = sys.path[:]
+ while True:
+ try:
+ self.syspath.remove('')
+ except ValueError:
+ break
+ while True:
+ try:
+ self.syspath.remove('.')
+ except ValueError:
+ break
+ self.open(filename)
+
+ def addEditor(self, editor):
+ """Add an editor."""
+ self.editor = editor
+ self.editors[editor.id] = editor
+
+ def hasChanged(self):
+ """Return True if text in editor has changed since last save."""
+ if self.editor:
+ return self.editor.hasChanged()
+ else:
+ return False
+
+ def new(self, filepath):
+ """New empty buffer."""
+ if not filepath:
+ return
+ if os.path.exists(filepath):
+ self.confirmed = self.overwriteConfirm(filepath)
+ else:
+ self.confirmed = True
+
+ def open(self, filename):
+ """Open file into buffer."""
+ self.doc = document.Document(filename)
+ self.name = self.doc.filename or ('Untitled:' + str(self.id))
+ self.modulename = self.doc.filebase
+ # XXX This should really make sure filedir is first item in syspath.
+ # XXX Or maybe this should be moved to the update namespace method.
+ if self.doc.filedir and self.doc.filedir not in self.syspath:
+ # To create the proper context for updateNamespace.
+ self.syspath.insert(0, self.doc.filedir)
+ if self.doc.filepath and os.path.exists(self.doc.filepath):
+ self.confirmed = True
+ if self.editor:
+ text = self.doc.read()
+ self.editor._setBuffer(buffer=self, text=text)
+
+ def overwriteConfirm(self, filepath):
+ """Confirm overwriting an existing file."""
+ return False
+
+ def save(self):
+ """Save buffer."""
+ filepath = self.doc.filepath
+ if not filepath:
+ return # XXX Get filename
+ if not os.path.exists(filepath):
+ self.confirmed = True
+ if not self.confirmed:
+ self.confirmed = self.overwriteConfirm(filepath)
+ if self.confirmed:
+ self.doc.write(self.editor.getText())
+ if self.editor:
+ self.editor.setSavePoint()
+
+ def saveAs(self, filename):
+ """Save buffer."""
+ self.doc = document.Document(filename)
+ self.name = self.doc.filename
+ self.modulename = self.doc.filebase
+ self.save()
+
+ def updateNamespace(self):
+ """Update the namespace for autocompletion and calltips.
+
+ Return True if updated, False if there was an error."""
+ if not self.interp or not hasattr(self.editor, 'getText'):
+ return False
+ syspath = sys.path
+ sys.path = self.syspath
+ text = self.editor.getText()
+ text = text.replace('\r\n', '\n')
+ text = text.replace('\r', '\n')
+ name = self.modulename or self.name
+ module = imp.new_module(name)
+ newspace = module.__dict__.copy()
+ try:
+ try:
+ code = compile(text, name, 'exec')
+ except:
+ raise
+# return False
+ try:
+ exec code in newspace
+ except:
+ raise
+# return False
+ else:
+ # No problems, so update the namespace.
+ self.interp.locals.clear()
+ self.interp.locals.update(newspace)
+ return True
+ finally:
+ sys.path = syspath
+ for m in sys.modules.keys():
+ if m not in self.modules:
+ del sys.modules[m]
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crust.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crust.py
new file mode 100644
index 0000000..aed30a1
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crust.py
@@ -0,0 +1,379 @@
+"""Crust combines the shell and filling into one control."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+
+import os
+import pprint
+import re
+import sys
+
+import dispatcher
+import editwindow
+from filling import Filling
+import frame
+from shell import Shell
+from version import VERSION
+
+
+class Crust(wx.SplitterWindow):
+ """Crust based on SplitterWindow."""
+
+ name = 'Crust'
+ revision = __revision__
+ sashoffset = 300
+
+ 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,
+ startupScript=None, execStartupScript=True,
+ *args, **kwds):
+ """Create Crust instance."""
+ wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
+
+ # Turn off the tab-traversal style that is automatically
+ # turned on by wx.SplitterWindow. We do this because on
+ # Windows the event for Ctrl-Enter is stolen and used as a
+ # navigation key, but the Shell window uses it to insert lines.
+ style = self.GetWindowStyle()
+ self.SetWindowStyle(style & ~wx.TAB_TRAVERSAL)
+
+ 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,
+ 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='History')
+
+ self.dispatcherlisting = DispatcherListing(parent=self.notebook)
+ self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
+
+
+ # Initialize in an unsplit mode, and check later after loading
+ # settings if we should split or not.
+ self.shell.Hide()
+ self.notebook.Hide()
+ self.Initialize(self.shell)
+ self._shouldsplit = True
+ wx.CallAfter(self._CheckShouldSplit)
+ self.SetMinimumPaneSize(100)
+
+ self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
+ self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
+ self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnSashDClick)
+
+ def _CheckShouldSplit(self):
+ if self._shouldsplit:
+ self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
+ self.lastsashpos = self.GetSashPosition()
+ else:
+ self.lastsashpos = -1
+ self.issplit = self.IsSplit()
+
+ def ToggleTools(self):
+ """Toggle the display of the filling and other tools"""
+ if self.issplit:
+ self.Unsplit()
+ else:
+ self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
+ self.lastsashpos = self.GetSashPosition()
+ self.issplit = self.IsSplit()
+
+ def ToolsShown(self):
+ return self.issplit
+
+ def OnChanged(self, event):
+ """update sash offset from the bottom of the window"""
+ self.sashoffset = self.GetSize().height - event.GetSashPosition()
+ self.lastsashpos = event.GetSashPosition()
+ event.Skip()
+
+ def OnSashDClick(self, event):
+ self.Unsplit()
+ self.issplit = False
+
+ # 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)
+ self.issplit = config.ReadInt('Sash/IsSplit', True)
+ if not self.issplit:
+ self._shouldsplit = False
+
+ def SaveSettings(self, config):
+ self.shell.SaveSettings(config)
+ self.filling.SaveSettings(config)
+
+ if self.lastsashpos != -1:
+ config.WriteInt('Sash/CrustPos', self.lastsashpos)
+ config.WriteInt('Sash/IsSplit', self.issplit)
+ config.WriteInt('View/Zoom/Display', self.display.GetZoom())
+
+class Display(editwindow.EditWindow):
+ """STC used to display an object using Pretty Print."""
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize,
+ style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER,
+ static=False):
+ """Create Display instance."""
+ editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
+ # Configure various defaults and user preferences.
+ self.SetReadOnly(True)
+ self.SetWrapMode(False)
+ if not static:
+ dispatcher.connect(receiver=self.push, signal='Interpreter.push')
+
+ def push(self, command, more):
+ """Receiver for Interpreter.push signal."""
+ self.Refresh()
+
+ def Refresh(self):
+ if not hasattr(self, "item"):
+ return
+ self.SetReadOnly(False)
+ text = pprint.pformat(self.item)
+ self.SetText(text)
+ self.SetReadOnly(True)
+
+ def setItem(self, item):
+ """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,ShellClassName='Shell'):
+ style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
+ wx.TextCtrl.__init__(self, parent, id, style=style)
+ self.SetBackgroundColour(wx.Colour(255, 255, 208))
+ self.ShellClassName=ShellClassName
+ dispatcher.connect(receiver=self.display, signal=self.ShellClassName+'.calltip')
+
+ df = self.GetFont()
+ font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
+ self.SetFont(font)
+
+ def display(self, calltip):
+ """Receiver for """+self.ShellClassName+""".calltip signal."""
+ ## self.SetValue(calltip) # Caused refresh problem on Windows.
+ self.Clear()
+ self.AppendText(calltip)
+ self.SetInsertionPoint(0)
+
+
+# TODO: Switch this to a editwindow.EditWindow
+class SessionListing(wx.TextCtrl):
+ """Text control containing all commands for session."""
+
+ def __init__(self, parent=None, id=-1,ShellClassName='Shell'):
+ style = (wx.TE_MULTILINE | wx.TE_READONLY |
+ wx.TE_RICH2 | wx.TE_DONTWRAP)
+ wx.TextCtrl.__init__(self, parent, id, style=style)
+ dispatcher.connect(receiver=self.addHistory,
+ signal=ShellClassName+".addHistory")
+ dispatcher.connect(receiver=self.clearHistory,
+ signal=ShellClassName+".clearHistory")
+ dispatcher.connect(receiver=self.loadHistory,
+ signal=ShellClassName+".loadHistory")
+
+ df = self.GetFont()
+ font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
+ self.SetFont(font)
+
+ def loadHistory(self, history):
+ # preload the existing history, if any
+ hist = history[:]
+ hist.reverse()
+ self.SetValue('\n'.join(hist) + '\n')
+ self.SetInsertionPointEnd()
+
+ def addHistory(self, command):
+ if command:
+ self.SetInsertionPointEnd()
+ self.AppendText(command + '\n')
+
+ def clearHistory(self):
+ self.SetValue("")
+
+
+class DispatcherListing(wx.TextCtrl):
+ """Text control containing all dispatches for session."""
+
+ def __init__(self, parent=None, id=-1):
+ style = (wx.TE_MULTILINE | wx.TE_READONLY |
+ wx.TE_RICH2 | wx.TE_DONTWRAP)
+ wx.TextCtrl.__init__(self, parent, id, style=style)
+ dispatcher.connect(receiver=self.spy)
+
+ df = self.GetFont()
+ font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
+ self.SetFont(font)
+
+ def spy(self, signal, sender):
+ """Receiver for Any signal from Any sender."""
+ text = '%r from %s' % (signal, sender)
+ self.SetInsertionPointEnd()
+ start, end = self.GetSelection()
+ if start != end:
+ self.SetSelection(0, 0)
+ self.AppendText(text + '\n')
+
+
+
+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,
+ config=None, dataDir=None,
+ *args, **kwds):
+ """Create CrustFrame instance."""
+ frame.Frame.__init__(self, parent, id, title, pos, size, style,
+ shellName='PyCrust')
+ frame.ShellFrameMixin.__init__(self, config, dataDir)
+
+ if size == wx.DefaultSize:
+ self.SetSize((800, 600))
+
+ intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
+
+ self.SetStatusText(intro.replace('\n', ', '))
+ self.crust = Crust(parent=self, intro=intro,
+ rootObject=rootObject,
+ rootLabel=rootLabel,
+ rootIsNamespace=rootIsNamespace,
+ locals=locals,
+ 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
+
+ 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'
+ text = 'PyCrust %s\n\n' % VERSION + \
+ 'Yet another Python shell, only flakier.\n\n' + \
+ 'Half-baked by Patrick K. O\'Brien,\n' + \
+ 'the other half is still in the oven.\n\n' + \
+ 'Shell Revision: %s\n' % self.shell.revision + \
+ 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
+ '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:]))
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+
+ def ToggleTools(self):
+ """Toggle the display of the filling and other tools"""
+ return self.crust.ToggleTools()
+
+ def ToolsShown(self):
+ return self.crust.ToolsShown()
+
+ def OnHelp(self, event):
+ """Show a help dialog."""
+ frame.ShellFrameMixin.OnHelp(self, event)
+
+ 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, force=False):
+ if self.config is not None:
+ frame.ShellFrameMixin.SaveSettings(self,force)
+ if self.autoSaveSettings or force:
+ frame.Frame.SaveSettings(self, self.config)
+ self.crust.SaveSettings(self.config)
+
+
+ def DoSaveSettings(self):
+ if self.config is not None:
+ self.SaveSettings(force=True)
+ self.config.Flush()
+
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crustslices.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crustslices.py
new file mode 100644
index 0000000..aa7bd23
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/crustslices.py
@@ -0,0 +1,416 @@
+"""PySlices combines the slices and filling into one control."""
+
+__author__ = "David N. Mashburn <david.n.mashburn@gmail.com> / "
+__author__ += "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id: crustslices.py 44235 2007-01-17 23:05:14Z RD $"
+__revision__ = "$Revision: 44235 $"[11:-2]
+
+import wx
+
+import os
+import pprint
+import re
+import sys
+
+import dispatcher
+import crust
+import document
+import editwindow
+import editor
+from filling import Filling
+import frame
+from sliceshell import SlicesShell
+from version import VERSION
+
+
+class CrustSlices(crust.Crust):
+ """Slices based on SplitterWindow."""
+
+ name = 'Slices'
+ revision = __revision__
+ sashoffset = 300
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
+ name='Slices Window', rootObject=None, rootLabel=None,
+ rootIsNamespace=True, intro='', locals=None,
+ InterpClass=None,
+ startupScript=None, execStartupScript=True,
+ showPySlicesTutorial=True,
+ enableShellMode=False, hideFoldingMargin=False,
+ *args, **kwds):
+ """Create CrustSlices instance."""
+ wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
+
+ # Turn off the tab-traversal style that is automatically
+ # turned on by wx.SplitterWindow. We do this because on
+ # Windows the event for Ctrl-Enter is stolen and used as a
+ # navigation key, but the SlicesShell window uses it to insert lines.
+ style = self.GetWindowStyle()
+ self.SetWindowStyle(style & ~wx.TAB_TRAVERSAL)
+
+ self.sliceshell = SlicesShell(parent=self, introText=intro,
+ locals=locals, InterpClass=InterpClass,
+ startupScript=startupScript,
+ execStartupScript=execStartupScript,
+ showPySlicesTutorial=showPySlicesTutorial,
+ enableShellMode=enableShellMode,
+ hideFoldingMargin=hideFoldingMargin,
+ *args, **kwds)
+
+ self.editor = self.sliceshell
+ self.shell = self.sliceshell
+ if rootObject is None:
+ rootObject = self.sliceshell.interp.locals
+ self.notebook = wx.Notebook(parent=self, id=-1)
+ self.sliceshell.interp.locals['notebook'] = self.notebook
+ self.filling = Filling(parent=self.notebook,
+ rootObject=rootObject,
+ rootLabel=rootLabel,
+ rootIsNamespace=rootIsNamespace)
+ # Add 'filling' to the interpreter's locals.
+ self.sliceshell.interp.locals['filling'] = self.filling
+ self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
+
+ self.display = crust.Display(parent=self.notebook)
+ self.notebook.AddPage(page=self.display, text='Display')
+ # Add 'pp' (pretty print) to the interpreter's locals.
+ self.sliceshell.interp.locals['pp'] = self.display.setItem
+ self.display.nbTab = self.notebook.GetPageCount()-1
+
+ self.calltip = crust.Calltip(parent=self.notebook,ShellClassName='SlicesShell')
+ self.notebook.AddPage(page=self.calltip, text='Calltip')
+
+ self.sessionlisting = crust.SessionListing(parent=self.notebook,ShellClassName='SlicesShell')
+ self.notebook.AddPage(page=self.sessionlisting, text='History')
+
+ self.dispatcherlisting = crust.DispatcherListing(parent=self.notebook)
+ self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
+
+
+ # Initialize in an unsplit mode, and check later after loading
+ # settings if we should split or not.
+ self.sliceshell.Hide()
+ self.notebook.Hide()
+ self.Initialize(self.sliceshell)
+ self._shouldsplit = True
+ wx.CallAfter(self._CheckShouldSplit)
+ self.SetMinimumPaneSize(100)
+
+ self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
+ self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
+ self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnSashDClick)
+
+class CrustSlicesFrame(crust.CrustFrame):
+ """Frame containing all the PySlices components."""
+
+ name = 'SliceFrame'
+ revision = __revision__
+
+
+ def __init__(self, parent=None, id=-1, title='PySlices',
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_FRAME_STYLE,
+ rootObject=None, rootLabel=None, rootIsNamespace=True,
+ locals=None, InterpClass=None,
+ config=None, dataDir=None, filename=None,
+ *args, **kwds):
+ """Create CrustFrame instance."""
+ frame.Frame.__init__(self, parent, id, title, pos, size, style,
+ shellName='PySlices')
+ frame.ShellFrameMixin.__init__(self, config, dataDir)
+
+ if size == wx.DefaultSize:
+ self.SetSize((800, 600))
+
+ intro = 'PySlices %s - The Flakiest Python Shell... Cut up!' % VERSION
+
+ self.SetStatusText(intro.replace('\n', ', '))
+ self.crust = CrustSlices(parent=self, intro=intro,
+ rootObject=rootObject,
+ rootLabel=rootLabel,
+ rootIsNamespace=rootIsNamespace,
+ locals=locals,
+ InterpClass=InterpClass,
+ startupScript=self.startupScript,
+ execStartupScript=self.execStartupScript,
+ showPySlicesTutorial=self.showPySlicesTutorial,
+ enableShellMode=self.enableShellMode,
+ hideFoldingMargin=self.hideFoldingMargin,
+ *args, **kwds)
+ self.sliceshell = self.crust.sliceshell
+ self.buffer = self.sliceshell.buffer
+ # 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.sliceshell.setStatusText = self.SetStatusText
+
+ self.sliceshell.SetFocus()
+ self.LoadSettings()
+
+ self.currentDirectory = os.path.expanduser('~')
+
+ if filename!=None:
+ self.bufferOpen(filename)
+
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+ def OnClose(self, event):
+ """Event handler for closing."""
+ self.bufferClose()
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PySlices'
+ text = 'PySlices %s\n\n' % VERSION + \
+ 'Yet another Python shell, only flakier.\n\n' + \
+ 'Half-baked by Patrick K. O\'Brien,\n' + \
+ 'the other half is still in the oven.\n\n' + \
+ 'Shell Revision: %s\n' % self.sliceshell.revision + \
+ 'Interpreter Revision: %s\n\n' % self.sliceshell.interp.revision + \
+ '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:]))
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ def OnEnableShellMode(self,event):
+ """Change between Slices Mode and Shell Mode"""
+ frame.Frame.OnEnableShellMode(self,event)
+ self.sliceshell.ToggleShellMode(self.enableShellMode)
+
+ def OnHideFoldingMargin(self,event):
+ """Change between Slices Mode and Shell Mode"""
+ frame.Frame.OnHideFoldingMargin(self,event)
+ self.sliceshell.ToggleFoldingMargin(self.hideFoldingMargin)
+
+ # Stolen Straight from editor.EditorFrame
+ # Modified a little... :)
+ # ||
+ # \/
+ def OnIdle(self, event):
+ """Event handler for idle time."""
+ self._updateTitle()
+ event.Skip()
+
+ def _updateTitle(self):
+ """Show current title information."""
+ title = self.GetTitle()
+ if self.bufferHasChanged():
+ if title.startswith('* '):
+ pass
+ else:
+ self.SetTitle('* ' + title)
+ else:
+ if title.startswith('* '):
+ self.SetTitle(title[2:])
+
+ def hasBuffer(self):
+ """Return True if there is a current buffer."""
+ if self.buffer:
+ return True
+ else:
+ return False
+
+ def bufferClose(self):
+ """Close buffer."""
+ if self.buffer.hasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ #event.Veto()
+ return cancel
+ self.SaveSettings()
+ self.crust.sliceshell.destroy()
+ self.bufferDestroy()
+ self.Destroy()
+
+ return False
+
+ def bufferCreate(self, filename=None):
+ """Create new buffer."""
+ self.bufferDestroy()
+ buffer = Buffer()
+ self.panel = panel = wx.Panel(parent=self, id=-1)
+ panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
+ editor = Editor(parent=panel)
+ panel.editor = editor
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(editor.window, 1, wx.EXPAND)
+ panel.SetSizer(sizer)
+ panel.SetAutoLayout(True)
+ sizer.Layout()
+ buffer.addEditor(editor)
+ buffer.open(filename)
+ self.setEditor(editor)
+ self.editor.setFocus()
+ self.SendSizeEvent()
+
+
+ def bufferDestroy(self):
+ """Destroy the current buffer."""
+ if self.buffer:
+ self.editor = None
+ self.buffer = None
+
+
+ def bufferHasChanged(self):
+ """Return True if buffer has changed since last save."""
+ if self.buffer:
+ return self.buffer.hasChanged()
+ else:
+ return False
+
+ def bufferNew(self):
+ """Create new buffer."""
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ self.sliceshell.clear()
+ self.SetTitle( 'PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+ self.sliceshell.SetSavePoint()
+ self.buffer.doc = document.Document()
+ self.buffer.name = 'This shell'
+ self.buffer.modulename = self.buffer.doc.filebase
+ #self.bufferCreate()
+ cancel = False
+ return cancel
+
+ def bufferOpen(self,file=None):
+ """Open file in buffer."""
+ if self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+
+ if file==None:
+ file=wx.FileSelector('Open a PySlices File',
+ wildcard='*.pyslices',
+ default_path=self.currentDirectory)
+ if file!=None and file!=u'':
+ fid=open(file,'r')
+ self.sliceshell.LoadPySlicesFile(fid)
+ fid.close()
+ self.currentDirectory = os.path.split(file)[0]
+ self.SetTitle( os.path.split(file)[1] + ' - PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+ self.sliceshell.SetSavePoint()
+ self.buffer.doc = document.Document(file)
+ self.buffer.name = self.buffer.doc.filename
+ self.buffer.modulename = self.buffer.doc.filebase
+ self.sliceshell.ScrollToLine(0)
+ return
+
+## def bufferPrint(self):
+## """Print buffer."""
+## pass
+
+## def bufferRevert(self):
+## """Revert buffer to version of file on disk."""
+## pass
+
+ # was self.buffer.save(self): # """Save buffer."""
+ def simpleSave(self,confirmed=False):
+ filepath = self.buffer.doc.filepath
+ self.buffer.confirmed = confirmed
+ if not filepath:
+ return # XXX Get filename
+ if not os.path.exists(filepath):
+ self.buffer.confirmed = True
+ if not self.buffer.confirmed:
+ self.buffer.confirmed = self.buffer.overwriteConfirm(filepath)
+ if self.buffer.confirmed:
+ try:
+ fid = open(filepath, 'wb')
+ self.sliceshell.SavePySlicesFile(fid)
+ finally:
+ if fid:
+ fid.close()
+ self.sliceshell.SetSavePoint()
+ self.SetTitle( os.path.split(filepath)[1] + ' - PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+
+ def bufferSave(self):
+ """Save buffer to its file."""
+ if self.buffer.doc.filepath:
+ # self.buffer.save()
+ self.simpleSave(confirmed=True)
+ cancel = False
+ else:
+ cancel = self.bufferSaveAs()
+ return cancel
+
+ def bufferSaveAs(self):
+ """Save buffer to a new filename."""
+ if self.bufferHasChanged() and self.buffer.doc.filepath:
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = editor.saveSingle(title='Save PySlices File',directory=filedir,
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
+ if result.path not in ['',None]:
+ if result.path[-9:]!=".pyslices":
+ result.path+=".pyslices"
+
+ self.buffer.doc = document.Document(result.path)
+ self.buffer.name = self.buffer.doc.filename
+ self.buffer.modulename = self.buffer.doc.filebase
+ self.simpleSave(confirmed=True) # allow overwrite
+ cancel = False
+ else:
+ cancel = True
+ return cancel
+
+ def bufferSaveACopy(self):
+ """Save buffer to a new filename."""
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = editor.saveSingle(title='Save a Copy of PySlices File',directory=filedir,
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
+
+ if result.path not in ['',None]:
+ if result.path[-9:]!=".pyslices":
+ result.path+=".pyslices"
+
+ # if not os.path.exists(result.path):
+ try: # Allow overwrite...
+ fid = open(result.path, 'wb')
+ self.sliceshell.SavePySlicesFile(fid)
+ finally:
+ if fid:
+ fid.close()
+
+ cancel = False
+ else:
+ cancel = True
+ return cancel
+
+ def bufferSuggestSave(self):
+ """Suggest saving changes. Return True if user selected Cancel."""
+ result = editor.messageDialog(parent=None,
+ message='%s has changed.\n'
+ 'Would you like to save it first'
+ '?' % self.buffer.name,
+ title='Save current file?',
+ style=wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT |
+ wx.CENTRE | wx.ICON_QUESTION )
+ if result.positive:
+ cancel = self.bufferSave()
+ else:
+ cancel = result.text == 'Cancel'
+ return cancel
+
+ def updateNamespace(self):
+ """Update the buffer namespace for autocompletion and calltips."""
+ if self.buffer.updateNamespace():
+ self.SetStatusText('Namespace updated')
+ else:
+ self.SetStatusText('Error executing, unable to update namespace')
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/dispatcher.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/dispatcher.py
new file mode 100644
index 0000000..c2a4673
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/dispatcher.py
@@ -0,0 +1,262 @@
+"""Provides global signal dispatching services."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import exceptions
+import types
+import weakref
+
+
+class DispatcherError(exceptions.Exception):
+ def __init__(self, args=None):
+ self.args = args
+
+
+class Parameter:
+ """Used to represent default parameter values."""
+ def __repr__(self):
+ return self.__class__.__name__
+
+class Any(Parameter): pass
+Any = Any()
+
+class Anonymous(Parameter): pass
+Anonymous = Anonymous()
+
+
+connections = {}
+senders = {}
+_boundMethods = weakref.WeakKeyDictionary()
+
+
+def connect(receiver, signal=Any, sender=Any, weak=True):
+ """
+ Connect receiver to sender for signal.
+
+ * If sender is Any, receiver will receive signal from any sender.
+ * If signal is Any, receiver will receive any signal from sender.
+ * If sender is None, receiver will receive signal from Anonymous.
+ * If signal is Any and sender is None, receiver will receive any
+ signal from Anonymous.
+ * If signal is Any and sender is Any, receiver will receive any
+ signal from any sender.
+ * If weak is true, weak references will be used.
+ """
+ if signal is None:
+ raise DispatcherError, 'signal cannot be None'
+ if weak:
+ receiver = safeRef(receiver)
+ senderkey = id(sender)
+ signals = {}
+ if connections.has_key(senderkey):
+ signals = connections[senderkey]
+ else:
+ connections[senderkey] = signals
+ # Keep track of senders for cleanup.
+ if sender not in (None, Any):
+ def remove(object, senderkey=senderkey):
+ _removeSender(senderkey=senderkey)
+ # Skip objects that can not be weakly referenced, which means
+ # they won't be automatically cleaned up, but that's too bad.
+ try:
+ weakSender = weakref.ref(sender, remove)
+ senders[senderkey] = weakSender
+ except:
+ pass
+ receivers = []
+ if signals.has_key(signal):
+ receivers = signals[signal]
+ else:
+ signals[signal] = receivers
+ try:
+ receivers.remove(receiver)
+ except ValueError:
+ pass
+ receivers.append(receiver)
+
+def disconnect(receiver, signal=Any, sender=Any, weak=True):
+ """Disconnect receiver from sender for signal.
+
+ Disconnecting is not required. The use of disconnect is the same as for
+ connect, only in reverse. Think of it as undoing a previous connection."""
+ if signal is None:
+ raise DispatcherError, 'signal cannot be None'
+ if weak:
+ receiver = safeRef(receiver)
+ senderkey = id(sender)
+ try:
+ receivers = connections[senderkey][signal]
+ except KeyError:
+ raise DispatcherError, \
+ 'No receivers for signal %r from sender %s' % (signal, sender)
+ try:
+ receivers.remove(receiver)
+ except ValueError:
+ raise DispatcherError, \
+ 'No connection to receiver %s for signal %r from sender %s' % \
+ (receiver, signal, sender)
+ _cleanupConnections(senderkey, signal)
+
+def send(signal, sender=Anonymous, **kwds):
+ """Send signal from sender to all connected receivers.
+
+ Return a list of tuple pairs [(receiver, response), ... ].
+ If sender is not specified, signal is sent anonymously."""
+ senderkey = id(sender)
+ anykey = id(Any)
+ # Get receivers that receive *this* signal from *this* sender.
+ receivers = []
+ try:
+ receivers.extend(connections[senderkey][signal])
+ except KeyError:
+ pass
+ # Add receivers that receive *any* signal from *this* sender.
+ anyreceivers = []
+ try:
+ anyreceivers = connections[senderkey][Any]
+ except KeyError:
+ pass
+ for receiver in anyreceivers:
+ if receivers.count(receiver) == 0:
+ receivers.append(receiver)
+ # Add receivers that receive *this* signal from *any* sender.
+ anyreceivers = []
+ try:
+ anyreceivers = connections[anykey][signal]
+ except KeyError:
+ pass
+ for receiver in anyreceivers:
+ if receivers.count(receiver) == 0:
+ receivers.append(receiver)
+ # Add receivers that receive *any* signal from *any* sender.
+ anyreceivers = []
+ try:
+ anyreceivers = connections[anykey][Any]
+ except KeyError:
+ pass
+ for receiver in anyreceivers:
+ if receivers.count(receiver) == 0:
+ receivers.append(receiver)
+ # Call each receiver with whatever arguments it can accept.
+ # Return a list of tuple pairs [(receiver, response), ... ].
+ responses = []
+ for receiver in receivers:
+ if type(receiver) is weakref.ReferenceType \
+ or isinstance(receiver, BoundMethodWeakref):
+ # Dereference the weak reference.
+ receiver = receiver()
+ if receiver is None:
+ # This receiver is dead, so skip it.
+ continue
+ response = _call(receiver, signal=signal, sender=sender, **kwds)
+ responses += [(receiver, response)]
+ return responses
+
+def _call(receiver, **kwds):
+ """Call receiver with only arguments it can accept."""
+## if type(receiver) is types.InstanceType:
+ if hasattr(receiver, '__call__') and \
+ (hasattr(receiver.__call__, 'im_func') or hasattr(receiver.__call__, 'im_code')):
+ # receiver is a class instance; assume it is callable.
+ # Reassign receiver to the actual method that will be called.
+ receiver = receiver.__call__
+ if hasattr(receiver, 'im_func'):
+ # receiver is a method. Drop the first argument, usually 'self'.
+ fc = receiver.im_func.func_code
+ acceptable = fc.co_varnames[1:fc.co_argcount]
+ elif hasattr(receiver, 'func_code'):
+ # receiver is a function.
+ fc = receiver.func_code
+ acceptable = fc.co_varnames[0:fc.co_argcount]
+ else:
+ raise DispatcherError, 'Unknown receiver %s of type %s' % (receiver, type(receiver))
+ if not (fc.co_flags & 8):
+ # fc does not have a **kwds type parameter, therefore
+ # remove unacceptable arguments.
+ for arg in kwds.keys():
+ if arg not in acceptable:
+ del kwds[arg]
+ return receiver(**kwds)
+
+
+def safeRef(object):
+ """Return a *safe* weak reference to a callable object."""
+ if hasattr(object, 'im_self'):
+ if object.im_self is not None:
+ # Turn a bound method into a BoundMethodWeakref instance.
+ # Keep track of these instances for lookup by disconnect().
+ selfkey = object.im_self
+ funckey = object.im_func
+ if not _boundMethods.has_key(selfkey):
+ _boundMethods[selfkey] = weakref.WeakKeyDictionary()
+ if not _boundMethods[selfkey].has_key(funckey):
+ _boundMethods[selfkey][funckey] = \
+ BoundMethodWeakref(boundMethod=object)
+ return _boundMethods[selfkey][funckey]
+ return weakref.ref(object, _removeReceiver)
+
+
+class BoundMethodWeakref:
+ """BoundMethodWeakref class."""
+
+ def __init__(self, boundMethod):
+ """Return a weak-reference-like instance for a bound method."""
+ self.isDead = 0
+ def remove(object, self=self):
+ """Set self.isDead to true when method or instance is destroyed."""
+ self.isDead = 1
+ _removeReceiver(receiver=self)
+ self.weakSelf = weakref.ref(boundMethod.im_self, remove)
+ self.weakFunc = weakref.ref(boundMethod.im_func, remove)
+
+ def __repr__(self):
+ """Return the closest representation."""
+ return '<bound method weakref for %s.%s>' % (self.weakSelf, self.weakFunc)
+
+ def __call__(self):
+ """Return a strong reference to the bound method."""
+ if self.isDead:
+ return None
+ else:
+ object = self.weakSelf()
+ method = self.weakFunc().__name__
+ try: # wxPython hack to handle wxDead objects.
+ return getattr(object, method)
+ except AttributeError:
+## _removeReceiver(receiver=self)
+ return None
+
+
+def _removeReceiver(receiver):
+ """Remove receiver from connections."""
+ for senderkey in connections.keys():
+ for signal in connections[senderkey].keys():
+ receivers = connections[senderkey][signal]
+ try:
+ receivers.remove(receiver)
+ except:
+ pass
+ _cleanupConnections(senderkey, signal)
+
+def _cleanupConnections(senderkey, signal):
+ """Delete any empty signals for senderkey. Delete senderkey if empty."""
+ receivers = connections[senderkey][signal]
+ if not receivers:
+ # No more connected receivers. Therefore, remove the signal.
+ signals = connections[senderkey]
+ del signals[signal]
+ if not signals:
+ # No more signal connections. Therefore, remove the sender.
+ _removeSender(senderkey)
+
+def _removeSender(senderkey):
+ """Remove senderkey from connections."""
+ del connections[senderkey]
+ # Senderkey will only be in senders dictionary if sender
+ # could be weakly referenced.
+ try:
+ del senders[senderkey]
+ except:
+ pass
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/document.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/document.py
new file mode 100644
index 0000000..ab00ca0
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/document.py
@@ -0,0 +1,43 @@
+"""Document class."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import os
+
+
+class Document:
+ """Document class."""
+
+ def __init__(self, filename=None):
+ """Create a Document instance."""
+ self.filename = filename
+ self.filepath = None
+ self.filedir = None
+ self.filebase = None
+ self.fileext = None
+ if self.filename:
+ self.filepath = os.path.realpath(self.filename)
+ self.filedir, self.filename = os.path.split(self.filepath)
+ self.filebase, self.fileext = os.path.splitext(self.filename)
+
+ def read(self):
+ """Return contents of file."""
+ if self.filepath and os.path.exists(self.filepath):
+ f = file(self.filepath, 'rb')
+ try:
+ return f.read()
+ finally:
+ f.close()
+ else:
+ return ''
+
+ def write(self, text):
+ """Write text to file."""
+ try:
+ f = file(self.filepath, 'wb')
+ f.write(text)
+ finally:
+ if f:
+ f.close()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editor.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editor.py
new file mode 100644
index 0000000..8c66de8
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editor.py
@@ -0,0 +1,838 @@
+"""PyAlaCarte and PyAlaMode editors."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+
+from buffer import Buffer
+import crust
+import dispatcher
+import editwindow
+import frame
+from shell import Shell
+import version
+
+
+class EditorFrame(frame.Frame):
+ """Frame containing one editor."""
+
+ def __init__(self, parent=None, id=-1, title='PyAlaCarte',
+ pos=wx.DefaultPosition, size=(800, 600),
+ style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
+ filename=None):
+ """Create EditorFrame instance."""
+ frame.Frame.__init__(self, parent, id, title, pos, size, style)
+ self.buffers = {}
+ self.buffer = None # Current buffer.
+ self.editor = None
+ self._defaultText = title + ' - the tastiest Python editor.'
+ self._statusText = self._defaultText
+ self.SetStatusText(self._statusText)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+ self._setup()
+ if filename:
+ self.bufferCreate(filename)
+
+ def _setup(self):
+ """Setup prior to first buffer creation.
+
+ Useful for subclasses."""
+ pass
+
+ def setEditor(self, editor):
+ self.editor = editor
+ self.buffer = self.editor.buffer
+ self.buffers[self.buffer.id] = self.buffer
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PyAlaCarte'
+ text = 'Another fine, flaky program.'
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ def OnClose(self, event):
+ """Event handler for closing."""
+ for buffer in self.buffers.values():
+ self.buffer = buffer
+ if buffer.hasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel and event.CanVeto():
+ event.Veto()
+ return
+ self.Destroy()
+
+ def OnIdle(self, event):
+ """Event handler for idle time."""
+ self._updateStatus()
+ if hasattr(self, 'notebook'):
+ self._updateTabText()
+ self._updateTitle()
+ event.Skip()
+
+ def _updateStatus(self):
+ """Show current status information."""
+ if self.editor and hasattr(self.editor, 'getStatus'):
+ status = self.editor.getStatus()
+ text = 'File: %s | Line: %d | Column: %d' % status
+ else:
+ text = self._defaultText
+ if text != self._statusText:
+ self.SetStatusText(text)
+ self._statusText = text
+
+ def _updateTabText(self):
+ """Show current buffer information on notebook tab."""
+## suffix = ' **'
+## notebook = self.notebook
+## selection = notebook.GetSelection()
+## if selection == -1:
+## return
+## text = notebook.GetPageText(selection)
+## window = notebook.GetPage(selection)
+## if window.editor and window.editor.buffer.hasChanged():
+## if text.endswith(suffix):
+## pass
+## else:
+## notebook.SetPageText(selection, text + suffix)
+## else:
+## if text.endswith(suffix):
+## notebook.SetPageText(selection, text[:len(suffix)])
+
+ def _updateTitle(self):
+ """Show current title information."""
+ title = self.GetTitle()
+ if self.bufferHasChanged():
+ if title.startswith('* '):
+ pass
+ else:
+ self.SetTitle('* ' + title)
+ else:
+ if title.startswith('* '):
+ self.SetTitle(title[2:])
+
+ def hasBuffer(self):
+ """Return True if there is a current buffer."""
+ if self.buffer:
+ return True
+ else:
+ return False
+
+ def bufferClose(self):
+ """Close buffer."""
+ if self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ self.bufferDestroy()
+ cancel = False
+ return cancel
+
+ def bufferCreate(self, filename=None):
+ """Create new buffer."""
+ self.bufferDestroy()
+ buffer = Buffer()
+ self.panel = panel = wx.Panel(parent=self, id=-1)
+ panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
+ editor = Editor(parent=panel)
+ panel.editor = editor
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(editor.window, 1, wx.EXPAND)
+ panel.SetSizer(sizer)
+ panel.SetAutoLayout(True)
+ sizer.Layout()
+ buffer.addEditor(editor)
+ buffer.open(filename)
+ self.setEditor(editor)
+ self.editor.setFocus()
+ self.SendSizeEvent()
+
+
+ def bufferDestroy(self):
+ """Destroy the current buffer."""
+ if self.buffer:
+ for editor in self.buffer.editors.values():
+ editor.destroy()
+ self.editor = None
+ del self.buffers[self.buffer.id]
+ self.buffer = None
+ self.panel.Destroy()
+
+
+ def bufferHasChanged(self):
+ """Return True if buffer has changed since last save."""
+ if self.buffer:
+ return self.buffer.hasChanged()
+ else:
+ return False
+
+ def bufferNew(self):
+ """Create new buffer."""
+ if self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ self.bufferCreate()
+ cancel = False
+ return cancel
+
+ def bufferOpen(self):
+ """Open file in buffer."""
+ if self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = openSingle(directory=filedir)
+ if result.path:
+ self.bufferCreate(result.path)
+ cancel = False
+ return cancel
+
+## def bufferPrint(self):
+## """Print buffer."""
+## pass
+
+## def bufferRevert(self):
+## """Revert buffer to version of file on disk."""
+## pass
+
+ def bufferSave(self):
+ """Save buffer to its file."""
+ if self.buffer.doc.filepath:
+ self.buffer.save()
+ cancel = False
+ else:
+ cancel = self.bufferSaveAs()
+ return cancel
+
+ def bufferSaveAs(self):
+ """Save buffer to a new filename."""
+ if self.bufferHasChanged() and self.buffer.doc.filepath:
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = saveSingle(directory=filedir)
+ if result.path:
+ self.buffer.saveAs(result.path)
+ cancel = False
+ else:
+ cancel = True
+ return cancel
+
+ def bufferSuggestSave(self):
+ """Suggest saving changes. Return True if user selected Cancel."""
+ result = messageDialog(parent=None,
+ message='%s has changed.\n'
+ 'Would you like to save it first'
+ '?' % self.buffer.name,
+ title='Save current file?')
+ if result.positive:
+ cancel = self.bufferSave()
+ else:
+ cancel = result.text == 'Cancel'
+ return cancel
+
+ def updateNamespace(self):
+ """Update the buffer namespace for autocompletion and calltips."""
+ if self.buffer.updateNamespace():
+ self.SetStatusText('Namespace updated')
+ else:
+ self.SetStatusText('Error executing, unable to update namespace')
+
+
+class EditorNotebookFrame(EditorFrame):
+ """Frame containing one or more editors in a notebook."""
+
+ def __init__(self, parent=None, id=-1, title='PyAlaMode',
+ pos=wx.DefaultPosition, size=(800, 600),
+ style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
+ filename=None):
+ """Create EditorNotebookFrame instance."""
+ self.notebook = None
+ EditorFrame.__init__(self, parent, id, title, pos,
+ size, style, filename)
+ if self.notebook:
+ dispatcher.connect(receiver=self._editorChange,
+ signal='EditorChange', sender=self.notebook)
+
+ def _setup(self):
+ """Setup prior to first buffer creation.
+
+ Called automatically by base class during init."""
+ self.notebook = EditorNotebook(parent=self)
+ intro = 'Py %s' % version.VERSION
+ import imp
+ module = imp.new_module('__main__')
+ import __builtin__
+ module.__dict__['__builtins__'] = __builtin__
+ namespace = module.__dict__.copy()
+ self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
+ 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)
+ self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
+ self.setEditor(self.crust.editor)
+ self.crust.editor.SetFocus()
+
+ def _editorChange(self, editor):
+ """Editor change signal receiver."""
+ self.setEditor(editor)
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PyAlaMode'
+ text = 'Another fine, flaky program.'
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ def _updateTitle(self):
+ """Show current title information."""
+ pass
+## title = self.GetTitle()
+## if self.bufferHasChanged():
+## if title.startswith('* '):
+## pass
+## else:
+## self.SetTitle('* ' + title)
+## else:
+## if title.startswith('* '):
+## self.SetTitle(title[2:])
+
+ def bufferCreate(self, filename=None):
+ """Create new buffer."""
+ buffer = Buffer()
+ panel = wx.Panel(parent=self.notebook, id=-1)
+ panel.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: x)
+ editor = Editor(parent=panel)
+ panel.editor = editor
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(editor.window, 1, wx.EXPAND)
+ panel.SetSizer(sizer)
+ panel.SetAutoLayout(True)
+ sizer.Layout()
+ buffer.addEditor(editor)
+ buffer.open(filename)
+ self.setEditor(editor)
+ self.notebook.AddPage(page=panel, text=self.buffer.name, select=True)
+ self.editor.setFocus()
+
+ def bufferDestroy(self):
+ """Destroy the current buffer."""
+ selection = self.notebook.GetSelection()
+## print "Destroy Selection:", selection
+ if selection > 0: # Don't destroy the PyCrust tab.
+ if self.buffer:
+ del self.buffers[self.buffer.id]
+ self.buffer = None # Do this before DeletePage().
+ self.notebook.DeletePage(selection)
+
+ def bufferNew(self):
+ """Create new buffer."""
+ self.bufferCreate()
+ cancel = False
+ return cancel
+
+ def bufferOpen(self):
+ """Open file in buffer."""
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = openMultiple(directory=filedir)
+ for path in result.paths:
+ self.bufferCreate(path)
+ cancel = False
+ return cancel
+
+
+class EditorNotebook(wx.Notebook):
+ """A notebook containing a page for each editor."""
+
+ def __init__(self, parent):
+ """Create EditorNotebook instance."""
+ wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
+ 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."""
+ self._updateTabText()
+ event.Skip()
+
+ def _updateTabText(self):
+ """Show current buffer display name on all but first tab."""
+ size = 3
+ changed = ' **'
+ unchanged = ' --'
+ selection = self.GetSelection()
+ if selection < 1:
+ return
+ text = self.GetPageText(selection)
+ window = self.GetPage(selection)
+ if not window.editor:
+ return
+ if text.endswith(changed) or text.endswith(unchanged):
+ name = text[:-size]
+ else:
+ name = text
+ if name != window.editor.buffer.name:
+ text = window.editor.buffer.name
+ if window.editor.buffer.hasChanged():
+ if text.endswith(changed):
+ text = None
+ elif text.endswith(unchanged):
+ text = text[:-size] + changed
+ else:
+ text += changed
+ else:
+ if text.endswith(changed):
+ text = text[:-size] + unchanged
+ elif text.endswith(unchanged):
+ text = None
+ else:
+ text += unchanged
+ if text is not None:
+ self.SetPageText(selection, text)
+ self.Refresh() # Needed on Win98.
+
+ def OnPageChanging(self, event):
+ """Page changing event handler."""
+ event.Skip()
+
+ def OnPageChanged(self, event):
+ """Page changed event handler."""
+ new = event.GetSelection()
+ window = self.GetPage(new)
+ dispatcher.send(signal='EditorChange', sender=self,
+ editor=window.editor)
+ window.SetFocus()
+ event.Skip()
+
+
+class EditorShellNotebookFrame(EditorNotebookFrame):
+ """Frame containing a notebook containing EditorShellNotebooks."""
+
+ def __init__(self, parent=None, id=-1, title='PyAlaModeTest',
+ pos=wx.DefaultPosition, size=(600, 400),
+ style=wx.DEFAULT_FRAME_STYLE,
+ filename=None, singlefile=False):
+ """Create EditorShellNotebookFrame instance."""
+ self._singlefile = singlefile
+ EditorNotebookFrame.__init__(self, parent, id, title, pos,
+ size, style, filename)
+
+ def _setup(self):
+ """Setup prior to first buffer creation.
+
+ Called automatically by base class during init."""
+ if not self._singlefile:
+ self.notebook = EditorNotebook(parent=self)
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PyAlaModePlus'
+ text = 'Another fine, flaky program.'
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ def bufferCreate(self, filename=None):
+ """Create new buffer."""
+ if self._singlefile:
+ self.bufferDestroy()
+ notebook = EditorShellNotebook(parent=self,
+ filename=filename)
+ self.notebook = notebook
+ else:
+ notebook = EditorShellNotebook(parent=self.notebook,
+ filename=filename)
+ self.setEditor(notebook.editor)
+ if not self._singlefile:
+ self.notebook.AddPage(page=notebook, text=self.buffer.name,
+ select=True)
+ self.editor.setFocus()
+
+ def bufferDestroy(self):
+ """Destroy the current buffer."""
+ if self.buffer:
+ self.editor = None
+ del self.buffers[self.buffer.id]
+ self.buffer = None # Do this before DeletePage().
+ if self._singlefile:
+ self.notebook.Destroy()
+ self.notebook = None
+ else:
+ selection = self.notebook.GetSelection()
+## print "Destroy Selection:", selection
+ self.notebook.DeletePage(selection)
+
+ def bufferNew(self):
+ """Create new buffer."""
+ if self._singlefile and self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ self.bufferCreate()
+ cancel = False
+ return cancel
+
+ def bufferOpen(self):
+ """Open file in buffer."""
+ if self._singlefile and self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ if self._singlefile:
+ result = openSingle(directory=filedir)
+ if result.path:
+ self.bufferCreate(result.path)
+ else:
+ result = openMultiple(directory=filedir)
+ for path in result.paths:
+ self.bufferCreate(path)
+ cancel = False
+ return cancel
+
+
+class EditorShellNotebook(wx.Notebook):
+ """A notebook containing an editor page and a shell page."""
+
+ def __init__(self, parent, filename=None):
+ """Create EditorShellNotebook instance."""
+ wx.Notebook.__init__(self, parent, id=-1)
+ usePanels = True
+ if usePanels:
+ editorparent = editorpanel = wx.Panel(self, -1)
+ shellparent = shellpanel = wx.Panel(self, -1)
+ else:
+ editorparent = self
+ shellparent = self
+ self.buffer = Buffer()
+ self.editor = Editor(parent=editorparent)
+ self.buffer.addEditor(self.editor)
+ self.buffer.open(filename)
+ self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
+ style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
+ self.buffer.interp.locals.clear()
+ if usePanels:
+ self.AddPage(page=editorpanel, text='Editor', select=True)
+ self.AddPage(page=shellpanel, text='Shell')
+ # Setup sizers
+ editorsizer = wx.BoxSizer(wx.VERTICAL)
+ editorsizer.Add(self.editor.window, 1, wx.EXPAND)
+ editorpanel.SetSizer(editorsizer)
+ editorpanel.SetAutoLayout(True)
+ shellsizer = wx.BoxSizer(wx.VERTICAL)
+ shellsizer.Add(self.shell, 1, wx.EXPAND)
+ shellpanel.SetSizer(shellsizer)
+ shellpanel.SetAutoLayout(True)
+ else:
+ self.AddPage(page=self.editor.window, text='Editor', select=True)
+ self.AddPage(page=self.shell, text='Shell')
+ self.editor.setFocus()
+ self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
+
+ def OnPageChanged(self, event):
+ """Page changed event handler."""
+ selection = event.GetSelection()
+ if selection == 0:
+ self.editor.setFocus()
+ else:
+ self.shell.SetFocus()
+ event.Skip()
+
+ def SetFocus(self):
+ wx.Notebook.SetFocus(self)
+ selection = self.GetSelection()
+ if selection == 0:
+ self.editor.setFocus()
+ else:
+ self.shell.SetFocus()
+
+
+class Editor:
+ """Editor having an EditWindow."""
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize,
+ style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
+ """Create Editor instance."""
+ self.window = EditWindow(self, parent, id, pos, size, style)
+ self.id = self.window.GetId()
+ self.buffer = None
+ # Assign handlers for keyboard events.
+ 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."""
+ self.buffer = buffer
+ self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
+ self.clearAll()
+ self.setText(text)
+ self.emptyUndoBuffer()
+ self.setSavePoint()
+
+ def destroy(self):
+ """Destroy all editor objects."""
+ self.window.Destroy()
+
+ def clearAll(self):
+ self.window.ClearAll()
+
+ def emptyUndoBuffer(self):
+ self.window.EmptyUndoBuffer()
+
+ def getStatus(self):
+ """Return (filepath, line, column) status tuple."""
+ if self.window:
+ pos = self.window.GetCurrentPos()
+ line = self.window.LineFromPosition(pos) + 1
+ col = self.window.GetColumn(pos)
+ if self.buffer:
+ name = self.buffer.doc.filepath or self.buffer.name
+ else:
+ name = ''
+ status = (name, line, col)
+ return status
+ else:
+ return ('', 0, 0)
+
+ def getText(self):
+ """Return contents of editor."""
+ return self.window.GetText()
+
+ def hasChanged(self):
+ """Return True if contents have changed."""
+ return self.window.GetModify()
+
+ def setFocus(self):
+ """Set the input focus to the editor window."""
+ self.window.SetFocus()
+
+ def setSavePoint(self):
+ self.window.SetSavePoint()
+
+ def setText(self, text):
+ """Set contents of editor."""
+ self.window.SetText(text)
+
+ def OnChar(self, event):
+ """Keypress event handler.
+
+ Only receives an event if OnKeyDown calls event.Skip() for the
+ corresponding event."""
+
+ key = event.GetKeyCode()
+ if key in self.autoCompleteKeys:
+ # Usually the dot (period) key activates auto completion.
+ if self.window.AutoCompActive():
+ self.window.AutoCompCancel()
+ self.window.ReplaceSelection('')
+ self.window.AddText(chr(key))
+ text, pos = self.window.GetCurLine()
+ text = text[:pos]
+ if self.window.autoComplete:
+ self.autoCompleteShow(text)
+ elif key == ord('('):
+ # The left paren activates a call tip and cancels an
+ # active auto completion.
+ if self.window.AutoCompActive():
+ self.window.AutoCompCancel()
+ self.window.ReplaceSelection('')
+ self.window.AddText('(')
+ text, pos = self.window.GetCurLine()
+ text = text[:pos]
+ self.autoCallTipShow(text)
+ else:
+ # Allow the normal event handling to take place.
+ event.Skip()
+
+ def OnKeyDown(self, event):
+ """Key down event handler."""
+
+ key = event.GetKeyCode()
+ # If the auto-complete window is up let it do its thing.
+ if self.window.AutoCompActive():
+ event.Skip()
+ return
+ controlDown = event.ControlDown()
+ altDown = event.AltDown()
+ shiftDown = event.ShiftDown()
+ # Let Ctrl-Alt-* get handled normally.
+ if controlDown and altDown:
+ event.Skip()
+ # Increase font size.
+ elif controlDown and key in (ord(']'),):
+ dispatcher.send(signal='FontIncrease')
+ # Decrease font size.
+ elif controlDown and key in (ord('['),):
+ dispatcher.send(signal='FontDecrease')
+ # Default font size.
+ elif controlDown and key in (ord('='),):
+ dispatcher.send(signal='FontDefault')
+ else:
+ event.Skip()
+
+ def autoCompleteShow(self, command):
+ """Display auto-completion popup list."""
+ list = self.buffer.interp.getAutoCompleteList(command,
+ includeMagic=self.window.autoCompleteIncludeMagic,
+ includeSingle=self.window.autoCompleteIncludeSingle,
+ includeDouble=self.window.autoCompleteIncludeDouble)
+ if list:
+ options = ' '.join(list)
+ offset = 0
+ self.window.AutoCompShow(offset, options)
+
+ def autoCallTipShow(self, command):
+ """Display argument spec and docstring in a popup window."""
+ if self.window.CallTipActive():
+ self.window.CallTipCancel()
+ (name, argspec, tip) = self.buffer.interp.getCallTip(command)
+ if tip:
+ dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
+ if not self.window.autoCallTip:
+ return
+ startpos = self.window.GetCurrentPos()
+ if argspec:
+ self.window.AddText(argspec + ')')
+ endpos = self.window.GetCurrentPos()
+ self.window.SetSelection(startpos, endpos)
+ if tip:
+ tippos = startpos - (len(name) + 1)
+ fallback = startpos - self.GetColumn(startpos)
+ # In case there isn't enough room, only go back to the
+ # fallback.
+ tippos = max(tippos, fallback)
+ self.CallTipShow(tippos, tip)
+
+
+class EditWindow(editwindow.EditWindow):
+ """EditWindow based on StyledTextCtrl."""
+
+ def __init__(self, editor, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize,
+ style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
+ """Create EditWindow instance."""
+ editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
+ self.editor = editor
+
+
+class DialogResults:
+ """DialogResults class."""
+
+ def __init__(self, returned):
+ """Create wrapper for results returned by dialog."""
+ self.returned = returned
+ self.positive = returned in (wx.ID_OK, wx.ID_YES)
+ self.text = self._asString()
+
+
+ def __repr__(self):
+ return str(self.__dict__)
+
+ def _asString(self):
+ returned = self.returned
+ if returned == wx.ID_OK:
+ return "Ok"
+ elif returned == wx.ID_CANCEL:
+ return "Cancel"
+ elif returned == wx.ID_YES:
+ return "Yes"
+ elif returned == wx.ID_NO:
+ return "No"
+
+
+def fileDialog(parent=None, title='Open', directory='', filename='',
+ wildcard='All Files (*.*)|*.*',
+ style=wx.OPEN | wx.MULTIPLE):
+ """File dialog wrapper function."""
+ dialog = wx.FileDialog(parent, title, directory, filename,
+ wildcard, style)
+ result = DialogResults(dialog.ShowModal())
+ if result.positive:
+ result.paths = dialog.GetPaths()
+ else:
+ result.paths = []
+ dialog.Destroy()
+ return result
+
+
+def openSingle(parent=None, title='Open', directory='', filename='',
+ wildcard='All Files (*.*)|*.*', style=wx.OPEN):
+ """File dialog wrapper function."""
+ dialog = wx.FileDialog(parent, title, directory, filename,
+ wildcard, style)
+ result = DialogResults(dialog.ShowModal())
+ if result.positive:
+ result.path = dialog.GetPath()
+ else:
+ result.path = None
+ dialog.Destroy()
+ return result
+
+
+def openMultiple(parent=None, title='Open', directory='', filename='',
+ wildcard='All Files (*.*)|*.*',
+ style=wx.OPEN | wx.MULTIPLE):
+ """File dialog wrapper function."""
+ return fileDialog(parent, title, directory, filename, wildcard, style)
+
+
+def saveSingle(parent=None, title='Save', directory='', filename='',
+ wildcard='All Files (*.*)|*.*',
+ style=wx.SAVE | wx.OVERWRITE_PROMPT):
+ """File dialog wrapper function."""
+ dialog = wx.FileDialog(parent, title, directory, filename,
+ wildcard, style)
+ result = DialogResults(dialog.ShowModal())
+ if result.positive:
+ result.path = dialog.GetPath()
+ else:
+ result.path = None
+ dialog.Destroy()
+ return result
+
+
+def directory(parent=None, message='Choose a directory', path='', style=0,
+ pos=wx.DefaultPosition, size=wx.DefaultSize):
+ """Dir dialog wrapper function."""
+ dialog = wx.DirDialog(parent, message, path, style, pos, size)
+ result = DialogResults(dialog.ShowModal())
+ if result.positive:
+ result.path = dialog.GetPath()
+ else:
+ result.path = None
+ dialog.Destroy()
+ return result
+
+
+def messageDialog(parent=None, message='', title='Message box',
+ style=wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION,
+ pos=wx.DefaultPosition):
+ """Message dialog wrapper function."""
+ dialog = wx.MessageDialog(parent, message, title, style, pos)
+ result = DialogResults(dialog.ShowModal())
+ dialog.Destroy()
+ return result
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editwindow.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editwindow.py
new file mode 100644
index 0000000..dadd003
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/editwindow.py
@@ -0,0 +1,297 @@
+"""EditWindow class."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import stc
+
+import keyword
+import os
+import sys
+import time
+
+import dispatcher
+from version import VERSION
+
+
+if 'wxMSW' in wx.PlatformInfo:
+ FACES = { 'times' : 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Arial',
+ 'lucida' : 'Lucida Console',
+ 'other' : 'Comic Sans MS',
+ 'size' : 10,
+ 'lnsize' : 8,
+ 'backcol' : '#FFFFFF',
+ 'calltipbg' : '#FFFFB8',
+ 'calltipfg' : '#404040',
+ }
+
+elif 'wxGTK' in wx.PlatformInfo and ('gtk2' in wx.PlatformInfo or
+ 'gtk3' in wx.PlatformInfo):
+ FACES = { 'times' : 'Serif',
+ 'mono' : 'Monospace',
+ 'helv' : 'Sans',
+ 'other' : 'new century schoolbook',
+ 'size' : 10,
+ 'lnsize' : 9,
+ 'backcol' : '#FFFFFF',
+ 'calltipbg' : '#FFFFB8',
+ 'calltipfg' : '#404040',
+ }
+
+elif 'wxMac' in wx.PlatformInfo:
+ FACES = { 'times' : 'Lucida Grande',
+ 'mono' : 'Monaco',
+ 'helv' : 'Geneva',
+ 'other' : 'new century schoolbook',
+ 'size' : 12,
+ 'lnsize' : 10,
+ 'backcol' : '#FFFFFF',
+ 'calltipbg' : '#FFFFB8',
+ 'calltipfg' : '#404040',
+ }
+
+else: # GTK1, etc.
+ FACES = { 'times' : 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other' : 'new century schoolbook',
+ 'size' : 12,
+ 'lnsize' : 10,
+ 'backcol' : '#FFFFFF',
+ 'calltipbg' : '#FFFFB8',
+ 'calltipfg' : '#404040',
+ }
+
+
+class EditWindow(stc.StyledTextCtrl):
+ """EditWindow based on StyledTextCtrl."""
+
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
+ """Create EditWindow instance."""
+ stc.StyledTextCtrl.__init__(self, parent, id, pos, size, style)
+ self.__config()
+ stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI)
+ dispatcher.connect(receiver=self._fontsizer, signal='FontIncrease')
+ dispatcher.connect(receiver=self._fontsizer, signal='FontDecrease')
+ dispatcher.connect(receiver=self._fontsizer, signal='FontDefault')
+
+ def _fontsizer(self, signal):
+ """Receiver for Font* signals."""
+ size = self.GetZoom()
+ if signal == 'FontIncrease':
+ size += 1
+ elif signal == 'FontDecrease':
+ size -= 1
+ elif signal == 'FontDefault':
+ size = 0
+ self.SetZoom(size)
+
+
+ def __config(self):
+ self.setDisplayLineNumbers(False)
+
+ self.SetLexer(stc.STC_LEX_PYTHON)
+ self.SetKeyWords(0, ' '.join(keyword.kwlist))
+
+ self.setStyles(FACES)
+ self.SetViewWhiteSpace(False)
+ self.SetTabWidth(4)
+ self.SetUseTabs(False)
+ # Do we want to automatically pop up command completion options?
+ self.autoComplete = True
+ self.autoCompleteIncludeMagic = True
+ self.autoCompleteIncludeSingle = True
+ self.autoCompleteIncludeDouble = True
+ self.autoCompleteCaseInsensitive = True
+ self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+ self.autoCompleteAutoHide = False
+ self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
+ 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)
+ try:
+ self.SetEndAtLastLine(False)
+ 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."""
+
+ # Default style
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
+ "face:%(mono)s,size:%(size)d,back:%(backcol)s" % \
+ faces)
+
+ self.StyleClearAll()
+ self.SetSelForeground(True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT))
+ self.SetSelBackground(True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+
+ # Built in styles
+ self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,
+ "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,
+ "fore:#0000FF,back:#FFFF88")
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
+ "fore:#FF0000,back:#FFFF88")
+
+ # Python styles
+ self.StyleSetSpec(stc.STC_P_DEFAULT,
+ "face:%(mono)s" % faces)
+ self.StyleSetSpec(stc.STC_P_COMMENTLINE,
+ "fore:#007F00,face:%(mono)s" % faces)
+ self.StyleSetSpec(stc.STC_P_NUMBER,
+ "")
+ self.StyleSetSpec(stc.STC_P_STRING,
+ "fore:#7F007F,face:%(mono)s" % faces)
+ self.StyleSetSpec(stc.STC_P_CHARACTER,
+ "fore:#7F007F,face:%(mono)s" % faces)
+ self.StyleSetSpec(stc.STC_P_WORD,
+ "fore:#00007F,bold")
+ self.StyleSetSpec(stc.STC_P_TRIPLE,
+ "fore:#7F0000")
+ self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE,
+ "fore:#000033,back:#FFFFE8")
+ self.StyleSetSpec(stc.STC_P_CLASSNAME,
+ "fore:#0000FF,bold")
+ self.StyleSetSpec(stc.STC_P_DEFNAME,
+ "fore:#007F7F,bold")
+ self.StyleSetSpec(stc.STC_P_OPERATOR,
+ "")
+ self.StyleSetSpec(stc.STC_P_IDENTIFIER,
+ "")
+ self.StyleSetSpec(stc.STC_P_COMMENTBLOCK,
+ "fore:#7F7F7F")
+ self.StyleSetSpec(stc.STC_P_STRINGEOL,
+ "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
+
+ def OnUpdateUI(self, event):
+ """Check for matching braces."""
+ # If the auto-complete window is up let it do its thing.
+ if self.AutoCompActive() or self.CallTipActive():
+ return
+ braceAtCaret = -1
+ braceOpposite = -1
+ charBefore = None
+ caretPos = self.GetCurrentPos()
+ if caretPos > 0:
+ charBefore = self.GetCharAt(caretPos - 1)
+ styleBefore = self.GetStyleAt(caretPos - 1)
+
+ # Check before.
+ if charBefore and chr(charBefore) in '[]{}()' \
+ and styleBefore == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos - 1
+
+ # Check after.
+ if braceAtCaret < 0:
+ charAfter = self.GetCharAt(caretPos)
+ styleAfter = self.GetStyleAt(caretPos)
+ if charAfter and chr(charAfter) in '[]{}()' \
+ and styleAfter == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos
+
+ if braceAtCaret >= 0:
+ braceOpposite = self.BraceMatch(braceAtCaret)
+
+ if braceAtCaret != -1 and braceOpposite == -1:
+ self.BraceBadLight(braceAtCaret)
+ else:
+ self.BraceHighlight(braceAtCaret, braceOpposite)
+
+ def CanCopy(self):
+ """Return True if text is selected and can be copied."""
+ return self.GetSelectionStart() != self.GetSelectionEnd()
+
+ def CanCut(self):
+ """Return True if text is selected and can be cut."""
+ return self.CanCopy() and self.CanEdit()
+
+ def CanEdit(self):
+ """Return True if editing should succeed."""
+ return not self.GetReadOnly()
+
+ 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 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) != 0
+ end = self.GetLastPosition()
+ # Changed to reflect the fact that StyledTextControl is in UTF-8 encoding
+ textstring = self.GetRange(0, end).encode('utf-8')
+ findstring = findData.GetFindString().encode('utf-8')
+ if not matchcase:
+ textstring = textstring.lower()
+ findstring = 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))
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/filling.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/filling.py
new file mode 100644
index 0000000..4ffe662
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/filling.py
@@ -0,0 +1,360 @@
+"""Filling is the gui tree control through which a user can navigate
+the local namespace or any object."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+
+import dispatcher
+import editwindow
+import inspect
+import introspect
+import keyword
+import sys
+import types
+from version import VERSION
+
+
+COMMONTYPES = [getattr(types, t) for t in dir(types) \
+ if not t.startswith('_') \
+ and t not in ('ClassType', 'InstanceType', 'ModuleType')]
+
+DOCTYPES = ('BuiltinFunctionType', 'BuiltinMethodType', 'ClassType',
+ 'FunctionType', 'GeneratorType', 'InstanceType',
+ 'LambdaType', 'MethodType', 'ModuleType',
+ 'UnboundMethodType', 'method-wrapper')
+
+SIMPLETYPES = [getattr(types, t) for t in dir(types) \
+ if not t.startswith('_') and t not in DOCTYPES]
+
+del t
+
+try:
+ COMMONTYPES.append(type(''.__repr__)) # Method-wrapper in version 2.2.x.
+except AttributeError:
+ pass
+
+
+class FillingTree(wx.TreeCtrl):
+ """FillingTree based on TreeCtrl."""
+
+ name = 'Filling Tree'
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE,
+ rootObject=None, rootLabel=None, rootIsNamespace=False,
+ static=False):
+ """Create FillingTree instance."""
+ wx.TreeCtrl.__init__(self, parent, id, pos, size, style)
+ self.rootIsNamespace = rootIsNamespace
+ import __main__
+ if rootObject is None:
+ rootObject = __main__.__dict__
+ self.rootIsNamespace = True
+ if rootObject is __main__.__dict__ and rootLabel is None:
+ rootLabel = 'locals()'
+ if not rootLabel:
+ rootLabel = 'Ingredients'
+ rootData = wx.TreeItemData(rootObject)
+ self.item = self.root = self.AddRoot(rootLabel, -1, -1, rootData)
+ self.SetItemHasChildren(self.root, self.objHasChildren(rootObject))
+ 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')
+
+ def push(self, command, more):
+ """Receiver for Interpreter.push signal."""
+ self.display()
+
+ def OnItemExpanding(self, event):
+ """Add children to the item."""
+ busy = wx.BusyCursor()
+ item = event.GetItem()
+ if self.IsExpanded(item):
+ return
+ self.addChildren(item)
+# self.SelectItem(item)
+
+ def OnItemCollapsed(self, event):
+ """Remove all children from the item."""
+ busy = wx.BusyCursor()
+ item = event.GetItem()
+# self.CollapseAndReset(item)
+# self.DeleteChildren(item)
+# self.SelectItem(item)
+
+ def OnSelChanged(self, event):
+ """Display information about the item."""
+ busy = wx.BusyCursor()
+ self.item = event.GetItem()
+ self.display()
+
+ def OnItemActivated(self, event):
+ """Launch a DirFrame."""
+ item = event.GetItem()
+ text = self.getFullName(item)
+ obj = self.GetPyData(item)
+ frame = FillingFrame(parent=self, size=(600, 100), rootObject=obj,
+ rootLabel=text, rootIsNamespace=False)
+ frame.Show()
+
+ def objHasChildren(self, obj):
+ """Return true if object has children."""
+ if self.objGetChildren(obj):
+ return True
+ else:
+ return False
+
+ def objGetChildren(self, obj):
+ """Return dictionary with attributes or contents of object."""
+ busy = wx.BusyCursor()
+ otype = type(obj)
+ if otype is types.DictType \
+ or str(otype)[17:23] == 'BTrees' and hasattr(obj, 'keys'):
+ return obj
+ d = {}
+ if otype is types.ListType or otype is types.TupleType:
+ for n in range(len(obj)):
+ key = '[' + str(n) + ']'
+ d[key] = obj[n]
+ if otype not in COMMONTYPES:
+ for key in introspect.getAttributeNames(obj):
+ # Believe it or not, some attributes can disappear,
+ # such as the exc_traceback attribute of the sys
+ # module. So this is nested in a try block.
+ try:
+ d[key] = getattr(obj, key)
+ except:
+ pass
+ return d
+
+ def addChildren(self, item):
+ self.DeleteChildren(item)
+ obj = self.GetPyData(item)
+ children = self.objGetChildren(obj)
+ if not children:
+ return
+ keys = children.keys()
+ keys.sort(lambda x, y: cmp(str(x).lower(), str(y).lower()))
+ for key in keys:
+ itemtext = str(key)
+ # Show string dictionary items with single quotes, except
+ # for the first level of items, if they represent a
+ # namespace.
+ if type(obj) is types.DictType \
+ and type(key) is types.StringType \
+ and (item != self.root \
+ or (item == self.root and not self.rootIsNamespace)):
+ itemtext = repr(key)
+ child = children[key]
+ data = wx.TreeItemData(child)
+ branch = self.AppendItem(parent=item, text=itemtext, data=data)
+ self.SetItemHasChildren(branch, self.objHasChildren(child))
+
+ def display(self):
+ item = self.item
+ if not item:
+ return
+ if self.IsExpanded(item):
+ self.addChildren(item)
+ self.setText('')
+ obj = self.GetPyData(item)
+ if wx.Platform == '__WXMSW__':
+ if obj is None: # Windows bug fix.
+ return
+ self.SetItemHasChildren(item, self.objHasChildren(obj))
+ otype = type(obj)
+ text = ''
+ text += self.getFullName(item)
+ text += '\n\nType: ' + str(otype)
+ try:
+ value = str(obj)
+ except:
+ value = ''
+ if otype is types.StringType or otype is types.UnicodeType:
+ value = repr(obj)
+ text += u'\n\nValue: ' + value
+ if otype not in SIMPLETYPES:
+ try:
+ text += '\n\nDocstring:\n\n"""' + \
+ inspect.getdoc(obj).strip() + '"""'
+ except:
+ pass
+ if otype is types.InstanceType:
+ try:
+ text += '\n\nClass Definition:\n\n' + \
+ inspect.getsource(obj.__class__)
+ except:
+ pass
+ else:
+ try:
+ text += '\n\nSource Code:\n\n' + \
+ inspect.getsource(obj)
+ except:
+ pass
+ self.setText(text)
+
+ def getFullName(self, item, partial=''):
+ """Return a syntactically proper name for item."""
+ name = self.GetItemText(item)
+ parent = None
+ obj = None
+ if item != self.root:
+ parent = self.GetItemParent(item)
+ obj = self.GetPyData(parent)
+ # Apply dictionary syntax to dictionary items, except the root
+ # and first level children of a namepace.
+ if (type(obj) is types.DictType \
+ or str(type(obj))[17:23] == 'BTrees' \
+ and hasattr(obj, 'keys')) \
+ and ((item != self.root and parent != self.root) \
+ or (parent == self.root and not self.rootIsNamespace)):
+ name = '[' + name + ']'
+ # Apply dot syntax to multipart names.
+ if partial:
+ if partial[0] == '[':
+ name += partial
+ else:
+ name += '.' + partial
+ # Repeat for everything but the root item
+ # and first level children of a namespace.
+ if (item != self.root and parent != self.root) \
+ or (parent == self.root and not self.rootIsNamespace):
+ name = self.getFullName(parent, partial=name)
+ return name
+
+ def setText(self, text):
+ """Display information about the current selection."""
+
+ # This method will likely be replaced by the enclosing app to
+ # do something more interesting, like write to a text control.
+ print text
+
+ def setStatusText(self, text):
+ """Display status information."""
+
+ # This method will likely be replaced by the enclosing app to
+ # do something more interesting, like write to a status bar.
+ print text
+
+
+class FillingText(editwindow.EditWindow):
+ """FillingText based on StyledTextCtrl."""
+
+ name = 'Filling Text'
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
+ static=False):
+ """Create FillingText instance."""
+ editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
+ # Configure various defaults and user preferences.
+ self.SetReadOnly(True)
+ self.SetWrapMode(True)
+ self.SetMarginWidth(1, 0)
+ if not static:
+ dispatcher.connect(receiver=self.push, signal='Interpreter.push')
+
+ def push(self, command, more):
+ """Receiver for Interpreter.push signal."""
+ self.Refresh()
+
+ def SetText(self, *args, **kwds):
+ self.SetReadOnly(False)
+ editwindow.EditWindow.SetText(self, *args, **kwds)
+ self.SetReadOnly(True)
+
+
+class Filling(wx.SplitterWindow):
+ """Filling based on wxSplitterWindow."""
+
+ name = 'Filling'
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ 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)
+
+ 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.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 strangely
+ #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."""
+
+ name = 'Filling Frame'
+ revision = __revision__
+
+ def __init__(self, parent=None, id=-1, title='PyFilling',
+ pos=wx.DefaultPosition, size=(600, 400),
+ style=wx.DEFAULT_FRAME_STYLE, rootObject=None,
+ rootLabel=None, rootIsNamespace=False, static=False):
+ """Create FillingFrame instance."""
+ wx.Frame.__init__(self, parent, id, title, pos, size, style)
+ intro = 'PyFilling - The Tastiest Namespace Inspector'
+ self.CreateStatusBar()
+ self.SetStatusText(intro)
+ import images
+ self.SetIcon(images.getPyIcon())
+ self.filling = Filling(parent=self, rootObject=rootObject,
+ rootLabel=rootLabel,
+ rootIsNamespace=rootIsNamespace,
+ static=static)
+ # Override so that status messages go to the status bar.
+ self.filling.tree.setStatusText = self.SetStatusText
+
+
+class App(wx.App):
+ """PyFilling standalone application."""
+
+ def OnInit(self):
+ wx.InitAllImageHandlers()
+ self.fillingFrame = FillingFrame()
+ self.fillingFrame.Show(True)
+ self.SetTopWindow(self.fillingFrame)
+ return True
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/frame.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/frame.py
new file mode 100644
index 0000000..2bece97
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/frame.py
@@ -0,0 +1,984 @@
+"""Base frame with menu."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+import os
+from version import VERSION
+import editwindow
+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.NewId()
+ID_ABOUT = wx.ID_ABOUT
+ID_HELP = wx.NewId()
+ID_AUTOCOMP = wx.NewId()
+ID_AUTOCOMP_SHOW = wx.NewId()
+ID_AUTOCOMP_MAGIC = wx.NewId()
+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_SHOW_LINENUMBERS = wx.NewId()
+ID_ENABLESHELLMODE = wx.NewId()
+ID_ENABLEAUTOSYMPY = wx.NewId()
+ID_AUTO_SAVESETTINGS = wx.NewId()
+ID_SAVEACOPY = wx.NewId()
+ID_SAVEHISTORY = wx.NewId()
+ID_SAVEHISTORYNOW = wx.NewId()
+ID_CLEARHISTORY = wx.NewId()
+ID_SAVESETTINGS = wx.NewId()
+ID_DELSETTINGSFILE = wx.NewId()
+ID_EDITSTARTUPSCRIPT = wx.NewId()
+ID_EXECSTARTUPSCRIPT = wx.NewId()
+ID_SHOWPYSLICESTUTORIAL = wx.NewId()
+ID_STARTUP = wx.NewId()
+ID_SETTINGS = wx.NewId()
+ID_FIND = wx.ID_FIND
+ID_FINDNEXT = wx.NewId()
+ID_FINDPREVIOUS = wx.NewId()
+ID_SHOWTOOLS = wx.NewId()
+ID_HIDEFOLDINGMARGIN = wx.NewId()
+
+
+
+class Frame(wx.Frame):
+ """Frame with standard menu items."""
+
+ revision = __revision__
+
+ 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
+ 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.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')
+ 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.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu,
+ 'Auto Completion Options')
+ m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu,
+ '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.AppendMenu(-1, "&History", self.historyMenu, "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.AppendMenu(ID_STARTUP, '&Startup', self.startupMenu, '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.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')
+
+ 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.FutureCall(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.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.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:
+ name = os.path.join(self.dataDir, 'history')
+ f = file(name, 'w')
+ hist = []
+ enc = wx.GetDefaultPyEncoding()
+ for h in self.shell.history:
+ if isinstance(h, unicode):
+ h = h.encode(enc)
+ hist.append(h)
+ hist = '\x00\n'.join(hist)
+ f.write(hist)
+ f.close()
+ 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:
+ f = file(name, 'U')
+ hist = f.read()
+ f.close()
+ self.shell.history = hist.split('\x00\n')
+ dispatcher.send(signal="Shell.loadHistory",
+ history=self.shell.history)
+ except:
+ 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:
+ 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|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()
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/images.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/images.py
new file mode 100644
index 0000000..f3cb5a1
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/images.py
@@ -0,0 +1,215 @@
+"""Support for icons."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com> / David Mashburn <david.n.mashburn@gmail.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+import cStringIO
+
+
+def getPyIcon(shellName='PyCrust'):
+ icon = wx.EmptyIcon()
+ icon.CopyFromBitmap(getPyBitmap(shellName))
+ return icon
+
+def getPyBitmap(shellName='PyCrust'):
+ return wx.BitmapFromImage(getPyImage(shellName))
+
+def getPyImage(shellName='PyCrust'):
+ stream = cStringIO.StringIO(getPyData(shellName))
+ return wx.ImageFromStream(stream)
+
+def getPyData(shellName='PyCrust'):
+ if shellName=='PyCrust':
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
+\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\
+\x95IDATx\x9c\xed\x97?lSG\x1c\xc7?\x97\x98\xd8Q\xa3\xdeY\xa2j\x06\xa4\xf7"QJ\
+\xbb<3@\x01\xa9\xc2\x0c\xa8!\x1d\x1c6\xcaB\xa8D[uI2\xf4\x8f\xe8\x103\xb4\xa2\
+,5\x0b\x03\x032C\xab\xc0\x92dh:t\xc0)*E\xcd@<Q\x01Rl\t\xd4D\xaa\xe4{R\xd0{&\
+\xa5\xd7\xe1\xfc\xec\xe7\xfciR\x08e\xe9O\xb2\xee|\xfe\xbd\xfb}~\xdf\xdf\xbd\
+\xbb\xb3PJ\xf1"\xad\xe3\x85F\xff\x1f\xe0y\x03h\xad\xcdA\xc7~\xb4\xd6f-\x9f\
+\xc4\xf3\x0c>Y\x1c#\x97\xddCUk\xf4B\x8d3\x9f\x8d\x9a\x9bU%\xe2~b\xab\xdf\x82\
+\x83N+\xd3\xe92\\\x1f\xcf\x93\xdd\x9f\xa1\xaa5\x95\xf9\n\xe7\xf3y\xe2\x10[V\
+\x82H\xe6\xd3G\x1dN\xf7\xc3\xa7\xc7a\xc0\x83\xc3\xc7\xf3\xcc\xcc\xcd\xe3(\
+\x85\xdb\xe7\xf2\xc9\xe8X\x1b\xe43+\x10\xd5\xb6\x94\x87Z\xe8\x90NU\x91I@\x00\
+\x06\xbe\x18\xb7J\x98\xca$`\x98\xb9]&{,\x8fRV\x85\xa7V@k\x9bq)o\x83+\t\xe9T\
+\xd5f\x95\x02\x91\xb4~_\r\xd9\xb6\xbaP\x03\x04n\x9f\xcbDa\xb8\t\xfe\xaf\x17a\
+<\xe3\xc8\x94lo\x9b\xd6\xa8\xf4\x80\x07\xb7o\xcd\xe0\x0c\x0e\xa2R\x8a\xb4\
+\x93n\xbal\x1a`e\xe0U\xc1\xd6\xb0\xb8\n\x99\x91"\x93\xaf\xba\xe4\x0ed\xda|6,\
+\x81\xd6\xda\x9c|\xab]\xea\xcd\x04\x8f\x9b\t\xad\nz\xa1\x02\x80\xdb\xe7R\x1a\
+\xcf\xa3\xb56\xeb\x02D5\x9e\xf8\xdc\xe1T\xff\xd3\x05\x8e\x82\x83U\xe1Z\xb1\
+\x18\x9b\xbf\x06\xacQ\x82H\xea\x01/Z@Ut\x08R\xb4$}\x16\xd3\x81A&%\xde\xee\
+\xbev\x80x\xe0]{\xb2\x1cR\xa5\xe6C*\xb5\xf1\xc4Q\xa6"e\xfbQ\x1b\x8dE\xe6\x87\
+>\xaa[Q\xadi\x0b\xb0r\x8f\x9e.\xc3t\xb9\xc4]\xaf5\xf6\xfe\xdb\xddt&\x02\xfa\
+\x9c\xf5\x01\xe2A\xa2\xbeX\x01>]ntR\x12\xe3[\x00\x01\x98\x89\x11[_\xed\xafn\
+\xab\x81U\xa0\xe7I7\x00\x97o\x04\xcd\x89\x06<;\xe9\x80\x07]i\x97\xc17\x1f\
+\xd2\xd3\x91`\xe9\xaf?\x01p^Y\x06Z\n\xfau8?a\xfb]i\x97\xec\xa1\x8c\x05(|\xd8\
+N\xba\xb3\xab\x87\xfb\x8f\x97\xd8\xd9\xd5\x03\xc0\xfd\xc7K\xec\xd8\xd6\xdd\
+\xfc\xfd\xc1r\xd0\xf4\x01\xda~\x03H\xf4\x04\xd4j :\xb75\xc7\xae\xfd\xbcLW\
+\xda\xa5\xf0M\x1e\t\xcc\xcc\xcdq\xa9P@\x8c\xf5fL\xdaHF\x16g\x9a\x19\xad\xcc\
+\xee\xcb\xa3\n\xad\xa1\xda\xf1\x08\xef\xe5\x97x\xf8\xc8f\xf8\xc7\x93:\xdb;\
+\x93M\xc8\x08j\xc7\xb6n\x1e,\x07m`\x97o\x04|;>\xd1T\xc4\x17\x8a\x13\xb9\xc3\
+\x88\x01\x0fs\xa4\x9cc}\xf3A\x190\x82\x1f\xddR{-\x1bV\xfc\xd8f\xba\xbd3\xd9\
+\x06\x15\x07\xbb\xf8\xd3\x12\xdf]-"\x93\xb2\xb1C*\xde\xcd\x1d\xde\xccN(\xc1\
+\xae\x17"\xd0#+<j\x17m{\xcd\x9bj\x00.\xaf\xf0Xb\xb8\xdfA\xa6\x14\x18\x03\x06\
+\xb4o\xcf\x8d\xc4\xbervc\x86M\xdaz\x80\x00\x95T\x19?\xd0 @&%~c\xbc\xe3W\xaf\
+\xb4e\x00\xffh\xc6@\xbd\x11\xbc\xde\x1a\xfe\xef.\xa5\xa2q4\n0\x81\xad\xe9\
+\xae7<\x12\xaf\xf5\xc2hy\xaa\xe97\x9cS\\\x98\xb2\x0e\x03\xb1\xcdhW\xdaC\x1a\
+\xa0\xa2\xa0\x0e"\x14`\xb0Y\x85\x1b\x1f\x12\xaa7\x03)\xd9\x84\xa8\xccW\xb8{\
+\xa7L\xe2\xde\x02\x94\xc6Gp_\xcf\x80\x90\x98\xd0g\xf4\xac\x82Pc\x82\x1a\xd5\
+\x10\x08}&\xa7J\xcc\xde.1]m\x80\xf6+\xee\xfd\xae\x9bo\xc4\xf0;\x80\xef\x90\
+\x0e\x04\x06`Q!\x02\x05\xc2 \xb5\xc2\x95\x15d\xb4C&[\xf7\xd2\x04\x80\xbb\xdb\
+\x9e\xd1\x8e\x02\x90\xd8\xd4$ I\x87\x80\xf1\xf1\xdc!4\xc3\x88\x94}\xd8,TH\
+\xbb.5m\xf0C\x9f3\x1f\r\x01\x96.\x82\x1a9\xe9Q\xb8\xd2\xf8\xf25\x0c\xbe\xe7#\
+\x92\x12\x1d[\x03\t\x00E\xf4\xa6\t\xaaZ7`$\x18\x90\xf8\xf8\x80JK\x94\xa1\x01\
+\x07\xb8\x0e~X\xc3\xed\x16\xf8)\xf8~j\x12B\rI\x89_\xf7!0 \x04\xf9Q\xc0\x18\
+\x0c\xd1i\xea\x13\xb7\x04\xc0\x89\x93C\xabj\xb6\xf7@\x96\xd9_J|0:\x86R\n\xb7\
+\xd7@\xaa%\x9d\xa3$\xba.\x90RA]\xe3\x87\x1a\x89\xdd\xefeR\xc2\x1a\'\xa8\x1f\
+\x82\x0e-@m\xd1\xde\x076\xbc\x15\x97~(\x9a\x89b\x9e\xd9[s\xab!\xf7g\xd6\x1c\
+\x8f\xdb\xbel\x8e\xa1S\xc7\xda\xc6\xe6\xee\xccs\xe9\xdcYnV\x95\xd8\xf2?&q+\
+\x9c\x1b1\xf3\xbf\xcd3{\xfdJ\xdb\xf8\xde\xfd\x19.\\\xad\x08\x80\xbf\x01\xd1\
+\x86\xfa\x8b\xc7\xc0\xc8\xb7\x00\x00\x00\x00IEND\xaeB`\x82'
+ elif shellName=='PySlices':
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\
+\x00szz\xf4\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\x06bKGD\x00\xff\
+\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\x00\x0b\
+\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xd8\n\x16\x03#\x0eV,\xc0?\x00\
+\x00\x06\xb8IDATX\xc3\xbd\x97\x7flS\xd7\x15\xc7?\xd7v\xe2\x17\x12x\xcf\x04X(\xb4\
+vT\n\x94L}\xde\xd6\x1f\x012\x91Pe\xd0LZ\x82\x80\xf2\xa3\x1a\t\xd2\xc6\xd0\xa4)\
+\xc9\xb4\x9f\x19\x1bN\xd6N\x1bRGZ\r\xb6vR\x15\xa6u\xb0I[b\x952\xf6C\xc2\xd01\xca\
+"Z\xa7\x82\xb2-lq\x10\xac\x89`\xf2{4\x89\xed8\xf1\xdd\x1f\xd7v\xe2\xfc\xa2H\xed\
+\x8ed\xbd\xfb\xae\xcf\xbd\xe7{\xce=\xdfs\xcf\x13\xcc,K\x97\x15\xf3\x9f#_\x04\xa3\
+\xd0Ar\\b\xc5\x04\xef\xf4\xbb\xa8*\x1b\xe7\xd0\xeb\xc5\xa9\x84X\xc4\xdem\x15\x94\
+,6p9\x1d\xa2x\xa1!*w>\x0b\xc0\xfaG\x1f>\xfa\xe7\xf3=G\xe2\xf1\xd1w\xb9\x8b\x88\x99\
+&\x1f{\x90\xe1\xf2\x95D?\xf7\x04K\x8cB\xf2\x1c\x0ep:@\x02\x89\xa4@\xcb\x93\x9c\xbc\
+\x94\xc7\xf9\xde"\xecQCn\xaaX!?\xfeP\tK\x97\xadHY\xc3Iy<x>\x15\xfc\xe3E\xc7\x9d\xf7\
+G6\x00\x17\xee\x15\x80o\xdf\x93\\\xae-\xc7Y\xe2A\x13\x0e@\x82\xc3\x91\xab4:\x06\xe3\
+)\xc1\xa0\r{\x8f\x14\x12\xb5\x87\xd8\xb3}\xe3\xf8W\xf7\xd5\x8e\xcf\x9b\xa7\xc5\xae\
+\xfc\xfbfd\xcb\xe7\xdbL`3\xf0\x87{\x01\xb0rc\x19\xe1gw\x93\xafi8\xa7\x1a\x9e,\xef\x8f\
+\xc0_\xae@b\x0c\xd6\xafv\xf2\xf4\x0b\x05D\xed!\xaew\xbf\xc2B\xbd\x88\xdb##\xf8\xfc\r\
+\x00\x07\x81\xb6\x0f\x04\xa0r\r\xe3\xa6\x8f\xe4\x9e\x8d\xe4;\x1c\x08!f\x07p\xee2|\xaa\
+\x14\x9c.\x88\xc7\xc1\x99\x0f\xd7n\xeb\x1c\xbb\xe8\xa5\xe5+;\xa8./\xa3\xdf\xb2x\xb7\
+\xe7_\xd4\xd4\x7f?\x04TM\xddc\x9a\x7f+\xefCT\x9bs\x1b\xbfz\x03~z\x1a\x8a\xe7\x83p\x80\
+\xe6\x06C\x87\xf9\x05\xf0\x89\xfbm\xda\xb7\xbd\xc3gv~\x87`\xe8m\xbc\x86\xc1\x1a\xf3A\
+\xc2\xa7\x0fW\xd6\x98\xc8\xbb\x02\xb0c\xe0\xce\x03)\xd5o&y\xeb\x1al}\x0c\x96\x190\xaf\
+`f\x9d\x1a\x13\xea\x1aZ\t\xbd\x19\xc6k\x18\x18%\x1e\xbe\x11\x080\x15\x84s\xf2\xcb\xaa\
+\xfb\x90;\xd6#|\x1fC\xb8\\\n@&\n\x89$<\xfa5\xb8u\x07\x9e\xa9\x00-\x0f\x16,\x98\xfdx\x9e\
+\xf4\xc3\xf5\x018p$DU\xe5\x13\x98\xbe\xa5\x88\x02\x8d5\xa5&\xb7\xfa\xce\x06z\x07i\x05pM^T\
+\xb1\x1a\xca\x1e\x80\xfc\xbc)Q\x19\x81\x17O\xc2\x1bm\x8a\x8a.\xd7\xec\x9e\x03\xc8\xb8\xca\
+\xae\xe7v\xa6\xf3\xaa\xae\x19\x19\xe9\xe2\xec\x990\xe1\x7f\xf4s\xaag\x86#x\xe6\xd3\xc8\xe5\
+\xc50\xcf\x9d\xceN1A\xbdC\x9d\xb0c-\x8c\xa7\xd4y\x17hw).\x1a\x087\xfc\xee-\xb0\x13j\xee\x97\
+\x9d!\xaa*L\x1a\xf7\xd7\xd2\xd9\xde\x88"\xf7\xa4\x08\xdc\xf8/|\xa1Z%\x95\x10*\xfc\xf6\x1d\
+\xa8\x0c@(\x00yy\xca\xb8\xd39\xb7\xf1_\x9c\x81\x01\x1b\x12\xa3p`+l]\x07-\x1dP$,\x84t\xe0\
+5t(\xf7g\xf5\xb3\x00\x16\xce\x87"\rR)H\x8e\xc3\xf3A\x05"\xf8Me\xd8\xe5\x9an\xfc\xf2ux\xf5\
+\x1c\xfc\xfe\x12|{+\xdc\xbf\x18\xf6TM\x07\xf5\x83\x06\xf07u\xd0u\xdc\xc7\xf2%~"\xef\xf5\
+\xe7\x1e\xc1S\x9fD.1\x94\x97c)\xd8\xdc\x06\x8f<\x00\r\x1b\xc0(\x84\x94T\x002\xf2\xbd\xe3\
+\xe0o\x86A\x0b\xea\xab\xe0\xe4\x01\xd8Q\x01\xebV\xcd\x9e\x135&X\x03\x11UjK}\x84N\x04\x00\
+\xa4\x0b@\xd7`\xd7Z\xa5\xfc\xd2i\x08~]\x8d\xc7Rp\xcb\x86\xfd?\x87M~\xe5qO\x04\xc2\x87\xa1\
+m\x17\x1fHd|"\n-\x1d\x1d\xd4o\xa9\x03\xc0\xb2\xa2\xea\x08\xb6\xaf\xa3\xfb\xc4_\xe1[\xdb\x95\
+W\xa1\x80Z\xb0\xed\xc7\xb0\xa1\x0c~{A\x19\xfc\xb0\xc4\x8aIt\xb7\x8e\xb9\xba4\x9d\x03)J\x1f\
+\xf1*\xe3Ue\xf0\xfck\xf0\xda\xa5\t\xa3\xdf}\xfa\xde<\x15\x9a\x1ag\x9e\x99\xb9,\xa5\xe36F\
+\x81A\x7f\xd4R\x00.\xf62\x1cKR\x0cp\xe6\xca\x84bK\xc7\xc48\xc3\xdb\xb9"1\xd9Hf,\xa6\xd05\
+\xcb\x7fMG\xdaV\xf62\x92\x9dM\xaa\x96[\xf6\xf4g\x7f\x0c\x0c\r\x8a\xc6\x0b\xd8\xf6\x93\x185\
+\xe6\xc4F\x99q\x8d\t\xf9\x1e\x1fuknR\xe4p1\x94\x1a\x03\xc0\xbb8\t\xa8\xf5\xa0j\xc2\xa1N5\
+\xce\xf7\xf8\xa8\xdc\xe0W\x00\xda\xbf\x94\x8btE~\x11\xd7F\x87X\x91_\x04\xc0\xb5\xd1!\x96\
+\xe7M\x94\xbe\x1b\xc9XV\x07\xc8\xf9\x0f\xc0U\x14#\x1a\x05\xe1\x9c(\xa9\xbf9\x9f$\xdf\xe3\
+\xa3\xfdp\x00\x1d8\x1b\x0e\xf3r{;\xe2`\x89_z\xa4N\xd3\xe0\xd9Y\xbd{\xee)\x03\xcb\x82~\xc70\
+\xe6\x82Bn\x0e+\x0fo\x8f\'X\xe4tgAf@-\xcf+\xe0F2\x96\x03\xec\x957b\xbcz\xa23\x1b\x11[\x18\
+\xec\xae\xadB\xd4\x98\xc8\xea\x9e\xda9\xd2\xcb\x06C\x82\x14\xfc\xc9\x17\xca=\xcb\xb4t|Yy\xba\
+\xc8\xe9\xce\x015\x19\xd8\xd1sC\xfc\xea\xd7\x1d\xe8n=\xdd\x85\x18|\xb6\xb6*\xf72\x9aYtP\
+\xf9B\x06h\xf5\x14\x8d\xe8\xd1t\x98\xcd`\x1a`r\x8a\xc6\x10\x8d\x9b\xbd\xe8\x9a\x91\xbe\xe7\
+\xc1\xb2U5t=\xdeS\xf9\xa1q|6\x80\x00\x11\xad\x07;f\x81\x00\xdd\xadcgJ\xf1\xdf\xcc\x10\xff\
+\x17\x91\x12\x12i\xe3\x899:\xa2\x8fL2\x9d\x8d\x00\x19Sg\xba\xf2a\x13\xd7C%\xd0\xdc\x13\xcc\
+\xea5\xd6\x1a\xbc\x10\xb4\xb2L\xc8\xf6\x8a\x1e\x13]\x02\x11\x03\x12 \xe2"\xfd\xa1\x00z\\\xbf\
+\xab}\xa3\xc4\x0f\x9a\x9e\x05\x11\xe9\x8b\xf0\xcf\xab=\xb8z\x07 t\xa2\t\xdf*?\x08\x1d\x19\
+\xb7in5 n!cQ\xfa\xe3@\xdc\xa6+\x18\xa2\xfb\xed\x10\xa7\xd27i\xe3f\x83\xde\xf7\xac,#\x1a7\x01\
+\xb6\x17OL\xa8Nc\xd0@\xc4\x0c\x10\x12\xdd2\xf0\xe9\x11\xf4L\x85t\x8b\xdc~\xc0\xb7Z5\x08^#\x9d\
+\xf5\xc8\xf4S\xc7\x13\x07\xa4\x8d\xe9k\xc0\xa2\x11\xa1\xa9\xc5r \x82\xc7\xe7#jI\xec\xb8M\xcb\
+\xfe\x06\xa0?\x87\xa6M\xf5&\xed\xc7\xd2/?\x82\xba]6\xc2\xadcM\xca\x01\x97bd\x86i\x82~\xcbJ\x83\
+\xd1A\x82\x8e\x8d\r\x18\x1e\x1dCf;)\xf0y\xb1\xe3Q|\x05\x02[\x83\xd7\x83]\x10\xb7\xc0\xadc\'l\x88\
+\xa9\x8e6\xd0\xac\x12P\xa2\xda4\xb2\xf9?\t\xc0\xee\xfa\x86\xe9\xdf\x87k+\xe9\xbe\x10b_\xf3A\x0c\
+\xc3\xc0W"A\x9b\x08\x9d\xd7\xd0\xb1\x12\x02]7 aa\xc7-\xf4t\xbd\xd7\xdd:\xcc\xd07\xdaq\xb0\xe2\
+\n@t0:\xfb\xc7\xe9d\t_\xe8\x92\x9d\x1d\x01\xba\xdf\x0cO\x07Y\xee\x9fq~\xb2<^YK\xc3\xde-\xb9{^\
+\xed\xe3\xe5\x1f\xb6r\xaa\x07!>J\xe6u\xfc, \xfb\xfe\xdeG\xf7\x99c\xd3\x80\xb7\xbe\x14\x16\x00\
+\xff\x03\x07\x06\x80\xbbd\xd4\xb0\x14\x00\x00\x00\x00IEND\xaeB`\x82'
+ elif shellName=='SymPySlices':
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
+\x00\x00szz\xf4\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\x06bKGD\
+\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\
+\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xd9\n\x10\x10\x0c\
+\x119od\xf7\x00\x00\x07\xa2IDATX\xc3\xb5\x97{PT\xd7\x1d\xc7?wY\x96\xbb\xb0\xcb\
+\xbd\x08\x08\xa8\x19V\x05\xe2\xab\xd95\xc1\x88\xa2\x03\x98\xf1\x11\'-\xda\x98h\
+\x92\xa9b\x1fN:mG\xb0\xb13\xd5v\x80\xc4\xa9m\x98\x04\x8cQcfj \xcdL\x9c\xfc\
+\x03$\xea\x18k\'\xc4\x91\xa8\xa5Iv\x93\xf8H\xa0e7\xf1\x01\xa3v\xef\x85\x95\xbd\
+\xeb\n\xb7\x7f\xdc\xdd\x85\xe5\xa1If\xfa\x9b\xb9s~\xf7\xbc~\xdfs~\xdf\xf3;\xbf\
+#0\xbe\xe4LM\xe7\xea\xbe_\x80\x9cb"<\xa8\xa3\x04\x05>\xf3\x99)\x9b;\xc8\x8bG\
+\xd3\x87BB\x06\x9b\xd7-!;S\xc6\x9c`\x12\xd2\'\xc9B\xe9\x86]\x00\x14\x17\xce\xde\
+\x7f\xb2\xdd\xb3O\xd3n_\xe0\x1e"\x8cW\xb9`&\xb7\x8a\n\xf0\xffh!\x93\xe5\x14\x12\
+M&H0\x81\x0e\x84\xc2\x02b\xa2\xce\x91\x8f\x13i\xef\xb4\xa1\xde\x96\xf5\x95K\xf2\
+\xf4y\xf9\xd9\xe4L\xcd\x1bRn\x85\xf5\xb7[\xdb\x87ZO\x9c3\xf5\xf5\x0f\x94\x00g\
+\xbe+\x00\xc7\x96G\xf8\xa2\xbc\x88\x84\xec4D\xc1\x04\xe8`2\xc5w\xba}\x07\x06\x87\
+\x04zU\xd8\xbc/\x05\xbf\x1a`\xe3\x13\xcb\x06\xb7m)\x1fLN\x16\x83\xe7\xffs\xc5\
+\xbb\xf6\'\xcf;\x81U\xc0\xfb\xdf\x05@\xc1\xb2\xb9\xb8w=\x8dE\x14I\x18mx\xa4\xf4\
+\x0f\xc0\xe9\xf3\x10\xba\x03\xc5\xb3\x12xr\x8f\x15\xbf\x1a\xe0\xeb\x8eCL\x92l\xdc\
+\x18\x18\xc0\xe1\xaa\x00\xa8\x06\x9e\xffV\x00J\xe70\xe8t\x10\xde\xb8\x0c\x8b\xc9\
+\x84 \x08\x13\x038\xf5\x05<4\x1d\x12\xcc\xa0i\x90`\x81\xae\x1b\x12M\xe7r\xd9\xf1\
+\x9b\xf5,/\x9a\x8bOQ\xb8\xe0\xf97\xab7\xbd\xd0\x06\x94\x8d\x9ec\xcc\xfa\n\xa6 ,w\
+\xde\xdd\xf8\xc5\xcbp\xe08\xa4\xdbA0\x81\x98\x04\xb2\x04v+\xcc\xbfO\xa5a\xddg\xac\
+\xd8\xb0\x93\xd6\xb6O\xc9\x95e\xe68g\xe2>^_\xba\xda\x89~O\x00j\x10\x92\x12A\xd7\
+\x8do<\xf9\xa4\x0b\x1e_\x00SeH\xb6\x8e\xdfg\xb5\x13\xd6T\xd4\xd2v\xd6M\xae,#g\xa7\
+\xf1\xbb\x9a\x1aF\x83H\x18\xf9s\xff\x14\xf4\xf5\xc5\x08\x8e,\x04\xb3\xd9\x00\x10\
+\xdd\x85P\x18\n\x9f\x83\xeb}\xf0\xcc\x12\x10\x13!5ub\xf7<\xe2\x82\xaf{\xe0\x0f\xfb\
+\xda(+]\x88\xd3\x91\x83`\x15\x993\xdd\xc9\xf5\xee\x0fk:{\xa9\x1d\xc3\x81\x9f-C\xdf\
+X\x06\xf6d\xc3\xb0\x1ea\xff\x81\xe3p\xf0}\xbe\x97d\xda\xe1z?\xe8\xde\x16\xdeln\xc3\
+\xfd\xa5\x8f\xfa\xd7\x9ac\xb6c.xf)\xfa\xb4tHN\x8a\xb0S0\x8c\xff\xf5\xe4\xf77\x0e\
+\x90\x96S\xc0\x91#Gx\xab\xb9\x8d\xb2%N\xb6>[Ns\xc3V\x8c\xc3=\x02\xc0\xe5\x9bP\xfa\
+\x03\x83T\xd1\xd5+*\xec=:\xf1\xe4\xc9\xc9\xc9$\'\'#\x8ab\xbc\xd1\xb44222\xc8\xcc\
+\xcc\xa4\xae\xae\x0e\xd7\xbc|l\x82\x82\xa0\x9b\xc8\x95e\xe6\x17\xb9b}\xcdQe\x92\x1d\
+l"\x0c\rAx\x10^j\x85\xf6\x8bF\x9b\x1eac \x10\xc0n\xb7\xc7\xd5i\xda\x00CC\x90\x92\
+\x92\x02@__\x1fv\xbb\x9d;\x9a\x1f\xf4A\xd0u\xbe9\xf9s\xd6V\xbeK\xcb\xdb\x0e\xa6Mv\
+\xe1\xbd\xe6\x8b\x07\xf0\xe8\x83\xe8\x93eHL\x84\x81\x10<\xfa\x02\xfc\xf6\x87p\xe6\
+\x12\xdc\xf8\xf2]\x00<\r\x02\xdd\xbd\xf1;\xf0\xf2O\x05\xa6\xa6\x1b\xc0\xa3b\xb7\xdb\
+\xf9|_*C\xe1\xfeX\x9d\xae\x19\xa7B\xe9\xf1\x02.\x1c\xd3\x1d\xb4\x1d\xae\xa1tC\x8dn\
+\x06\x90Dxj\x91\xd1\xf9\xe0qh\xddn\xe8\x8b\x0b\xc0"\x17\x90)\t\xactA\xfb\xa5QL\x7f\
+`|\xd7\x8c6\x0e\xf0\xa7\n\xd8\xd1\xd8\xc8\xa6\xb5k\x00P\x14\xbf\x11\x07\x9eXL\xc7\
+\xe1\x8f\x8c@\xe2\xaa\x82\xcd\xa5\xc6\x80u/\xc3\x81\xbfCj\xd6,N\xd6\xc2\xf6\xb5\xb0\
+n\xf1\xf8\x06\xff\xdb\xff\xedI\xa9\x04u\xa4$\t\xe7\xac\xe9\x11\x17\x0c1\xfd\x81\\\
+\xc3x\xd9\\x\xe9=x\xefcp\xd7\x1b\x03\xfe\xf8\xe4\xf0\xe0\xce\xabF\x99\x95\x95\x157\
+\xa9\xefz\xbc\x11]\x03A\x1c^\xbd0\xc2E\xaa\xa6"[e|~\xc5\x00p\xae\x93[\xc10\xe9\x00\
+\x1f\x9c\x1f\xee\xb8\xa3qX?\xe61\xca\xfc\x1c\xa3,,,$|k\x98\x10\xa3\xb9\x115(\xc4\
+\x1f\x8e\xd8<\x88\x12\xba\xaa\xc4.#\xbd\xb9\xd2p\x81\xa2\x8e-}A\x90E\xb0\rZY\xf7j\
+\x10\x80\xba\xba:f\xcf\x9e\xcd\xfe\x9d\x8fq\xcc\x03yY\xd0\xd5;|b\x9a~e\x01 73\x0c\
+\x18\xe3\x01\xd4\x10\xbc\xd8l\xe8\x964\x07\xa5%.\xe3\x14\xf8\x82\xc6\x17\xd5\xf3,6\
+<=\x01\xf2,6\xf2,\xd0\xa5\x05\xb0%\x0e\xaf\xa4\xa4\xa4\x04\xdb\x95\x16V\x14\xc1\x8a\
+"8y6\x81\xae\xdeA\xa6M\x9bf\x18L\r\xe3\xf7\x83\xef\xba1\xc8\x07\xbc\xd3\x1e\xc6\x92\
+\xe6`\x7fc\r\x12\xf0\xa1\xdb\xcd\xeb\r\r\x98\xaa\xb3]\xd0RB\xe5A8q\x16*\x0f\xc2c{\
+\x03\x9c8k\x94\xfbO\x05(I\x93\t\xde0\x0fgL\x0b\x16p\xb3\xeb4rB"y\x16\x9b\x912\x01\
+\xaa\xaa\xd2\xef\xbf\xcc\x9d\x80\x15\x15\xb0\x99\xcc\xb1\x0f\xe0\x8d\x03\xf5H\xa2\
+\x84,K\x94\x96\x95\x1b\x1c\xe8\xc8r\xb3\xdcSN=\xe5\xe0\x81\xe5Q+Q\xdd\xa3\xd2\xe6\
+\xd3\xd9\xd5w.\xce\x9fK\xb7\x9f\x8aha\xd6/2\x00\xf4\xf7\xf7#Z%D!\x81<\x8b\x8d\x81\
+\xdb:\xa7\xae\xdeb\x95\xc3\x16\t\xef*R\x92\x04\x02H\xa3#\xe1\xc4"\xe1V\xaep\x13-\xae\
+\xb6\x9e\xf2\x98~\xfeL\x0f`\x00\xdc\xfdb=\xd5{\x03\xb16Q\x14\xf9|\xe1C\xb8r\xbcH\xa2\
+\x1c\xb9\xe7AQ\x8dhhz\xd8SzO\x08M\xfc+\xa6\x17\x17\x17\x8fi\xcf\'#\xa6WWW\xc7\xb5}\
+\xd3q\x89\x9d3\x1f\x07Q@\r*\xa8!\xd5pW4!\xf9\xa7\xb3\xed\xae\xc6\xaf\xd1\x17\xf7\xbf\
+{\xf7n\xaeF/\x89\x88X&\xd8\xc8\xbc\xbc<2\xe6\xe5r\xfe\xd0?\x8c\x95\x87@J\x92PCw\xc9\
+\x88\xc6<\x10H\x8d\xdb\xce\xa5K\x97r\xfa\xf7\x7f\x1b\xd3o\x1b%q\xffV\xab\x95\xce\xce\
+N\x94\xaek\xc3\xf7{\xe4\xe0\xebA#\x06\x14\xccvb\xce\xcf\x86*Okl\xe0\xd6r\x99=\xadJ,\
+\xad\x02X\r\xecz\xe3\x13\xe6\xcf\x9fOX\x0bq\xa1\xf3#\x04Y\x88<\x14@\xd2$\xeeC\xe6\xad\
+\x07\xab\xc8\xdd\xf3cf\xcc\x98\xc1\x94)S\xb8\x13\x0c\xd1\x98\xffK\xe3hf\xbb@\x94b \
+\xbc\xdd^\xbe\xba\xe8\xc1\xdc\xd9\x03m\x87+q\xdc\xef\x02AB\xd7T\xaaje\xd0\x14\xf4\xa0\
+\x1f\x9f\x06h*o\xbe\xb2\x8dC\x03*\xaf\xbe\xf3\xa9\x01t\x95L\xe75%\x16\xdd\xb6\xae\x04\
+\xaf\x9aK\xd7\xaf\x9b\xf9\xcaU\x88\xdf\xad\x12\xf0\x86A\xd6\x91\x14\x19\x87\xe4E\x8aF\
+\xc8$!\xfe:v\xcc2\x12\x84\\\xd9`\xbd\xb14\t\x90H\xd3\x00]\xc5\xe9\xa8@A\xe2\xb9Zc\xb0\
+\xde\xe3%\xcd\xe1\xc0\xaf\xe8\xa8\x9a\xca\x8eg+"!\x07j\x9a\xbc\x00Tnr\xd2\xd0\x14A\xf8\
+\x17X\xf3\x94\x8a\x90$\xa1\x8c\xe0\x80\x19@\x06\xa2\x91\xd9\xa7(\x110\x12\xe8 \xa1\xa2\
+\x02r\x9a\x84\xac\xc72)p\xe4\xa2j~\x1cV\x01U\x84\xa3\xad-\xa0)\x90$\x19L\x0f\x1a\x19\
+mM\x15\xa0\xeb\xe8\x80\x904\x92\xff#\x00<\xbd\xa9b\xec\xfbpQ)\x1dg\xda\xd8RU\x8d,\xcb\
+8\xb2u\x10\x87\xb7.W\x96PB\x02\x92$CHA\xd5\x14\xa4H\xbc\x97\x92$\x10\xc7\x12Z\xd5@\xd1\
+\x0c\x00\xfe^\xff\xc4\x8f\xd3\x91\xe2>\xd3\xa277\xd6\xd0q\xd6=\x16d\x91k\xdc\xfa\x91\
+\xf2pi9\x15\x9b\xd7\xc6\xcfy\xb1\x9b\xd7\xff\\\xcb1\x0f\x82\xc0\xffQ\x1a_\xab\xd1\xbb\
+/u\xd3\xf1A\xd3\x18\xe0\xb5\x07\xdd\x02\xc0\xff\x00+\xe4\xca\x93\x95`\xa8\xfa\x00\x00\
+\x00\x00IEND\xaeB`\x82'
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/interpreter.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/interpreter.py
new file mode 100644
index 0000000..35468a1
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/interpreter.py
@@ -0,0 +1,170 @@
+"""Interpreter executes Python commands."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com> / "
+__author__ += "David N. Mashburn <david.n.mashburn@gmail.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import os
+import sys
+from code import InteractiveInterpreter, compile_command
+import dispatcher
+import introspect
+import wx
+
+class Interpreter(InteractiveInterpreter):
+ """Interpreter based on code.InteractiveInterpreter."""
+
+ revision = __revision__
+
+ def __init__(self, locals=None, rawin=None,
+ stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
+ showInterpIntro=True):
+ """Create an interactive interpreter object."""
+ InteractiveInterpreter.__init__(self, locals=locals)
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ if rawin:
+ import __builtin__
+ __builtin__.raw_input = rawin
+ del __builtin__
+ if showInterpIntro:
+ copyright = 'Type "help", "copyright", "credits" or "license"'
+ copyright += ' for more information.'
+ self.introText = 'Python %s on %s%s%s' % \
+ (sys.version, sys.platform, os.linesep, copyright)
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = '>>> '
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = '... '
+ self.more = 0
+ # List of lists to support recursive push().
+ self.commandBuffer = []
+ self.startupScript = None
+
+ def push(self, command, astMod=None):
+ """Send command to the interpreter to be executed.
+
+ Because this may be called recursively, we append a new list
+ onto the commandBuffer list and then append commands into
+ that. If the passed in command is part of a multi-line
+ command we keep appending the pieces to the last list in
+ commandBuffer until we have a complete command. If not, we
+ delete that last list."""
+
+ # In case the command is unicode try encoding it
+ if type(command) == unicode:
+ try:
+ command = command.encode(wx.GetDefaultPyEncoding())
+ except UnicodeEncodeError:
+ pass # otherwise leave it alone
+
+ if not self.more:
+ try: del self.commandBuffer[-1]
+ except IndexError: pass
+ if not self.more: self.commandBuffer.append([])
+ self.commandBuffer[-1].append(command)
+ source = '\n'.join(self.commandBuffer[-1])
+
+ # If an ast code module is passed, pass it to runModule instead
+ more=False
+ if astMod != None:
+ self.runModule(astMod)
+ self.more=False
+ else:
+ more = self.more = self.runsource(source)
+ dispatcher.send(signal='Interpreter.push', sender=self,
+ command=command, more=more, source=source)
+ return more
+
+ def runsource(self, source):
+ """Compile and run source code in the interpreter."""
+ stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
+ sys.stdin, sys.stdout, sys.stderr = \
+ self.stdin, self.stdout, self.stderr
+ more = InteractiveInterpreter.runsource(self, source)
+ # this was a cute idea, but didn't work...
+ #more = self.runcode(compile(source,'',
+ # ('exec' if self.useExecMode else 'single')))
+
+
+ # If sys.std* is still what we set it to, then restore it.
+ # But, if the executed source changed sys.std*, assume it was
+ # meant to be changed and leave it. Power to the people.
+ if sys.stdin == self.stdin:
+ sys.stdin = stdin
+ else:
+ self.stdin = sys.stdin
+ if sys.stdout == self.stdout:
+ sys.stdout = stdout
+ else:
+ self.stdout = sys.stdout
+ if sys.stderr == self.stderr:
+ sys.stderr = stderr
+ else:
+ self.stderr = sys.stderr
+ return more
+
+ def runModule(self, mod):
+ """Compile and run an ast module in the interpreter."""
+ stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
+ sys.stdin, sys.stdout, sys.stderr = \
+ self.stdin, self.stdout, self.stderr
+ self.runcode(compile(mod,'','single'))
+ # If sys.std* is still what we set it to, then restore it.
+ # But, if the executed source changed sys.std*, assume it was
+ # meant to be changed and leave it. Power to the people.
+ if sys.stdin == self.stdin:
+ sys.stdin = stdin
+ else:
+ self.stdin = sys.stdin
+ if sys.stdout == self.stdout:
+ sys.stdout = stdout
+ else:
+ self.stdout = sys.stdout
+ if sys.stderr == self.stderr:
+ sys.stderr = stderr
+ else:
+ self.stderr = sys.stderr
+ return False
+
+ def getAutoCompleteKeys(self):
+ """Return list of auto-completion keycodes."""
+ return [ord('.')]
+
+ def getAutoCompleteList(self, command='', *args, **kwds):
+ """Return list of auto-completion options for a command.
+
+ The list of options will be based on the locals namespace."""
+ stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
+ sys.stdin, sys.stdout, sys.stderr = \
+ self.stdin, self.stdout, self.stderr
+ l = introspect.getAutoCompleteList(command, self.locals,
+ *args, **kwds)
+ sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
+ return l
+
+ def getCallTip(self, command='', *args, **kwds):
+ """Return call tip text for a command.
+
+ Call tip information will be based on the locals namespace."""
+ return introspect.getCallTip(command, self.locals, *args, **kwds)
+
+
+class InterpreterAlaCarte(Interpreter):
+ """Demo Interpreter."""
+
+ def __init__(self, locals, rawin, stdin, stdout, stderr,
+ ps1='main prompt', ps2='continuation prompt'):
+ """Create an interactive interpreter object."""
+ Interpreter.__init__(self, locals=locals, rawin=rawin,
+ stdin=stdin, stdout=stdout, stderr=stderr)
+ sys.ps1 = ps1
+ sys.ps2 = ps2
+
+
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/introspect.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/introspect.py
new file mode 100644
index 0000000..0a14f89
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/introspect.py
@@ -0,0 +1,389 @@
+"""Provides a variety of introspective-type support functions for
+things like call tips and command auto completion."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import cStringIO
+import inspect
+import sys
+import tokenize
+import types
+import wx
+
+def getAutoCompleteList(command='', locals=None, includeMagic=1,
+ includeSingle=1, includeDouble=1):
+ """Return list of auto-completion options for command.
+
+ The list of options will be based on the locals namespace."""
+ attributes = []
+ # Get the proper chunk of code from the command.
+ root = getRoot(command, terminator='.')
+ try:
+ if locals is not None:
+ object = eval(root, locals)
+ else:
+ object = eval(root)
+ except:
+ pass
+ else:
+ attributes = getAttributeNames(object, includeMagic,
+ includeSingle, includeDouble)
+ return attributes
+
+def getAttributeNames(object, includeMagic=1, includeSingle=1,
+ includeDouble=1):
+ """Return list of unique attributes, including inherited, for object."""
+ attributes = []
+ dict = {}
+ if not hasattrAlwaysReturnsTrue(object):
+ # Add some attributes that don't always get picked up.
+ special_attrs = ['__bases__', '__class__', '__dict__', '__name__',
+ 'func_closure', 'func_code', 'func_defaults',
+ 'func_dict', 'func_doc', 'func_globals', 'func_name']
+ attributes += [attr for attr in special_attrs \
+ if hasattr(object, attr)]
+ if includeMagic:
+ try: attributes += object._getAttributeNames()
+ except: pass
+ # Special code to allow traits to be caught by autocomplete
+ if hasattr(object,'trait_get'):
+ try:
+ for i in object.trait_get().keys():
+ if i not in attributes:
+ if hasattr(object, i):
+ attributes += i
+ except:
+ pass
+ # Get all attribute names.
+ str_type = str(type(object))
+ if str_type == "<type 'array'>":
+ attributes += dir(object)
+ else:
+ attrdict = getAllAttributeNames(object)
+ # Store the object's dir.
+ object_dir = dir(object)
+ for (obj_type_name, technique, count), attrlist in attrdict.items():
+ # This complexity is necessary to avoid accessing all the
+ # attributes of the object. This is very handy for objects
+ # whose attributes are lazily evaluated.
+ if type(object).__name__ == obj_type_name and technique == 'dir':
+ attributes += attrlist
+ else:
+ attributes += [attr for attr in attrlist \
+ if attr not in object_dir and hasattr(object, attr)]
+
+ # Remove duplicates from the attribute list.
+ for item in attributes:
+ dict[item] = None
+ attributes = dict.keys()
+ # new-style swig wrappings can result in non-string attributes
+ # e.g. ITK http://www.itk.org/
+ attributes = [attribute for attribute in attributes \
+ if type(attribute) == str]
+ attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))
+ if not includeSingle:
+ attributes = filter(lambda item: item[0]!='_' \
+ or item[1:2]=='_', attributes)
+ if not includeDouble:
+ attributes = filter(lambda item: item[:2]!='__', attributes)
+ return attributes
+
+def hasattrAlwaysReturnsTrue(object):
+ return hasattr(object, 'bogu5_123_aTTri8ute')
+
+def getAllAttributeNames(object):
+ """Return dict of all attributes, including inherited, for an object.
+
+ Recursively walk through a class and all base classes.
+ """
+ attrdict = {} # (object, technique, count): [list of attributes]
+ # !!!
+ # Do Not use hasattr() as a test anywhere in this function,
+ # because it is unreliable with remote objects: xmlrpc, soap, etc.
+ # They always return true for hasattr().
+ # !!!
+ try:
+ # This could(?) fail if the type is poorly defined without
+ # even a name.
+ key = type(object).__name__
+ except:
+ key = 'anonymous'
+ # Wake up sleepy objects - a hack for ZODB objects in "ghost" state.
+ wakeupcall = dir(object)
+ del wakeupcall
+ # Get attributes available through the normal convention.
+ attributes = dir(object)
+ attrdict[(key, 'dir', len(attributes))] = attributes
+ # Get attributes from the object's dictionary, if it has one.
+ try:
+ attributes = object.__dict__.keys()
+ attributes.sort()
+ except: # Must catch all because object might have __getattr__.
+ pass
+ else:
+ attrdict[(key, '__dict__', len(attributes))] = attributes
+ # For a class instance, get the attributes for the class.
+ try:
+ klass = object.__class__
+ except: # Must catch all because object might have __getattr__.
+ pass
+ else:
+ if klass is object:
+ # Break a circular reference. This happens with extension
+ # classes.
+ pass
+ else:
+ attrdict.update(getAllAttributeNames(klass))
+ # Also get attributes from any and all parent classes.
+ try:
+ bases = object.__bases__
+ except: # Must catch all because object might have __getattr__.
+ pass
+ else:
+ if isinstance(bases, types.TupleType):
+ for base in bases:
+ if type(base) is types.TypeType:
+ # Break a circular reference. Happens in Python 2.2.
+ pass
+ else:
+ attrdict.update(getAllAttributeNames(base))
+ return attrdict
+
+def getCallTip(command='', locals=None):
+ """For a command, return a tuple of object name, argspec, tip text.
+
+ The call tip information will be based on the locals namespace."""
+ calltip = ('', '', '') # object name, argspec, tip text.
+ # Get the proper chunk of code from the command.
+ root = getRoot(command, terminator='(')
+ try:
+ if locals is not None:
+ object = eval(root, locals)
+ else:
+ object = eval(root)
+ except:
+ return calltip
+ name = ''
+ object, dropSelf = getBaseObject(object)
+ try:
+ name = object.__name__
+ except AttributeError:
+ pass
+ tip1 = ''
+ argspec = ''
+ if inspect.isbuiltin(object):
+ # Builtin functions don't have an argspec that we can get.
+ pass
+ elif inspect.isfunction(object):
+ # tip1 is a string like: "getCallTip(command='', locals=None)"
+ argspec = apply(inspect.formatargspec, inspect.getargspec(object))
+ if dropSelf:
+ # The first parameter to a method is a reference to an
+ # instance, usually coded as "self", and is usually passed
+ # automatically by Python; therefore we want to drop it.
+ temp = argspec.split(',')
+ if len(temp) == 1: # No other arguments.
+ argspec = '()'
+ elif temp[0][:2] == '(*': # first param is like *args, not self
+ pass
+ else: # Drop the first argument.
+ argspec = '(' + ','.join(temp[1:]).lstrip()
+ tip1 = name + argspec
+ doc = ''
+ if callable(object):
+ try:
+ doc = inspect.getdoc(object)
+ except:
+ pass
+ if doc:
+ # tip2 is the first separated line of the docstring, like:
+ # "Return call tip text for a command."
+ # tip3 is the rest of the docstring, like:
+ # "The call tip information will be based on ... <snip>
+ firstline = doc.split('\n')[0].lstrip()
+ if tip1 == firstline or firstline[:len(name)+1] == name+'(':
+ tip1 = ''
+ else:
+ tip1 += '\n\n'
+ docpieces = doc.split('\n\n')
+ tip2 = docpieces[0]
+ tip3 = '\n\n'.join(docpieces[1:])
+ tip = '%s%s\n\n%s' % (tip1, tip2, tip3)
+ else:
+ tip = tip1
+ calltip = (name, argspec[1:-1], tip.strip())
+ return calltip
+
+def getRoot(command, terminator=None):
+ """Return the rightmost root portion of an arbitrary Python command.
+
+ Return only the root portion that can be eval()'d without side
+ effects. The command would normally terminate with a '(' or
+ '.'. The terminator and anything after the terminator will be
+ dropped."""
+ command = command.split('\n')[-1]
+ if command.startswith(sys.ps2):
+ command = command[len(sys.ps2):]
+ command = command.lstrip()
+ command = rtrimTerminus(command, terminator)
+ tokens = getTokens(command)
+ if not tokens:
+ return ''
+ if tokens[-1][0] is tokenize.ENDMARKER:
+ # Remove the end marker.
+ del tokens[-1]
+ if not tokens:
+ return ''
+ if terminator == '.' and \
+ (tokens[-1][1] <> '.' or tokens[-1][0] is not tokenize.OP):
+ # Trap decimals in numbers, versus the dot operator.
+ return ''
+ else:
+ # Strip off the terminator.
+ if terminator and command.endswith(terminator):
+ size = 0 - len(terminator)
+ command = command[:size]
+ command = command.rstrip()
+ tokens = getTokens(command)
+ tokens.reverse()
+ line = ''
+ start = None
+ prefix = ''
+ laststring = '.'
+ emptyTypes = ('[]', '()', '{}')
+ for token in tokens:
+ tokentype = token[0]
+ tokenstring = token[1]
+ line = token[4]
+ if tokentype is tokenize.ENDMARKER:
+ continue
+ if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
+ and laststring != '.':
+ # We've reached something that's not part of the root.
+ if prefix and line[token[3][1]] != ' ':
+ # If it doesn't have a space after it, remove the prefix.
+ prefix = ''
+ break
+ if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
+ or (tokentype is tokenize.OP and tokenstring == '.'):
+ if prefix:
+ # The prefix isn't valid because it comes after a dot.
+ prefix = ''
+ break
+ else:
+ # start represents the last known good point in the line.
+ start = token[2][1]
+ elif len(tokenstring) == 1 and tokenstring in ('[({])}'):
+ # Remember, we're working backwords.
+ # So prefix += tokenstring would be wrong.
+ if prefix in emptyTypes and tokenstring in ('[({'):
+ # We've already got an empty type identified so now we
+ # are in a nested situation and we can break out with
+ # what we've got.
+ break
+ else:
+ prefix = tokenstring + prefix
+ else:
+ # We've reached something that's not part of the root.
+ break
+ laststring = tokenstring
+ if start is None:
+ start = len(line)
+ root = line[start:]
+ if prefix in emptyTypes:
+ # Empty types are safe to be eval()'d and introspected.
+ root = prefix + root
+ return root
+
+def getTokens(command):
+ """Return list of token tuples for command."""
+
+ # In case the command is unicode try encoding it
+ if type(command) == unicode:
+ try:
+ command = command.encode(wx.GetDefaultPyEncoding())
+ except UnicodeEncodeError:
+ pass # otherwise leave it alone
+
+ f = cStringIO.StringIO(command)
+ # tokens is a list of token tuples, each looking like:
+ # (type, string, (srow, scol), (erow, ecol), line)
+ tokens = []
+ # Can't use list comprehension:
+ # tokens = [token for token in tokenize.generate_tokens(f.readline)]
+ # because of need to append as much as possible before TokenError.
+ try:
+## This code wasn't backward compatible with Python 2.1.3.
+##
+## for token in tokenize.generate_tokens(f.readline):
+## tokens.append(token)
+
+ # This works with Python 2.1.3 (with nested_scopes).
+ def eater(*args):
+ tokens.append(args)
+ tokenize.tokenize_loop(f.readline, eater)
+ except tokenize.TokenError:
+ # This is due to a premature EOF, which we expect since we are
+ # feeding in fragments of Python code.
+ pass
+ return tokens
+
+def rtrimTerminus(command, terminator=None):
+ """Return command minus anything that follows the final terminator."""
+ if terminator:
+ pieces = command.split(terminator)
+ if len(pieces) > 1:
+ command = terminator.join(pieces[:-1]) + terminator
+ return command
+
+def getBaseObject(object):
+ """Return base object and dropSelf indicator for an object."""
+ if inspect.isbuiltin(object):
+ # Builtin functions don't have an argspec that we can get.
+ dropSelf = 0
+ elif inspect.ismethod(object):
+ # Get the function from the object otherwise
+ # inspect.getargspec() complains that the object isn't a
+ # Python function.
+ try:
+ if object.im_self is None:
+ # This is an unbound method so we do not drop self
+ # from the argspec, since an instance must be passed
+ # as the first arg.
+ dropSelf = 0
+ else:
+ dropSelf = 1
+ object = object.im_func
+ except AttributeError:
+ dropSelf = 0
+ elif inspect.isclass(object):
+ # Get the __init__ method function for the class.
+ constructor = getConstructor(object)
+ if constructor is not None:
+ object = constructor
+ dropSelf = 1
+ else:
+ dropSelf = 0
+ elif callable(object):
+ # Get the __call__ method instead.
+ try:
+ object = object.__call__.im_func
+ dropSelf = 1
+ except AttributeError:
+ dropSelf = 0
+ else:
+ dropSelf = 0
+ return object, dropSelf
+
+def getConstructor(object):
+ """Return constructor for class object, or None if there isn't one."""
+ try:
+ return object.__init__.im_func
+ except AttributeError:
+ for base in object.__bases__:
+ constructor = getConstructor(base)
+ if constructor is not None:
+ return constructor
+ return None
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/magic.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/magic.py
new file mode 100644
index 0000000..9625f87
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/magic.py
@@ -0,0 +1,92 @@
+"""magic.py is a utility that allows a simple line from the interpreter
+be translated from a more bash-like form to a python form.
+For instance, 'plot a' is transformed to 'plot(a)'
+Special exceptions are made for predefined ls,cd, and pwd functions"""
+
+__author__ = "David N. Mashburn <david.n.mashburn@gmail.com>"
+# created 07/01/2009
+
+import keyword
+
+from parse import testForContinuations
+
+aliasDict = {}
+
+#DNM
+# TODO : Still Refining this... seems to be ok for now... still finding gotchas, though!
+# TODO : Multi-line strings seem to be correctly broken into commands by PyCrust(PySlices)
+# TODO : Is there a better version of ls, cd, pwd, etc that could be used?
+def magicSingle(command):
+ if command=='': # Pass if command is blank
+ return command
+
+ first_space=command.find(' ')
+
+ if command[0]==' ': # Pass if command begins with a space
+ pass
+ elif command[0]=='?': # Do help if starts with ?
+ command='help('+command[1:]+')'
+ elif command[0]=='!': # Use os.system if starts with !
+ command='sx("'+command[1:]+'")'
+ elif command in ('ls','pwd'): # automatically use ls and pwd with no arguments
+ command=command+'()'
+ elif command[:3] in ('ls ','cd '): # when using the 'ls ' or 'cd ' constructs, fill in both parentheses and quotes
+ command=command[:2]+'("'+command[3:]+'")'
+ elif command[:6] == 'alias ':
+ c = command[6:].lstrip().split(' ')
+ if len(c)<2:
+ #print 'Not enough arguments for alias!'
+ command = ''
+ else:
+ n,v = c[0],' '.join(c[1:])
+ aliasDict[n]=v
+ command = ''
+ elif command.split(' ')[0] in aliasDict.keys():
+ c = command.split(' ')
+ if len(c)<2:
+ command = 'sx("'+aliasDict[c[0]]+'")'
+ else:
+ command = 'sx("'+aliasDict[c[0]]+' '+' '.join(c[1:])+'")'
+ elif first_space!=-1: # if there is at least one space, add parentheses at beginning and end
+ cmds=command.split(' ')
+ if len(cmds)>1:
+ wd1=cmds[0]
+ wd2=cmds[1]
+ i=1
+ while wd2=='':
+ i+=1
+ if len(cmds)==i:
+ break
+ wd2=cmds[i]
+ if wd2=='':
+ return command
+ if (wd1[0].isalpha() or wd1[0]=='_') and (wd2[0].isalnum() or (wd2[0] in """."'_""")) and not keyword.iskeyword(wd1) and not keyword.iskeyword(wd2):
+ if wd1.replace('.','').replace('_','').isalnum():
+ command=wd1+'('+command[(first_space+1):]+')' # add parentheses where the first space was and at the end... hooray!
+ return command
+
+def magic(command):
+ continuations = testForContinuations(command)
+
+ if len(continuations)==2: # Error case...
+ return command
+ elif len(continuations)==4:
+ stringContinuationList,indentationBlockList, \
+ lineContinuationList,parentheticalContinuationList = continuations
+
+ commandList=[]
+ firstLine = True
+ for i in command.split('\n'):
+ if firstLine:
+ commandList.append(magicSingle(i))
+ elif stringContinuationList.pop(0)==False and \
+ indentationBlockList.pop(0)==False and \
+ lineContinuationList.pop(0)==False and \
+ parentheticalContinuationList.pop(0)==False:
+ commandList.append(magicSingle(i)) # unless this is in a larger expression, use magic
+ else:
+ commandList.append(i)
+
+ firstLine=False
+
+ return '\n'.join(commandList)
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/parse.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/parse.py
new file mode 100644
index 0000000..bb6c819
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/parse.py
@@ -0,0 +1,128 @@
+"""parse.py is a utility that allows simple checking for line continuations
+to give the shell information about where text is commented and where it is
+not and also how to appropriately break up a sequence of commands into
+separate multi-line commands...
+"""
+
+__author__ = "David N. Mashburn <david.n.mashburn@gmail.com>"
+# created 12/20/2009
+
+import re
+
+# change this to testForContinuations
+
+def testForContinuations(codeBlock,ignoreErrors=False):
+ """ Test 4 different types of continuations:""" + \
+ """ String Continuations (ie with ''')""" + \
+ """ Indentation Block Continuations (ie "if 1:" )""" + \
+ """ Line Continuations (ie with \\ character )""" + \
+ """ Parenthetical continuations (, [, or {"""
+
+ stringMark = None
+ paraList = []
+ indentNumber=[0]
+
+ stringMarks = ['"""',"'''",'"',"'"]
+ openMarks = ['(','[','{']
+ closeMarks = [')',']','}']
+ paraMarkDict = { '(':')', '[':']', '{':'}' }
+
+ stringContinuationList=[]
+ lineContinuationList=[] # For \ continuations ... False because cannot start as line Continuation...
+ indentationBlockList=[]
+ parentheticalContinuationList=[]
+ newIndent=False
+ lspContinuation=False
+ for i,l in enumerate(codeBlock.split('\n')):
+ currentIndentation = len(l)-len(l.lstrip())
+
+ if i>0:
+ lspContinuation = lineContinuationList[-1] or \
+ stringContinuationList[-1] or \
+ parentheticalContinuationList[-1]
+ # first, check for non-executing lines (whitespace and/or comments only)
+ if l.lstrip()=='':
+ emptyLine=True
+ elif l.strip()[0]=='#':
+ emptyLine=True
+ else: # otherwise, check the indentation...
+ emptyLine=False
+ if newIndent and currentIndentation>indentNumber[-1]:
+ newIndent=False
+ indentNumber.append(currentIndentation)
+ elif lspContinuation:
+ pass
+ elif not newIndent and currentIndentation in indentNumber:
+ while currentIndentation<indentNumber[-1]:
+ indentNumber.pop() # This is the end of an indentation block
+ elif not ignoreErrors:
+ #print 'Invalid Indentation!!'
+ return ['Invalid Indentation Error',i]
+
+ firstWord = re.match(' *\w*',l).group().lstrip()
+ if firstWord in ['if','else','elif','for','while',
+ 'def','class','try','except','finally']:
+ hasContinuationWord = True
+ else:
+ hasContinuationWord = False
+
+
+ commented=False
+ nonCommentLength=len(l)
+
+ result = re.finditer('"""'+'|'+"'''" + r'''|"|'|\"|\'|\(|\)|\[|\]|\{|\}|#''',l)
+ for r in result:
+ j = r.group()
+
+ if stringMark == None:
+ if j=='#': # If it is a legitimate comment, ignore everything after
+ commented=True
+ # get length up to last non-comment character
+ nonCommentLength = r.start()
+ break
+ elif j in stringMarks:
+ stringMark=j
+ else:
+ if paraList != [] and j in closeMarks:
+ if paraMarkDict[paraList[-1]]==j:
+ paraList.pop()
+ elif not ignoreErrors:
+ #print 'Invalid Syntax!!'
+ return ['Invalid Syntax Error',i]
+ if j in openMarks:
+ paraList.append(j)
+ elif stringMark==j:
+ stringMark=None
+
+ stringContinuationList.append(stringMark!=None)
+
+ indentationBlockList.append(False)
+ nonCommentString = l[:nonCommentLength].rstrip()
+ if nonCommentString!='' and stringContinuationList[-1]==False:
+ if nonCommentString[-1]==':':
+ indentationBlockList[-1]=True
+ newIndent=True
+
+ lineContinuationList.append(False)
+ if len(l)>0 and not commented:
+ if l[-1]=='\\':
+ lineContinuationList[-1]=True
+
+ parentheticalContinuationList.append( paraList != [] )
+
+ # Now stringContinuationList (et al) is line by line key for magic
+ # telling it whether or not each next line is part of a string continuation
+
+ if (stringContinuationList[-1] or indentationBlockList[-1] or \
+ lineContinuationList[-1] or parentheticalContinuationList[-1]) \
+ and not ignoreErrors:
+ #print 'Incomplete Syntax!!'
+ return ['Incomplete Syntax Error',i]
+
+ if newIndent and not ignoreErrors:
+ #print 'Incomplete Indentation!'
+ return ['Incomplete Indentation Error',i]
+
+ # Note that if one of these errors above gets thrown, the best solution is to pass the resulting block
+ # to the interpreter as exec instead of interp
+ return stringContinuationList,indentationBlockList,lineContinuationList,parentheticalContinuationList
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/path.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/path.py
new file mode 100644
index 0000000..ccc8177
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/path.py
@@ -0,0 +1,36 @@
+"""path.py is a utility containing some very simple path utilities for Py to use"""
+
+__author__ = "David N. Mashburn <david.n.mashburn@gmail.com>"
+# 07/01/2009
+
+import os
+import glob
+import commands
+
+def pwd():
+ print os.getcwd()
+
+def cd(path,usePrint=True):
+ os.chdir(os.path.expandvars(os.path.expanduser(path)))
+ if usePrint:
+ pwd()
+
+def ls(str='*',fullpath=False):
+ g=glob.glob(os.path.expandvars(os.path.expanduser(str)))
+ if fullpath:
+ for i in g:
+ print i
+ else:
+ for i in g:
+ print os.path.split(i)[1]
+
+# This prints the results of running a command in the GUI shell but be warned!
+# This is a blocking call, and if you open any kind of interactive
+# command-line program like python or bash, the shell will permanantly
+# freeze!
+# If you want this kind of behavior to be available, please use ipython
+# This is NOT a feature or goal of the Py project!
+def sx(str=''):
+ print commands.getoutput(str)
+
+#cd('~',usePrint=False)
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/pseudo.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/pseudo.py
new file mode 100644
index 0000000..482be6c
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/pseudo.py
@@ -0,0 +1,101 @@
+"""Provides a variety of classes to create pseudo keywords and pseudo files."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+
+class PseudoKeyword:
+ """A callable class that calls a method passed as a parameter.
+
+ Good for creating a pseudo keyword in the python runtime
+ environment. The keyword is really an object that has a repr()
+ that calls itself which calls the method that was passed in the
+ init of the object. All this just to avoid having to type in the
+ closing parens on a method. So, for example:
+
+ >>> quit = PseudoKeyword(SomeObject.someMethod)
+ >>> quit
+
+ SomeObject.someMethod gets executed as if it had been called
+ directly and the user didn't have to type the parens, like
+ 'quit()'. This technique is most applicable for pseudo keywords
+ like quit, exit and help.
+
+ If SomeObject.someMethod can take parameters, they can still be
+ passed by using the keyword in the traditional way with parens."""
+
+ def __init__(self, method):
+ """Create a callable object that executes method when called."""
+
+ if callable(method):
+ self.method = method
+ else:
+ raise ValueError, 'method must be callable'
+
+ def __call__(self, *args, **kwds):
+ self.method(*args, **kwds)
+
+ def __repr__(self):
+ self()
+ return ''
+
+
+class PseudoFile:
+
+ def __init__(self):
+ """Create a file-like object."""
+ pass
+
+ def readline(self):
+ pass
+
+ def write(self, s):
+ pass
+
+ def writelines(self, l):
+ map(self.write, l)
+
+ def flush(self):
+ pass
+
+ def isatty(self):
+ pass
+
+
+class PseudoFileIn(PseudoFile):
+
+ def __init__(self, readline, readlines=None):
+ if callable(readline):
+ self.readline = readline
+ else:
+ raise ValueError, 'readline must be callable'
+ if callable(readlines):
+ self.readlines = readlines
+
+ def isatty(self):
+ return 1
+
+
+class PseudoFileOut(PseudoFile):
+
+ def __init__(self, write):
+ if callable(write):
+ self.write = write
+ else:
+ raise ValueError, 'write must be callable'
+
+ def isatty(self):
+ return 1
+
+
+class PseudoFileErr(PseudoFile):
+
+ def __init__(self, write):
+ if callable(write):
+ self.write = write
+ else:
+ raise ValueError, 'write must be callable'
+
+ def isatty(self):
+ return 1
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/shell.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/shell.py
new file mode 100644
index 0000000..1009f6a
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/shell.py
@@ -0,0 +1,1575 @@
+"""Shell is an interactive text control in which a user types in
+commands to be sent to the interpreter. This particular shell is
+based on wxPython's wxStyledTextCtrl.
+
+Sponsored by Orbtech - Your source for Python programming expertise."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import stc
+
+import keyword
+import os
+import sys
+import time
+
+from buffer import Buffer
+import dispatcher
+import editwindow
+import frame
+from pseudo import PseudoFileIn
+from pseudo import PseudoFileOut
+from pseudo import PseudoFileErr
+from version import VERSION
+from magic import magic
+from path import ls,cd,pwd,sx
+
+sys.ps3 = '<-- ' # Input prompt.
+USE_MAGIC=True
+# Force updates from long-running commands after this many seconds
+PRINT_UPDATE_MAX_TIME=2
+
+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, frame.ShellFrameMixin):
+ """Frame containing the shell component."""
+
+ name = 'Shell Frame'
+ revision = __revision__
+
+ def __init__(self, parent=None, id=-1, title='PyShell',
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_FRAME_STYLE, locals=None,
+ 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
+ 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.
+ if self.shell.waiting:
+ if event.CanVeto():
+ event.Veto(True)
+ else:
+ self.SaveSettings()
+ self.shell.destroy()
+ self.Destroy()
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PyShell'
+ text = 'PyShell %s\n\n' % VERSION + \
+ 'Yet another Python shell, only flakier.\n\n' + \
+ 'Half-baked by Patrick K. O\'Brien,\n' + \
+ 'the other half is still in the oven.\n\n' + \
+ 'Shell Revision: %s\n' % self.shell.revision + \
+ 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
+ '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:]))
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+
+ def OnHelp(self, event):
+ """Show a help dialog."""
+ frame.ShellFrameMixin.OnHelp(self, event)
+
+
+ def LoadSettings(self):
+ if self.config is not None:
+ frame.ShellFrameMixin.LoadSettings(self)
+ frame.Frame.LoadSettings(self, self.config)
+ self.shell.LoadSettings(self.config)
+
+ def SaveSettings(self, force=False):
+ if self.config is not None:
+ frame.ShellFrameMixin.SaveSettings(self)
+ if self.autoSaveSettings or force:
+ frame.Frame.SaveSettings(self, self.config)
+ self.shell.SaveSettings(self.config)
+
+ def DoSaveSettings(self):
+ if self.config is not None:
+ self.SaveSettings(force=True)
+ self.config.Flush()
+
+
+
+
+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.
+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.
+Ctrl+Up Arrow Retrieve Previous History item.
+Alt+P Retrieve Previous History item.
+Ctrl+Down Arrow Retrieve Next History item.
+Alt+N Retrieve Next History item.
+Shift+Up Arrow Insert Previous History item.
+Shift+Down Arrow Insert Next History item.
+F8 Command-completion of History item.
+ (Type a few characters of a previous command and press F8.)
+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.
+Shift+Enter Complete Text from History.
+Ctrl+F Search
+F3 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
+ d['this'] = other.this
+
+ def help(self):
+ """Display some useful information about how to use the shell."""
+ self.write(self.helpText)
+
+ def __getattr__(self, name):
+ if hasattr(self.other, name):
+ return getattr(self.other, name)
+ else:
+ raise AttributeError, name
+
+ def __setattr__(self, name, value):
+ if self.__dict__.has_key(name):
+ self.__dict__[name] = value
+ elif hasattr(self.other, name):
+ setattr(self.other, name, value)
+ else:
+ raise AttributeError, name
+
+ def _getAttributeNames(self):
+ """Return list of magic attributes to extend introspection."""
+ list = [
+ 'about',
+ 'ask',
+ 'autoCallTip',
+ 'autoComplete',
+ 'autoCompleteAutoHide',
+ 'autoCompleteCaseInsensitive',
+ 'autoCompleteIncludeDouble',
+ 'autoCompleteIncludeMagic',
+ 'autoCompleteIncludeSingle',
+ 'callTipInsert',
+ 'clear',
+ 'pause',
+ 'prompt',
+ 'quit',
+ 'redirectStderr',
+ 'redirectStdin',
+ 'redirectStdout',
+ 'run',
+ 'runfile',
+ 'wrap',
+ 'zoom',
+ ]
+ list.sort()
+ return list
+
+
+#DNM
+DISPLAY_TEXT="""
+Author: %r
+Py Version: %s
+Py Shell Revision: %s
+Py Interpreter Revision: %s
+Python Version: %s
+wxPython Version: %s
+wxPython PlatformInfo: %s
+Platform: %s"""
+
+class Shell(editwindow.EditWindow):
+ """Shell based on StyledTextCtrl."""
+
+ name = 'Shell'
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
+ 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,
+ stdin=self.reader,
+ 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
+
+ # For use with forced updates during long-running scripts
+ self.lastUpdate=None
+
+ # 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
+ # gets incremented as you retrieve the previous command,
+ # decremented as you retrieve the next, and reset when you hit
+ # Enter. self.historyIndex == -1 means you're on the current
+ # 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.
+ self.Bind(wx.EVT_CHAR, self.OnChar)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+
+ # Assign handler for the context menu
+ self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
+ self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI)
+
+ # Assign handlers for edit events
+ self.Bind(wx.EVT_MENU, lambda evt: self.Cut(), id=wx.ID_CUT)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Copy(), id=wx.ID_COPY)
+ self.Bind(wx.EVT_MENU, lambda evt: self.CopyWithPrompts(), id=frame.ID_COPY_PLUS)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Paste(), id=wx.ID_PASTE)
+ self.Bind(wx.EVT_MENU, lambda evt: self.PasteAndRun(), id=frame.ID_PASTE_PLUS)
+ self.Bind(wx.EVT_MENU, lambda evt: self.SelectAll(), id=wx.ID_SELECTALL)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Clear(), id=wx.ID_CLEAR)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Undo(), id=wx.ID_UNDO)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Redo(), id=wx.ID_REDO)
+
+
+ # Assign handler for idle time.
+ self.waiting = False
+ 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.
+ if execStartupScript:
+ if startupScript is None:
+ startupScript = os.environ.get('PYTHONSTARTUP')
+ self.execStartupScript(startupScript)
+ else:
+ self.prompt()
+
+ wx.CallAfter(self.ScrollToLine, 0)
+
+
+ def clearHistory(self):
+ self.history = []
+ self.historyIndex = -1
+ dispatcher.send(signal="Shell.clearHistory")
+
+
+ def destroy(self):
+ del self.interp
+
+ def setFocus(self):
+ """Set focus to the shell."""
+ self.SetFocus()
+
+ def OnIdle(self, event):
+ """Free the CPU to do other things."""
+ if self.waiting:
+ time.sleep(0.05)
+ event.Skip()
+
+ def showIntro(self, text=''):
+ """Display introductory text in the shell."""
+ if text:
+ self.write(text)
+ try:
+ if self.interp.introText:
+ if text and not text.endswith(os.linesep):
+ self.write(os.linesep)
+ self.write(self.interp.introText)
+ except AttributeError:
+ pass
+
+ def setBuiltinKeywords(self):
+ """Create pseudo keywords as part of builtins.
+
+ This sets "close", "exit" and "quit" to a helpful string.
+ """
+ import __builtin__
+ __builtin__.close = __builtin__.exit = __builtin__.quit = \
+ 'Click on the close button to leave the application.'
+ __builtin__.cd = cd
+ __builtin__.ls = ls
+ __builtin__.pwd = pwd
+ __builtin__.sx = sx
+
+
+ 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."""
+ #DNM
+ text = DISPLAY_TEXT % \
+ (__author__, VERSION, self.revision, self.interp.revision,
+ 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():
+ return
+ key = event.GetKeyCode()
+ currpos = self.GetCurrentPos()
+ stoppos = self.promptPosEnd
+ # Return (Enter) needs to be ignored in this handler.
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ pass
+ elif key in self.autoCompleteKeys:
+ # Usually the dot (period) key activates auto completion.
+ # Get the command between the prompt and the cursor. Add
+ # the autocomplete character to the end of the command.
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ command = self.GetTextRange(stoppos, currpos) + chr(key)
+ self.write(chr(key))
+ if self.autoComplete:
+ self.autoCompleteShow(command)
+ elif key == ord('('):
+ # The left paren activates a call tip and cancels an
+ # active auto completion.
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ # Get the command between the prompt and the cursor. Add
+ # the '(' to the end of the command.
+ self.ReplaceSelection('')
+ command = self.GetTextRange(stoppos, currpos) + '('
+ self.write('(')
+ 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."""
+
+ key = event.GetKeyCode()
+ # If the auto-complete window is up let it do its thing.
+ if self.AutoCompActive():
+ event.Skip()
+ return
+
+ # Prevent modification of previously submitted
+ # commands/responses.
+ controlDown = event.ControlDown()
+ rawControlDown = event.RawControlDown()
+ altDown = event.AltDown()
+ shiftDown = event.ShiftDown()
+ currpos = self.GetCurrentPos()
+ endpos = self.GetTextLength()
+ selecting = self.GetSelectionStart() != self.GetSelectionEnd()
+
+ if (rawControlDown or controlDown) and shiftDown and key in (ord('F'), ord('f')):
+ 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)
+ # select reappearing text to allow "hide again"
+ self.SetSelection( startP, endP )
+ return
+ startP,endP = self.GetSelection()
+ endP-=1
+ startL = self.LineFromPosition(startP)
+ endL = self.LineFromPosition(endP)
+
+ # never hide last prompt
+ if endL == self.LineFromPosition(self.promptPosEnd):
+ 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 (rawControlDown or controlDown) and not shiftDown and not altDown) and \
+ key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ if self.CallTipActive():
+ self.CallTipCancel()
+ self.processLine()
+
+ # Complete Text (from already typed words)
+ elif shiftDown and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ self.OnShowCompHistory()
+
+ # Ctrl+Return (Ctrl+Enter) is used to insert a line break.
+ elif (rawControlDown or controlDown) and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ if self.CallTipActive():
+ self.CallTipCancel()
+ if currpos == endpos:
+ self.processLine()
+ else:
+ self.insertLineBreak()
+
+ # Let Ctrl-Alt-* get handled normally.
+ elif (rawControlDown or controlDown) and altDown:
+ event.Skip()
+
+ # Clear the current, unexecuted command.
+ elif key == wx.WXK_ESCAPE:
+ if self.CallTipActive():
+ event.Skip()
+ else:
+ self.clearCommand()
+
+ # Clear the current command
+ elif key == wx.WXK_BACK and (rawControlDown or controlDown) and shiftDown:
+ self.clearCommand()
+
+ # Increase font size.
+ elif (rawControlDown or controlDown) and key in (ord(']'), wx.WXK_NUMPAD_ADD):
+ dispatcher.send(signal='FontIncrease')
+
+ # Decrease font size.
+ elif (rawControlDown or controlDown) and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
+ dispatcher.send(signal='FontDecrease')
+
+ # Default font size.
+ elif (rawControlDown or controlDown) and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
+ dispatcher.send(signal='FontDefault')
+
+ # Cut to the clipboard.
+ elif ((rawControlDown or controlDown) and key in (ord('X'), ord('x'))) \
+ or (shiftDown and key == wx.WXK_DELETE):
+ self.Cut()
+
+ # Copy to the clipboard.
+ elif (rawControlDown or controlDown) and not shiftDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.Copy()
+
+ # Copy to the clipboard, including prompts.
+ elif (rawControlDown or controlDown) and shiftDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.CopyWithPrompts()
+
+ # Copy to the clipboard, including prefixed prompts.
+ elif altDown and not controlDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.CopyWithPromptsPrefixed()
+
+ # Home needs to be aware of the prompt.
+ elif (rawControlDown or controlDown) and key == wx.WXK_HOME:
+ home = self.promptPosEnd
+ if currpos > home:
+ self.SetCurrentPos(home)
+ if not selecting and not shiftDown:
+ self.SetAnchor(home)
+ self.EnsureCaretVisible()
+ else:
+ event.Skip()
+
+ # Home needs to be aware of the prompt.
+ elif key == wx.WXK_HOME:
+ home = self.promptPosEnd
+ if currpos > home:
+ [line_str,line_len] = self.GetCurLine()
+ pos=self.GetCurrentPos()
+ if line_str[:4] in [sys.ps1,sys.ps2,sys.ps3]:
+ self.SetCurrentPos(pos+4-line_len)
+ #self.SetCurrentPos(home)
+ if not selecting and not shiftDown:
+ self.SetAnchor(pos+4-line_len)
+ self.EnsureCaretVisible()
+ else:
+ event.Skip()
+ else:
+ event.Skip()
+
+ #
+ # The following handlers modify text, so we need to see if
+ # there is a selection that includes text prior to the prompt.
+ #
+ # Don't modify a selection with text prior to the prompt.
+ elif selecting and key not in NAVKEYS and not self.CanEdit():
+ pass
+
+ # Paste from the clipboard.
+ elif ((rawControlDown or controlDown) and not shiftDown and key in (ord('V'), ord('v'))) \
+ or (shiftDown and not controlDown and key == wx.WXK_INSERT):
+ self.Paste()
+
+ # manually invoke AutoComplete and Calltips
+ elif (rawControlDown or controlDown) and key == wx.WXK_SPACE:
+ self.OnCallTipAutoCompleteManually(shiftDown)
+
+ # Paste from the clipboard, run commands.
+ elif (rawControlDown or controlDown) and shiftDown and key in (ord('V'), ord('v')):
+ self.PasteAndRun()
+
+ # Replace with the previous command from the history buffer.
+ elif ((rawControlDown or controlDown) and not shiftDown and key == wx.WXK_UP) \
+ or (altDown and key in (ord('P'), ord('p'))):
+ self.OnHistoryReplace(step=+1)
+
+ # Replace with the next command from the history buffer.
+ elif ((rawControlDown or controlDown) and not shiftDown and key == wx.WXK_DOWN) \
+ or (altDown and key in (ord('N'), ord('n'))):
+ self.OnHistoryReplace(step=-1)
+
+ # Insert the previous command from the history buffer.
+ elif ((rawControlDown or controlDown) and shiftDown and key == wx.WXK_UP) and self.CanEdit():
+ self.OnHistoryInsert(step=+1)
+
+ # Insert the next command from the history buffer.
+ elif ((rawControlDown or controlDown) and shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
+ self.OnHistoryInsert(step=-1)
+
+ # Search up the history for the text in front of the cursor.
+ elif key == wx.WXK_F8:
+ self.OnHistorySearch()
+
+ # Don't backspace over the latest non-continuation prompt.
+ elif key == wx.WXK_BACK:
+ if selecting and self.CanEdit():
+ event.Skip()
+ elif currpos > self.promptPosEnd:
+ event.Skip()
+
+ # Only allow these keys after the latest prompt.
+ elif key in (wx.WXK_TAB, wx.WXK_DELETE):
+ if self.CanEdit():
+ event.Skip()
+
+ # Don't toggle between insert mode and overwrite mode.
+ elif key == wx.WXK_INSERT:
+ pass
+
+ # Don't allow line deletion.
+ elif controlDown and key in (ord('L'), ord('l')):
+ # TODO : Allow line deletion eventually...
+ #event.Skip()
+ pass
+
+ # Don't allow line transposition.
+ elif controlDown and key in (ord('T'), ord('t')):
+ # TODO : Allow line transposition eventually...
+ # TODO : Will have to adjust markers accordingly and test if allowed...
+ #event.Skip()
+ pass
+
+ # Basic navigation keys should work anywhere.
+ elif key in NAVKEYS:
+ event.Skip()
+
+ # Protect the readonly portion of the shell.
+ elif not self.CanEdit():
+ pass
+
+ 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
+ endpos = self.GetTextLength()
+ self.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+ self.more = False
+
+ def OnHistoryReplace(self, step):
+ """Replace with the previous/next command from the history buffer."""
+ self.clearCommand()
+ self.replaceFromHistory(step)
+
+ def replaceFromHistory(self, step):
+ """Replace selection with command from the history buffer."""
+ ps2 = str(sys.ps2)
+ self.ReplaceSelection('')
+ newindex = self.historyIndex + step
+ if -1 <= newindex <= len(self.history):
+ self.historyIndex = newindex
+ if 0 <= newindex <= len(self.history)-1:
+ command = self.history[self.historyIndex]
+ command = command.replace('\n', os.linesep + ps2)
+ self.ReplaceSelection(command)
+
+ def OnHistoryInsert(self, step):
+ """Insert the previous/next command from the history buffer."""
+ if not self.CanEdit():
+ return
+ startpos = self.GetCurrentPos()
+ self.replaceFromHistory(step)
+ endpos = self.GetCurrentPos()
+ self.SetSelection(endpos, startpos)
+
+ def OnHistorySearch(self):
+ """Search up the history buffer for the text in front of the cursor."""
+ if not self.CanEdit():
+ return
+ startpos = self.GetCurrentPos()
+ # The text up to the cursor is what we search for.
+ numCharsAfterCursor = self.GetTextLength() - startpos
+ searchText = self.getCommand(rstrip=False)
+ if numCharsAfterCursor > 0:
+ searchText = searchText[:-numCharsAfterCursor]
+ if not searchText:
+ return
+ # Search upwards from the current history position and loop
+ # back to the beginning if we don't find anything.
+ if (self.historyIndex <= -1) \
+ or (self.historyIndex >= len(self.history)-2):
+ searchOrder = range(len(self.history))
+ else:
+ searchOrder = range(self.historyIndex+1, len(self.history)) + \
+ range(self.historyIndex)
+ for i in searchOrder:
+ command = self.history[i]
+ if command[:len(searchText)] == searchText:
+ # Replace the current selection with the one we found.
+ self.ReplaceSelection(command[len(searchText):])
+ endpos = self.GetCurrentPos()
+ self.SetSelection(endpos, startpos)
+ # We've now warped into middle of the history.
+ self.historyIndex = i
+ break
+
+ def setStatusText(self, text):
+ """Display status information."""
+
+ # This method will likely be replaced by the enclosing app to
+ # do something more interesting, like write to a status bar.
+ print text
+
+ def insertLineBreak(self):
+ """Insert a new line break."""
+ if self.CanEdit():
+ self.write(os.linesep)
+ self.more = True
+ self.prompt()
+
+ def processLine(self):
+ """Process the line of text at which the user hit Enter."""
+
+ # The user hit ENTER and we need to decide what to do. They
+ # could be sitting on any line in the shell.
+
+ thepos = self.GetCurrentPos()
+ startpos = self.promptPosEnd
+ endpos = self.GetTextLength()
+ ps2 = str(sys.ps2)
+ # If they hit RETURN inside the current command, execute the
+ # command.
+ if self.CanEdit():
+ self.SetCurrentPos(endpos)
+ self.interp.more = False
+ command = self.GetTextRange(startpos, endpos)
+ lines = command.split(os.linesep + ps2)
+ lines = [line.rstrip() for line in lines]
+ command = '\n'.join(lines)
+ if self.reader.isreading:
+ if not command:
+ # Match the behavior of the standard Python shell
+ # when the user hits return without entering a
+ # value.
+ command = '\n'
+ self.reader.input = command
+ 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).
+ if self.getCommand(rstrip=False):
+ command = self.getMultilineCommand()
+ self.clearCommand()
+ self.write(command)
+ # Otherwise, put the cursor back where we started.
+ else:
+ self.SetCurrentPos(thepos)
+ self.SetAnchor(thepos)
+
+ def getMultilineCommand(self, rstrip=True):
+ """Extract a multi-line command from the editor.
+
+ The command may not necessarily be valid Python syntax."""
+ # XXX Need to extract real prompts here. Need to keep track of
+ # the prompt every time a command is issued.
+ ps1 = str(sys.ps1)
+ ps1size = len(ps1)
+ ps2 = str(sys.ps2)
+ ps2size = len(ps2)
+ # This is a total hack job, but it works.
+ text = self.GetCurLine()[0]
+ line = self.GetCurrentLine()
+ while text[:ps2size] == ps2 and line > 0:
+ line -= 1
+ self.GotoLine(line)
+ text = self.GetCurLine()[0]
+ if text[:ps1size] == ps1:
+ line = self.GetCurrentLine()
+ self.GotoLine(line)
+ startpos = self.GetCurrentPos() + ps1size
+ line += 1
+ self.GotoLine(line)
+ while self.GetCurLine()[0][:ps2size] == ps2:
+ line += 1
+ self.GotoLine(line)
+ stoppos = self.GetCurrentPos()
+ command = self.GetTextRange(startpos, stoppos)
+ command = command.replace(os.linesep + ps2, '\n')
+ command = command.rstrip()
+ command = command.replace('\n', os.linesep + ps2)
+ else:
+ command = ''
+ if rstrip:
+ command = command.rstrip()
+ return command
+
+ def getCommand(self, text=None, rstrip=True):
+ """Extract a command from text which may include a shell prompt.
+
+ The command may not necessarily be valid Python syntax."""
+ if not text:
+ text = self.GetCurLine()[0]
+ # Strip the prompt off the front leaving just the command.
+ command = self.lstripPrompt(text)
+ if command == text:
+ command = '' # Real commands have prompts.
+ if rstrip:
+ command = command.rstrip()
+ return command
+
+ def lstripPrompt(self, text):
+ """Return text without a leading prompt."""
+ ps1 = str(sys.ps1)
+ ps1size = len(ps1)
+ ps2 = str(sys.ps2)
+ ps2size = len(ps2)
+ # Strip the prompt off the front of text.
+ if text[:ps1size] == ps1:
+ text = text[ps1size:]
+ elif text[:ps2size] == ps2:
+ text = text[ps2size:]
+ return text
+
+ def push(self, command, silent = False):
+ """Send command to the interpreter for execution."""
+ if not silent:
+ self.write(os.linesep)
+
+ #DNM
+ if USE_MAGIC:
+ command=magic(command)
+
+ busy = wx.BusyCursor()
+ self.waiting = True
+ self.lastUpdate=None
+ self.more = self.interp.push(command)
+ self.lastUpdate=None
+ self.waiting = False
+ del busy
+ if not self.more:
+ self.addHistory(command.rstrip())
+ if not silent:
+ self.prompt()
+
+ def addHistory(self, command):
+ """Add command to the command history."""
+ # Reset the history position.
+ self.historyIndex = -1
+ # Insert this command into the history, unless it's a blank
+ # line or the same as the last command.
+ if command != '' \
+ and (len(self.history) == 0 or command != self.history[0]):
+ self.history.insert(0, command)
+ dispatcher.send(signal="Shell.addHistory", command=command)
+
+ def write(self, text):
+ """Display text in the shell.
+
+ Replace line endings with OS-specific endings."""
+ text = self.fixLineEndings(text)
+ self.AddText(text)
+ self.EnsureCaretVisible()
+
+ if self.waiting:
+ if self.lastUpdate==None:
+ self.lastUpdate=time.time()
+ if time.time()-self.lastUpdate > PRINT_UPDATE_MAX_TIME:
+ self.Update()
+ self.lastUpdate=time.time()
+
+ def fixLineEndings(self, text):
+ """Return text with line endings replaced by OS-specific endings."""
+ lines = text.split('\r\n')
+ for l in range(len(lines)):
+ chunks = lines[l].split('\r')
+ for c in range(len(chunks)):
+ chunks[c] = os.linesep.join(chunks[c].split('\n'))
+ lines[l] = os.linesep.join(chunks)
+ text = os.linesep.join(lines)
+ return text
+
+ def prompt(self):
+ """Display proper prompt for the context: ps1, ps2 or ps3.
+
+ If this is a continuation line, autoindent as necessary."""
+ isreading = self.reader.isreading
+ skip = False
+ if isreading:
+ prompt = str(sys.ps3)
+ elif self.more:
+ prompt = str(sys.ps2)
+ else:
+ prompt = str(sys.ps1)
+ pos = self.GetCurLine()[1]
+ if pos > 0:
+ if isreading:
+ skip = True
+ else:
+ self.write(os.linesep)
+ if not self.more:
+ self.promptPosStart = self.GetCurrentPos()
+ if not skip:
+ self.write(prompt)
+ if not self.more:
+ self.promptPosEnd = self.GetCurrentPos()
+ # Keep the undo feature from undoing previous responses.
+ self.EmptyUndoBuffer()
+
+ if self.more:
+ line_num=self.GetCurrentLine()
+ currentLine=self.GetLine(line_num)
+ previousLine=self.GetLine(line_num-1)[len(prompt):]
+ pstrip=previousLine.strip()
+ lstrip=previousLine.lstrip()
+
+ # Get the first alnum word:
+ first_word=[]
+ for i in pstrip:
+ if i.isalnum():
+ first_word.append(i)
+ else:
+ break
+ first_word = ''.join(first_word)
+
+ if pstrip == '':
+ # because it is all whitespace!
+ indent=previousLine.strip('\n').strip('\r')
+ else:
+ indent=previousLine[:(len(previousLine)-len(lstrip))]
+ if pstrip[-1]==':' and \
+ first_word in ['if','else','elif','for','while',
+ 'def','class','try','except','finally']:
+ indent+=' '*4
+
+ self.write(indent)
+ self.EnsureCaretVisible()
+ self.ScrollToColumn(0)
+
+ def readline(self):
+ """Replacement for stdin.readline()."""
+ input = ''
+ reader = self.reader
+ reader.isreading = True
+ self.prompt()
+ try:
+ while not reader.input:
+ wx.YieldIfNeeded()
+ input = reader.input
+ finally:
+ reader.input = ''
+ reader.isreading = False
+ input = str(input) # In case of Unicode.
+ return input
+
+ def readlines(self):
+ """Replacement for stdin.readlines()."""
+ lines = []
+ while lines[-1:] != ['\n']:
+ lines.append(self.readline())
+ return lines
+
+ def raw_input(self, prompt=''):
+ """Return string based on user input."""
+ if prompt:
+ self.write(prompt)
+ return self.readline()
+
+ def ask(self, prompt='Please enter your response:'):
+ """Get response from the user using a dialog box."""
+ dialog = wx.TextEntryDialog(None, prompt,
+ 'Input Dialog (Raw)', '')
+ try:
+ if dialog.ShowModal() == wx.ID_OK:
+ text = dialog.GetValue()
+ return text
+ finally:
+ dialog.Destroy()
+ return ''
+
+ def pause(self):
+ """Halt execution pending a response from the user."""
+ self.ask('Press enter to continue:')
+
+ def clear(self):
+ """Delete all text from the shell."""
+ self.ClearAll()
+
+ def run(self, command, prompt=True, verbose=True):
+ """Execute command as if it was typed in directly.
+ >>> shell.run('print "this"')
+ >>> print "this"
+ this
+ >>>
+ """
+ # Go to the very bottom of the text.
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ command = command.rstrip()
+ if prompt: self.prompt()
+ if verbose: self.write(command)
+ self.push(command)
+
+ def runfile(self, filename):
+ """Execute all commands in file as if they were typed into the
+ shell."""
+ file = open(filename)
+ try:
+ self.prompt()
+ for command in file.readlines():
+ if command[:6] == 'shell.':
+ # Run shell methods silently.
+ self.run(command, prompt=False, verbose=False)
+ else:
+ self.run(command, prompt=False, verbose=True)
+ finally:
+ file.close()
+
+ def autoCompleteShow(self, command, offset = 0):
+ """Display auto-completion popup list."""
+ self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
+ self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+ list = self.interp.getAutoCompleteList(command,
+ includeMagic=self.autoCompleteIncludeMagic,
+ includeSingle=self.autoCompleteIncludeSingle,
+ includeDouble=self.autoCompleteIncludeDouble)
+ if list:
+ options = ' '.join(list)
+ #offset = 0
+ self.AutoCompShow(offset, options)
+
+ 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 and not forceCallTip:
+ return
+ startpos = self.GetCurrentPos()
+ if argspec and insertcalltip and self.callTipInsert:
+ self.write(argspec + ')')
+ endpos = self.GetCurrentPos()
+ self.SetSelection(startpos, endpos)
+ if tip:
+ tippos = startpos - (len(name) + 1)
+ fallback = startpos - self.GetColumn(startpos)
+ # In case there isn't enough room, only go back to the
+ # 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."""
+ self.write(text)
+
+ def writeErr(self, text):
+ """Replacement for stderr."""
+ self.write(text)
+
+ def redirectStdin(self, redirect=True):
+ """If redirect is true then sys.stdin will come from the shell."""
+ if redirect:
+ sys.stdin = self.reader
+ else:
+ sys.stdin = self.stdin
+
+ def redirectStdout(self, redirect=True):
+ """If redirect is true then sys.stdout will go to the shell."""
+ if redirect:
+ sys.stdout = PseudoFileOut(self.writeOut)
+ else:
+ sys.stdout = self.stdout
+
+ def redirectStderr(self, redirect=True):
+ """If redirect is true then sys.stderr will go to the shell."""
+ if redirect:
+ sys.stderr = PseudoFileErr(self.writeErr)
+ else:
+ sys.stderr = self.stderr
+
+ def CanCut(self):
+ """Return true if text is selected and can be cut."""
+ if self.GetSelectionStart() != self.GetSelectionEnd() \
+ and self.GetSelectionStart() >= self.promptPosEnd \
+ and self.GetSelectionEnd() >= self.promptPosEnd:
+ return True
+ else:
+ return False
+
+ def CanPaste(self):
+ """Return true if a paste should succeed."""
+ if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
+ return True
+ else:
+ return False
+
+ def CanEdit(self):
+ """Return true if editing should succeed."""
+ if self.GetSelectionStart() != self.GetSelectionEnd():
+ if self.GetSelectionStart() >= self.promptPosEnd \
+ and self.GetSelectionEnd() >= self.promptPosEnd:
+ return True
+ else:
+ return False
+ else:
+ return self.GetCurrentPos() >= self.promptPosEnd
+
+ def Cut(self):
+ """Remove selection and place it on the clipboard."""
+ if self.CanCut() and self.CanCopy():
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ if self.CallTipActive():
+ self.CallTipCancel()
+ self.Copy()
+ self.ReplaceSelection('')
+
+ def Copy(self):
+ """Copy selection and place it on the clipboard."""
+ if self.CanCopy():
+ ps1 = str(sys.ps1)
+ ps2 = str(sys.ps2)
+ command = self.GetSelectedText()
+ command = command.replace(os.linesep + ps2, os.linesep)
+ command = command.replace(os.linesep + ps1, os.linesep)
+ command = self.lstripPrompt(text=command)
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def CopyWithPrompts(self):
+ """Copy selection, including prompts, and place it on the clipboard."""
+ if self.CanCopy():
+ command = self.GetSelectedText()
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def CopyWithPromptsPrefixed(self):
+ """Copy selection, including prompts prefixed with four
+ spaces, and place it on the clipboard."""
+ if self.CanCopy():
+ command = self.GetSelectedText()
+ spaces = ' ' * 4
+ command = spaces + command.replace(os.linesep,
+ os.linesep + spaces)
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def _clip(self, data):
+ if wx.TheClipboard.Open():
+ wx.TheClipboard.UsePrimarySelection(False)
+ wx.TheClipboard.SetData(data)
+ wx.TheClipboard.Flush()
+ wx.TheClipboard.Close()
+
+ def Paste(self):
+ """Replace selection with clipboard contents."""
+ if self.CanPaste() and wx.TheClipboard.Open():
+ ps2 = str(sys.ps2)
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+ data = wx.TextDataObject()
+ if wx.TheClipboard.GetData(data):
+ self.ReplaceSelection('')
+ command = data.GetText()
+ command = command.rstrip()
+ command = self.fixLineEndings(command)
+ command = self.lstripPrompt(text=command)
+ command = command.replace(os.linesep + ps2, '\n')
+ command = command.replace(os.linesep, '\n')
+ command = command.replace('\n', os.linesep + ps2)
+ self.write(command)
+ wx.TheClipboard.Close()
+
+
+ def PasteAndRun(self):
+ """Replace selection with clipboard contents, run commands."""
+ text = ''
+ if wx.TheClipboard.Open():
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+ data = wx.TextDataObject()
+ if wx.TheClipboard.GetData(data):
+ text = data.GetText()
+ wx.TheClipboard.Close()
+ if text:
+ self.Execute(text)
+
+
+ def Execute(self, text):
+ """Replace selection with text and run commands."""
+ ps1 = str(sys.ps1)
+ ps2 = str(sys.ps2)
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ startpos = self.promptPosEnd
+ self.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+ text = text.lstrip()
+ text = self.fixLineEndings(text)
+ text = self.lstripPrompt(text)
+ text = text.replace(os.linesep + ps1, '\n')
+ text = text.replace(os.linesep + ps2, '\n')
+ text = text.replace(os.linesep, '\n')
+ lines = text.split('\n')
+ commands = []
+ command = ''
+ for line in lines:
+ if line.strip() == ps2.strip():
+ # If we are pasting from something like a
+ # web page that drops the trailing space
+ # from the ps2 prompt of a blank line.
+ line = ''
+ lstrip = line.lstrip()
+ if line.strip() != '' and lstrip == line and \
+ lstrip[:4] not in ['else','elif'] and \
+ lstrip[:6] != 'except':
+ # New command.
+ if command:
+ # Add the previous command to the list.
+ commands.append(command)
+ # Start a new command, which may be multiline.
+ command = line
+ else:
+ # Multiline command. Add to the command.
+ command += '\n'
+ command += line
+ commands.append(command)
+ for command in commands:
+ command = command.replace('\n', os.linesep + ps2)
+ self.write(command)
+ self.processLine()
+
+
+ def wrap(self, wrap=True):
+ """Sets whether text is word wrapped."""
+ try:
+ self.SetWrapMode(wrap)
+ except AttributeError:
+ return 'Wrapping is not available in this version.'
+
+ def zoom(self, points=0):
+ """Set the zoom level.
+
+ 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))
+
+ 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('View/WrapMode', self.GetWrapMode())
+ config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
+ config.WriteInt('View/Zoom/Shell', self.GetZoom())
+
+ def GetContextMenu(self):
+ """
+ Create and return a context menu for the shell.
+ This is used instead of the scintilla default menu
+ in order to correctly respect our immutable buffer.
+ """
+ menu = wx.Menu()
+ menu.Append(wx.ID_UNDO, "Undo")
+ menu.Append(wx.ID_REDO, "Redo")
+
+ menu.AppendSeparator()
+
+ menu.Append(wx.ID_CUT, "Cut")
+ menu.Append(wx.ID_COPY, "Copy")
+ menu.Append(frame.ID_COPY_PLUS, "Copy Plus")
+ menu.Append(wx.ID_PASTE, "Paste")
+ menu.Append(frame.ID_PASTE_PLUS, "Paste Plus")
+ menu.Append(wx.ID_CLEAR, "Clear")
+
+ menu.AppendSeparator()
+
+ menu.Append(wx.ID_SELECTALL, "Select All")
+ return menu
+
+ def OnContextMenu(self, evt):
+ menu = self.GetContextMenu()
+ self.PopupMenu(menu)
+
+ def OnUpdateUI(self, evt):
+ id = evt.Id
+ if id in (wx.ID_CUT, wx.ID_CLEAR):
+ evt.Enable(self.CanCut())
+ elif id in (wx.ID_COPY, frame.ID_COPY_PLUS):
+ evt.Enable(self.CanCopy())
+ elif id in (wx.ID_PASTE, frame.ID_PASTE_PLUS):
+ evt.Enable(self.CanPaste())
+ elif id == wx.ID_UNDO:
+ evt.Enable(self.CanUndo())
+ elif id == wx.ID_REDO:
+ evt.Enable(self.CanRedo())
+
+
+
+
+## NOTE: The DnD of file names is disabled until we 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
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/sliceshell.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/sliceshell.py
new file mode 100644
index 0000000..437fce7
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/sliceshell.py
@@ -0,0 +1,3789 @@
+"""Slices is an interactive text control in which a user types in
+commands to be sent to the interpreter. This particular shell is
+based on wxPython's wxStyledTextCtrl.
+
+Sponsored by Orbtech - Your source for Python programming expertise.
+Slices is a version of shell modified by David Mashburn."""
+
+__author__ = "David N. Mashburn <david.n.mashburn@gmail.com> / "
+__author__ += "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id: sliceshell.py 60100 2009-04-12 02:56:29Z RD $"
+__revision__ = "$Revision: 60100 $"[11:-2]
+
+import wx
+from wx import stc
+
+import keyword
+import os
+import sys
+import time
+
+from buffer import Buffer
+import dispatcher
+import editor
+import editwindow
+import document
+import frame
+from pseudo import PseudoFileIn
+from pseudo import PseudoFileOut
+from pseudo import PseudoFileErr
+from version import VERSION
+from magic import magic
+from parse import testForContinuations
+from path import ls,cd,pwd,sx
+
+
+sys.ps3 = '<-- ' # Input prompt.
+USE_MAGIC=True
+# Force updates from long-running commands after this many seconds
+PRINT_UPDATE_MAX_TIME=2
+
+NAVKEYS = (wx.WXK_HOME, wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
+ wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
+
+GROUPING_SELECTING=0
+IO_SELECTING = 1
+
+GROUPING_START = 2
+GROUPING_START_FOLDED = 3
+GROUPING_MIDDLE = 4
+GROUPING_END = 5
+INPUT_START = 6
+INPUT_START_FOLDED = 7
+INPUT_MIDDLE = 8
+INPUT_END = 9
+OUTPUT_START = 10
+OUTPUT_START_FOLDED = 11
+OUTPUT_MIDDLE = 12
+OUTPUT_END = 13
+
+OUTPUT_BG = 14
+READLINE_BG = 15
+INPUT_READLINE = 16
+
+# Could add C integration right into the markers...
+# Non-editable file marker for auto-loaded files...
+# Weave VariableInput = 15
+# Weave C code = 16
+# C code = 17 (only for use with Pyrex)
+# Pyrex / Cython code = 18
+
+GROUPING_MASK = ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED |
+ 1<<GROUPING_MIDDLE | 1<<GROUPING_END )
+
+INPUT_MASK = ( 1<<INPUT_START | 1<<INPUT_START_FOLDED |
+ 1<<INPUT_MIDDLE | 1<<INPUT_END )
+OUTPUT_MASK = ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED |
+ 1<<OUTPUT_MIDDLE | 1<<OUTPUT_END )
+IO_MASK = ( INPUT_MASK | OUTPUT_MASK )
+
+IO_START_MASK = ( 1<<INPUT_START | 1<<OUTPUT_START )
+IO_START_FOLDED_MASK = ( 1<<INPUT_START_FOLDED | 1<<OUTPUT_START_FOLDED )
+IO_ANY_START_MASK = ( 1<<INPUT_START | 1<<OUTPUT_START |
+ 1<<INPUT_START_FOLDED | 1<<OUTPUT_START_FOLDED )
+IO_MIDDLE_MASK = ( 1<<INPUT_MIDDLE | 1<<OUTPUT_MIDDLE )
+IO_END_MASK = ( 1<<INPUT_END | 1<<OUTPUT_END )
+
+usrBinEnvPythonText = '#!/usr/bin/env python2\n'
+pyslicesFormatHeaderText = ['#PySlices Save Format Version 1.1 (PySlices v0.9.7.8 and later)\n',
+ '#PySlices Save Format Version 1.2 (PySlices v0.9.8 and later)\n']
+groupingStartText = '#PySlices Marker Information -- Begin Grouping Slice\n'
+inputStartText = '#PySlices Marker Information -- Begin Input Slice\n'
+outputStartText = '#PySlices Marker Information -- Begin Output Slice\n'
+
+tutorialText = """
+
+ Tutorial!!!
+------------------------------------------------------------------------
+PySlices is the newest member of the Py suite!
+It is a modified version of PyCrust that supports multi-line commands.
+
+Input and output are contained in "Slices" shown as markers in the left margin.
+Input Slices have RED margins (active, editable).
+Output Slices have BLUE margins (frozen, not editable).
+
+Commands in slices can be on more than one line, as with Sage or Mathematica.
+For example, the command:
+a=1
+b=2
+print a+b
+will all run in sequence, much like a script.
+Try running the above Input Slice by clicking somewhere in its text and
+using Ctrl-Return, Shift-Return, or Numpad Enter to execute.
+Previous commands (Old Slices) can be re-edited and run again in place.
+
+Slices can also be:
+ * selceted (click on the margin, Shift-click for multiple selection)
+ * folded (click the margin twice)
+ * selected and deleted (hit delete while selected)
+ * divided (Ctrl-D)
+ * merged (Ctrl-M while selecting adjacent, like-colored slices)
+
+Try deleting the slice above this one by clicking on the red margin.
+
+If you want a more traditional shell feel, try enabling "Shell Mode" in
+"Options->Settings->Shell Mode" (or try PyCrust).
+In Shell Mode, two returns in a row executes the command, and
+ Ctrl-Return and Shift-Return always print newlines.
+
+Saving and opening "sessions" is now supported! This is a little
+different to other shells where the history is saved. With PySlices,
+the whole document is saved in a simple text format!
+
+To disable this Tutorial on startup, uncheck it in the menu at:
+"Options->Startup->Show PySlices tutorial"
+
+PySlices may not be the best thing since sliced bread, but
+I hope it makes using Python a little bit sweeter!
+"""
+
+class SlicesShellFrame(frame.Frame, frame.ShellFrameMixin):
+ """Frame containing the sliceshell component."""
+
+ name = 'SlicesShell Frame'
+ revision = __revision__
+
+ def __init__(self, parent=None, id=-1, title='PySlicesShell',
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_FRAME_STYLE, locals=None,
+ InterpClass=None,
+ config=None, dataDir=None, filename=None,
+ *args, **kwds):
+ """Create SlicesShellFrame instance."""
+ frame.Frame.__init__(self, parent, id, title, pos, size, style,shellName='PySlices')
+ frame.ShellFrameMixin.__init__(self, config, dataDir)
+
+ if size == wx.DefaultSize:
+ self.SetSize((750, 525))
+
+ intro = 'PySlices %s - The Flakiest Python Shell... Cut Up!' % VERSION
+ self.SetStatusText(intro.replace('\n', ', '))
+ self.sliceshell = SlicesShell(parent=self, id=-1, introText=intro,
+ locals=locals, InterpClass=InterpClass,
+ startupScript=self.startupScript,
+ execStartupScript=self.execStartupScript,
+ showPySlicesTutorial=self.showPySlicesTutorial,
+ enableShellMode=self.enableShellMode,
+ hideFoldingMargin=self.hideFoldingMargin,
+ *args, **kwds)
+ self.buffer = self.sliceshell.buffer
+
+ # Override the shell so that status messages go to the status bar.
+ self.sliceshell.setStatusText = self.SetStatusText
+
+ self.sliceshell.SetFocus()
+ self.LoadSettings()
+
+ self.currentDirectory = os.path.expanduser('~')
+
+ if filename!=None:
+ self.bufferOpen(filename)
+
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+
+ def OnClose(self, event):
+ """Event handler for closing."""
+ self.bufferClose()
+ # This isn't working the way I want, but I'll leave it for now.
+ #if self.sliceshell.waiting:
+ # if event.CanVeto():
+ # event.Veto(True)
+ #else:
+ # # TODO: Add check for saving
+ # self.SaveSettings()
+ # self.sliceshell.destroy()
+ # self.Destroy()
+
+ def OnAbout(self, event):
+ """Display an About window."""
+ title = 'About PySliceShell'
+ text = 'PySliceShell %s\n\n' % VERSION + \
+ 'Yet another Python shell, only flakier.\n\n' + \
+ 'Half-baked by Patrick K. O\'Brien,\n' + \
+ 'the other half is still in the oven.\n\n' + \
+ 'Shell Revision: %s\n' % self.shell.revision + \
+ 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
+ '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:]))
+ dialog = wx.MessageDialog(self, text, title,
+ wx.OK | wx.ICON_INFORMATION)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+
+ def OnHelp(self, event):
+ """Show a help dialog."""
+ frame.ShellFrameMixin.OnHelp(self, event)
+
+
+ def LoadSettings(self):
+ if self.config is not None:
+ frame.ShellFrameMixin.LoadSettings(self)
+ frame.Frame.LoadSettings(self, self.config)
+ self.sliceshell.LoadSettings(self.config)
+
+ def SaveSettings(self, force=False):
+ if self.config is not None:
+ frame.ShellFrameMixin.SaveSettings(self,force)
+ if self.autoSaveSettings or force:
+ frame.Frame.SaveSettings(self, self.config)
+ self.sliceshell.SaveSettings(self.config)
+
+ def DoSaveSettings(self):
+ if self.config is not None:
+ self.SaveSettings(force=True)
+ self.config.Flush()
+
+ def OnEnableShellMode(self,event):
+ """Change between Slices Mode and Shell Mode"""
+ frame.Frame.OnEnableShellMode(self,event)
+ self.sliceshell.ToggleShellMode(self.enableShellMode)
+
+ def OnHideFoldingMargin(self,event):
+ """Change between Slices Mode and Shell Mode"""
+ frame.Frame.OnHideFoldingMargin(self,event)
+ self.sliceshell.ToggleFoldingMargin(self.hideFoldingMargin)
+ # Copied Straight from crustslices.py (update both with any changes...)
+ # Stolen Straight from editor.EditorFrame
+ # Modified a little... :)
+ # ||
+ # \/
+ def OnIdle(self, event):
+ """Event handler for idle time."""
+ self._updateTitle()
+ event.Skip()
+
+ def _updateTitle(self):
+ """Show current title information."""
+ title = self.GetTitle()
+ if self.bufferHasChanged():
+ if title.startswith('* '):
+ pass
+ else:
+ self.SetTitle('* ' + title)
+ else:
+ if title.startswith('* '):
+ self.SetTitle(title[2:])
+
+ def hasBuffer(self):
+ """Return True if there is a current buffer."""
+ if self.buffer:
+ return True
+ else:
+ return False
+
+ def bufferClose(self):
+ """Close buffer."""
+ if self.buffer.hasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ #event.Veto()
+ return cancel
+ self.SaveSettings()
+ self.sliceshell.destroy()
+ self.bufferDestroy()
+ self.Destroy()
+
+ return False
+
+ def bufferCreate(self, filename=None):
+ """Create new buffer."""
+ self.bufferDestroy()
+ buffer = Buffer()
+ self.panel = panel = wx.Panel(parent=self, id=-1)
+ panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
+ editor = Editor(parent=panel)
+ panel.editor = editor
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(editor.window, 1, wx.EXPAND)
+ panel.SetSizer(sizer)
+ panel.SetAutoLayout(True)
+ sizer.Layout()
+ buffer.addEditor(editor)
+ buffer.open(filename)
+ self.setEditor(editor)
+ self.editor.setFocus()
+ self.SendSizeEvent()
+
+
+ def bufferDestroy(self):
+ """Destroy the current buffer."""
+ if self.buffer:
+ self.editor = None
+ self.buffer = None
+
+
+ def bufferHasChanged(self):
+ """Return True if buffer has changed since last save."""
+ if self.buffer:
+ return self.buffer.hasChanged()
+ else:
+ return False
+
+ def bufferNew(self):
+ """Create new buffer."""
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ #self.bufferCreate()
+ self.clear()
+ self.SetTitle( 'PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+ self.sliceshell.SetSavePoint()
+ self.buffer.doc = document.Document()
+ self.buffer.name = 'This shell'
+ self.buffer.modulename = self.buffer.doc.filebase
+ cancel = False
+ return cancel
+
+ def bufferOpen(self,file=None):
+ """Open file in buffer."""
+ if self.bufferHasChanged():
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+
+ if file==None:
+ file=wx.FileSelector('Open a PySlices File',
+ wildcard='*.pyslices',
+ default_path=self.currentDirectory)
+ if file!=None and file!=u'':
+ fid=open(file,'r')
+ self.sliceshell.LoadPySlicesFile(fid)
+ fid.close()
+ self.currentDirectory = os.path.split(file)[0]
+ self.SetTitle( os.path.split(file)[1] + ' - PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+ self.sliceshell.SetSavePoint()
+ self.buffer.doc = document.Document(file)
+ self.buffer.name = self.buffer.doc.filename
+ self.buffer.modulename = self.buffer.doc.filebase
+ self.sliceshell.ScrollToLine(0)
+ return
+
+## def bufferPrint(self):
+## """Print buffer."""
+## pass
+
+## def bufferRevert(self):
+## """Revert buffer to version of file on disk."""
+## pass
+
+ # was self.buffer.save(self): # """Save buffer."""
+ def simpleSave(self,confirmed=False):
+ filepath = self.buffer.doc.filepath
+ self.buffer.confirmed = confirmed
+ if not filepath:
+ return # XXX Get filename
+ if not os.path.exists(filepath):
+ self.buffer.confirmed = True
+ if not self.buffer.confirmed:
+ self.buffer.confirmed = self.buffer.overwriteConfirm(filepath)
+ if self.buffer.confirmed:
+ try:
+ fid = open(filepath, 'wb')
+ self.sliceshell.SavePySlicesFile(fid)
+ finally:
+ if fid:
+ fid.close()
+ self.sliceshell.SetSavePoint()
+ self.SetTitle( os.path.split(filepath)[1] + ' - PySlices')
+ self.sliceshell.NeedsCheckForSave=False
+
+ def bufferSave(self):
+ """Save buffer to its file."""
+ if self.buffer.doc.filepath:
+ # self.buffer.save()
+ self.simpleSave(confirmed=True)
+ cancel = False
+ else:
+ cancel = self.bufferSaveAs()
+ return cancel
+
+ def bufferSaveAs(self):
+ """Save buffer to a new filename."""
+ if self.bufferHasChanged() and self.buffer.doc.filepath:
+ cancel = self.bufferSuggestSave()
+ if cancel:
+ return cancel
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = editor.saveSingle(title='Save PySlices File',directory=filedir,
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
+ if result.path not in ['',None]:
+ if result.path[-9:]!=".pyslices":
+ result.path+=".pyslices"
+
+ self.buffer.doc = document.Document(result.path)
+ self.buffer.name = self.buffer.doc.filename
+ self.buffer.modulename = self.buffer.doc.filebase
+ self.simpleSave(confirmed=True) # allow overwrite
+ cancel = False
+ else:
+ cancel = True
+ return cancel
+
+ def bufferSaveACopy(self):
+ """Save buffer to a new filename."""
+ filedir = ''
+ if self.buffer and self.buffer.doc.filedir:
+ filedir = self.buffer.doc.filedir
+ result = editor.saveSingle(title='Save a Copy of PySlices File',directory=filedir,
+ wildcard='PySlices Files (*.pyslices)|*.pyslices')
+
+ if result.path not in ['',None]:
+ if result.path[-9:]!=".pyslices":
+ result.path+=".pyslices"
+
+ # if not os.path.exists(result.path):
+ try: # Allow overwrite...
+ fid = open(result.path, 'wb')
+ self.sliceshell.SavePySlicesFile(fid)
+ finally:
+ if fid:
+ fid.close()
+
+ cancel = False
+ else:
+ cancel = True
+ return cancel
+
+ def bufferSuggestSave(self):
+ """Suggest saving changes. Return True if user selected Cancel."""
+ result = editor.messageDialog(parent=None,
+ message='%s has changed.\n'
+ 'Would you like to save it first'
+ '?' % self.buffer.name,
+ title='Save current file?',
+ style=wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT |
+ wx.CENTRE | wx.ICON_QUESTION )
+ if result.positive:
+ cancel = self.bufferSave()
+ else:
+ cancel = result.text == 'Cancel'
+ return cancel
+
+ def updateNamespace(self):
+ """Update the buffer namespace for autocompletion and calltips."""
+ if self.buffer.updateNamespace():
+ self.SetStatusText('Namespace updated')
+ else:
+ self.SetStatusText('Error executing, unable to update namespace')
+
+
+
+# TODO : Update the help text
+HELP_TEXT = """\
+* Key bindings:
+Home Go to the beginning of the line.
+End Go to the end of the line.
+Shift+Home Select to the beginning of the line.
+Shift+End Select to the end of the line.
+Ctrl-Home Jump to the beginning of the slice;
+ If already there, jump to beginning of previous slice
+Ctrl-End Jump to the end of the slice;
+ If already there, jump to end of next slice
+Ctrl-PageUp Jump to the beginning of the shell
+Ctrl-PageDown Jump to the end of the shell
+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.
+Ctrl+Up Arrow Retrieve Previous History item.
+Alt+P Retrieve Previous History item.
+Ctrl+Down Arrow Retrieve Next History item.
+Alt+N Retrieve Next History item.
+Shift+Up Arrow Insert Previous History item.
+Shift+Down Arrow Insert Next History item.
+F8 Command-completion of History item.
+ (Type a few characters of a previous command and press F8.)
+Ctrl+] Increase font size.
+Ctrl+[ Decrease font size.
+Ctrl+= Default font size.
+
+Ctrl-Space Show Auto Completion.
+Ctrl-Shift-Space Show Call Tip.
+Ctrl-Shift-H Complete Text from History.
+
+Ctrl+F Search
+Ctrl+G Search next
+F12 on/off "free-edit" mode
+ For testing only -- This does not preserve markers!
+
+In "Slices Mode":
+Return Insert new line
+Enter (Numpad) Run command in slice
+Ctrl+Return ""
+Shift+Return ""
+
+In "Shell Mode":
+Return or Enter Insert a new line
+Ctrl+Return ""
+Shift+Return ""
+2 Returns in a row Run command in slice
+"""
+
+class SlicesShellFacade:
+ """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 = 'SlicesShell Interface'
+ revision = __revision__
+
+ def __init__(self, other):
+ """Create a SlicesShellFacade instance."""
+ d = self.__dict__
+ d['other'] = other
+ d['helpText'] = HELP_TEXT
+ d['this'] = other.this
+
+ def help(self):
+ """Display some useful information about how to use the slices shell."""
+ self.write(self.helpText,type='Output')
+
+ def __getattr__(self, name):
+ if hasattr(self.other, name):
+ return getattr(self.other, name)
+ else:
+ raise AttributeError, name
+
+ def __setattr__(self, name, value):
+ if self.__dict__.has_key(name):
+ self.__dict__[name] = value
+ elif hasattr(self.other, name):
+ setattr(self.other, name, value)
+ else:
+ raise AttributeError, name
+
+ def _getAttributeNames(self):
+ """Return list of magic attributes to extend introspection."""
+ list = [
+ 'about',
+ 'ask',
+ 'autoCallTip',
+ 'autoComplete',
+ 'autoCompleteAutoHide',
+ 'autoCompleteCaseInsensitive',
+ 'autoCompleteIncludeDouble',
+ 'autoCompleteIncludeMagic',
+ 'autoCompleteIncludeSingle',
+ 'callTipInsert',
+ 'clear',
+ 'pause',
+ 'prompt',
+ 'quit',
+ 'redirectStderr',
+ 'redirectStdin',
+ 'redirectStdout',
+ 'run',
+ 'runfile',
+ 'wrap',
+ 'zoom',
+ ]
+ list.sort()
+ return list
+
+DISPLAY_TEXT="""
+Author: %r
+Py Version: %s
+Py Slices Shell Revision: %s
+Py Interpreter Revision: %s
+Python Version: %s
+wxPython Version: %s
+wxPython PlatformInfo: %s
+Platform: %s"""
+
+class SlicesShell(editwindow.EditWindow):
+ """Notebook Shell based on StyledTextCtrl."""
+
+ name = 'SlicesShell'
+ revision = __revision__
+
+ def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
+ introText='', locals=None, InterpClass=None,
+ startupScript=None, execStartupScript=True,
+ showPySlicesTutorial=True,enableShellMode=False,
+ hideFoldingMargin=False, *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,
+ stdin=self.reader,
+ stdout=PseudoFileOut(self.writeOut),
+ stderr=PseudoFileErr(self.writeErr),
+ *args, **kwds)
+
+ # Set up the buffer.
+ self.buffer = Buffer()
+ self.id = self.GetId()
+ self.buffer.addEditor(self)
+ self.buffer.name='This shell'
+ self.NeedsCheckForSave=False
+
+ # Find out for which keycodes the interpreter will autocomplete.
+ self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
+
+ # Keep track of the last non-continuation prompt positions.
+ # Removed all references to these... solved a lot of odd bugs...
+ # self.promptPosStart = 0
+ # self.promptPosEnd = 0
+
+ # Keep track of multi-line commands.
+ self.more = False
+
+ # Use Margins to track input / output / slice number
+ self.margins = True
+
+ # For use with forced updates during long-running scripts
+ self.lastUpdate=None
+
+ if self.margins:
+ # margin 1 is already defined for the line numbers
+ # may eventually change it back to 0 like it ought to be...
+ self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+ self.SetMarginType(3, stc.STC_MARGIN_SYMBOL)
+ self.SetMarginType(4, stc.STC_MARGIN_SYMBOL)
+ self.SetMarginWidth(2, 22)
+ self.SetMarginWidth(3, 22)
+ self.SetMarginWidth(4, 12)
+ self.SetMarginSensitive(2,True)
+ self.SetMarginSensitive(3,True)
+ self.SetMarginSensitive(4,True)
+ self.SetProperty("fold", "1")
+ # tabs are bad, use spaces
+ self.SetProperty("tab.timmy.whinge.level", "4")
+ self.SetMargins(0,0)
+
+
+ self.SetMarginMask(2, GROUPING_MASK | 1<<GROUPING_SELECTING )
+ # Display Markers -24...
+ self.SetMarginMask(3, IO_MASK | 1<<IO_SELECTING | 1<<READLINE_BG | 1<<INPUT_READLINE )
+ self.SetMarginMask(4, stc.STC_MASK_FOLDERS)
+ # Set the mask for the line markers, too...
+ self.SetMarginMask(1, 0)
+
+ if hideFoldingMargin:
+ self.SetMarginWidth(4, 0)
+ self.hideFoldingMargin=hideFoldingMargin
+
+ sel_color="#E0E0E0"
+ grouping_color="black"
+ input_color="red"
+ output_color="blue"
+
+ self.MarkerDefine(GROUPING_SELECTING, stc.STC_MARK_FULLRECT,
+ sel_color, sel_color)
+ self.MarkerDefine(IO_SELECTING, stc.STC_MARK_FULLRECT,
+ sel_color, sel_color)
+
+ self.MarkerDefine(GROUPING_START, stc.STC_MARK_BOXMINUS,
+ "white", grouping_color)
+ self.MarkerDefine(GROUPING_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", grouping_color)
+ self.MarkerDefine(GROUPING_MIDDLE, stc.STC_MARK_VLINE,
+ "white", grouping_color)
+ self.MarkerDefine(GROUPING_END, stc.STC_MARK_LCORNER,
+ "white", grouping_color)
+
+ self.MarkerDefine(READLINE_BG, stc.STC_MARK_FULLRECT,
+ wx.Colour(191,191,191), wx.Colour(191,191,191))
+ self.MarkerDefine(INPUT_READLINE, stc.STC_MARK_CHARACTER+ord('<'),
+ input_color, wx.Colour(191,191,191))
+
+ if enableShellMode:
+ self.mode='ShellMode'
+ else:
+ self.mode='SlicesMode'
+
+ self.execOnNextReturn=False
+ if self.mode=='SlicesMode':
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_BOXMINUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_VLINE,
+ "white", input_color)
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_LCORNER,
+ "white", input_color)
+ elif self.mode=='ShellMode':
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_ARROWS,
+ input_color, "white")
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_DOTDOTDOT,
+ input_color, "white")
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_DOTDOTDOT,
+ input_color, "white")
+
+ self.MarkerDefine(OUTPUT_START, stc.STC_MARK_BOXMINUS,
+ "white", output_color)
+ self.MarkerDefine(OUTPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", output_color)
+ self.MarkerDefine(OUTPUT_MIDDLE, stc.STC_MARK_VLINE,
+ "white", output_color)
+ self.MarkerDefine(OUTPUT_END, stc.STC_MARK_LCORNER,
+ "white", output_color)
+
+ self.MarkerDefine(OUTPUT_BG, stc.STC_MARK_BACKGROUND,
+ "white", wx.Colour(242,242,255))
+
+ # Markers for folding margin...
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED,
+ "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,
+ "white", "#808080")
+
+ # 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
+ # gets incremented as you retrieve the previous command,
+ # decremented as you retrieve the next, and reset when you hit
+ # Enter. self.historyIndex == -1 means you're on the current
+ # command, not in the history.
+ self.history = []
+ self.historyIndex = -1
+
+ #DNM -- disable these markers...
+ #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.
+ self.Bind(wx.EVT_CHAR, self.OnChar)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+
+ self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
+ # TODO : Add a general functions to handle mouse clicks in the
+ # TODO: STC window whose sole purpose is to make it so
+ # TODO: that margin selection becomes unselected...
+
+ # Assign handler for the context menu
+ self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
+ self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI)
+
+ # Assign handlers for edit events
+ self.Bind(wx.EVT_MENU, lambda evt: self.Cut(), id=wx.ID_CUT)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Copy(), id=wx.ID_COPY)
+ self.Bind(wx.EVT_MENU, lambda evt: self.CopyWithPrompts(), id=frame.ID_COPY_PLUS)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Paste(), id=wx.ID_PASTE)
+ self.Bind(wx.EVT_MENU, lambda evt: self.PasteAndRun(), id=frame.ID_PASTE_PLUS)
+ self.Bind(wx.EVT_MENU, lambda evt: self.SelectAll(), id=wx.ID_SELECTALL)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Clear(), id=wx.ID_CLEAR)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Undo(), id=wx.ID_UNDO)
+ self.Bind(wx.EVT_MENU, lambda evt: self.Redo(), id=wx.ID_REDO)
+
+ # Assign handler for idle time.
+ self.waiting = False
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+ # Display the introductory banner information.
+ self.showIntro(introText)
+
+ outStart,outEnd,inStart,inMiddle,inEnd = [[],[],[],[],[]]
+
+ # Make "executed startup script move to the top..."
+ if showPySlicesTutorial:
+ self.write(tutorialText,'Output')
+ tutStart=5
+ testStart=16
+ outStart=[tutStart,testStart+3]
+ outEnd=[tutStart-1,testStart-1]
+ inStart=[testStart]
+ inMiddle=[testStart+1]
+ inEnd=[testStart+2]
+
+ # Assign some pseudo keywords to the interpreter's namespace.
+ self.setBuiltinKeywords()
+
+ # Add 'shell' to the interpreter's local namespace.
+ self.setLocalShell()
+
+ # Do this last so the user has complete control over their
+ # environment. They can override anything they want.
+ if execStartupScript:
+ if startupScript is None:
+ startupScript = os.environ.get('PYTHONSTARTUP')
+ self.execStartupScript(startupScript)
+ else:
+ self.prompt()
+
+ outStart+=[0]
+ outEnd+=[self.GetLineCount()-2]
+ inStart+=[self.GetLineCount()-1]
+ # Set all the line markers to the proper initial states...
+ for i in range(self.GetLineCount()):
+ self.clearGroupingMarkers(i)
+ self.clearIOMarkers(i)
+ if i in outStart:
+ self.MarkerAdd(i,GROUPING_START)
+ self.MarkerAdd(i,OUTPUT_START)
+ # Background color is confusing for tutorial... skip it!
+ #self.MarkerAdd(i,OUTPUT_BG)
+ elif i in outEnd:
+ self.MarkerAdd(i,GROUPING_END)
+ self.MarkerAdd(i,OUTPUT_END)
+ #self.MarkerAdd(i,OUTPUT_BG)
+ elif i in inStart:
+ self.MarkerAdd(i,GROUPING_START)
+ self.MarkerAdd(i,INPUT_START)
+ elif i in inMiddle:
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+ self.MarkerAdd(i,INPUT_MIDDLE)
+ elif i in inEnd:
+ self.MarkerAdd(i,GROUPING_END)
+ self.MarkerAdd(i,INPUT_END)
+ else:
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
+ #self.MarkerAdd(i,OUTPUT_BG)
+
+ self.SliceSelection=False
+ self.runningSlice=None
+
+ ## NOTE: See note at bottom of this file...
+ ## #seb: File drag and drop
+ ## self.SetDropTarget( FileDropTarget(self) )
+
+ #ADD UNDO
+ # Everywhere "ADD UNDO" appears, there is new code to handle markers
+ self.EmptyUndoBuffer()
+
+ wx.CallAfter(self.ScrollToLine, 0)
+
+ def ToggleShellMode(self,enableShellMode=None):
+ if enableShellMode==None:
+ if self.mode=='ShellMode': self.mode='SlicesMode'
+ elif self.mode=='SlicesMode': self.mode='ShellMode'
+ elif enableShellMode:
+ self.mode='ShellMode'
+ else:
+ self.mode='SlicesMode'
+
+ input_color="red"
+ if self.mode=='SlicesMode':
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_BOXMINUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_VLINE,
+ "white", input_color)
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_LCORNER,
+ "white", input_color)
+ elif self.mode=='ShellMode':
+ self.MarkerDefine(INPUT_START, stc.STC_MARK_ARROWS,
+ input_color, "white")
+ self.MarkerDefine(INPUT_START_FOLDED, stc.STC_MARK_BOXPLUS,
+ "white", input_color)
+ self.MarkerDefine(INPUT_MIDDLE, stc.STC_MARK_DOTDOTDOT,
+ input_color, "white")
+ self.MarkerDefine(INPUT_END, stc.STC_MARK_DOTDOTDOT,
+ input_color, "white")
+
+ def ToggleFoldingMargin(self,hideFoldingMargin=None):
+ if hideFoldingMargin==None:
+ self.hideFoldingMargin = not self.hideFoldingMargin
+ else:
+ self.hideFoldingMargin = hideFoldingMargin
+
+ if self.hideFoldingMargin:
+ self.SetMarginWidth(4, 0)
+ else:
+ self.SetMarginWidth(4, 12)
+
+ def clearHistory(self):
+ self.history = []
+ self.historyIndex = -1
+ dispatcher.send(signal="SlicesShell.clearHistory")
+
+
+ def destroy(self):
+ del self.interp
+
+ def setFocus(self):
+ """Set focus to the slices shell."""
+ self.SetFocus()
+
+ def OnIdle(self, event):
+ """Free the CPU to do other things."""
+ if self.waiting:
+ time.sleep(0.05)
+ event.Skip()
+
+ def showIntro(self, text=''):
+ """Display introductory text in the slices shell."""
+ if text:
+ self.write(text,type='Output')
+ try:
+ if self.interp.introText:
+ if text and not text.endswith(os.linesep):
+ self.write(os.linesep,type='Output')
+ self.write(self.interp.introText,type='Output')
+ except AttributeError:
+ pass
+
+ def setBuiltinKeywords(self):
+ """Create pseudo keywords as part of builtins.
+
+ This sets "close", "exit" and "quit" to a helpful string.
+ """
+ import __builtin__
+ __builtin__.close = __builtin__.exit = __builtin__.quit = \
+ 'Click on the close button to leave the application.'
+ __builtin__.cd = cd
+ __builtin__.ls = ls
+ __builtin__.pwd = pwd
+ __builtin__.sx = sx
+
+
+ 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.',
+ type='Output')
+
+
+ def setLocalShell(self):
+ """Add 'slicesshell' to locals as reference to ShellFacade instance."""
+ self.interp.locals['slicesshell'] = SlicesShellFacade(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 = DISPLAY_TEXT % \
+ (__author__, VERSION, self.revision, self.interp.revision,
+ sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
+ sys.platform)
+ self.write(text.strip(),type='Output')
+
+ def BreakTextIntoCommands(self,text):
+ """Turn a text block into multiple multi-line commands."""
+
+ #text = text.lstrip() # This should not be done!
+ text = self.fixLineEndings(text)
+ text = self.lstripPrompt(text)
+ text = text.replace(os.linesep, '\n')
+ lines = text.split('\n')
+
+ continuations = testForContinuations(text)
+
+ if len(continuations)==2: # Error case...
+ return None,continuations[1]
+ elif len(continuations)==4:
+ stringContinuationList,indentationBlockList, \
+ lineContinuationList,parentheticalContinuationList = continuations
+
+ commands = []
+ command = ''
+ for j,line in enumerate(lines):
+ lstrip = line.lstrip()
+
+ # Get the first alnum word:
+ first_word=[]
+ for i in lstrip:
+ if i.isalnum():
+ first_word.append(i)
+ else:
+ break
+ first_word = ''.join(first_word)
+
+ # Continue the command if it is blank, has indentation,
+ # starts with else, elif,except, or finally
+ # or previous line had a line continuation \
+
+ if j==0:
+ stringCont = False
+ lineCont=False
+ else:
+ stringCont = stringContinuationList[j-1]
+ lineCont = lineContinuationList[j-1]
+
+ if line.strip() == '' or lstrip != line or \
+ first_word in ['else','elif','except','finally'] or \
+ stringCont or lineCont:
+ # Multiline command. Add to the command.
+ command += '\n'
+ command += line
+ else:
+ # New command.
+ if command:
+ # Add the previous command to the list.
+ commands.append(command)
+ # Start a new command, which may be multiline.
+ command = line
+
+ commands.append(command)
+
+ return commands
+
+ def MarkerSet(self,line,markerBitsSet):
+ """MarkerSet is the Set command for MarkerGet"""
+ markerBits=self.MarkerGet(line)
+
+ numMarkers=14
+ for i in range(numMarkers):
+ if (markerBitsSet & (1<<i)) and not (markerBits & (1<<i)):
+ self.MarkerAdd(line,i)
+ elif not (markerBitsSet & (1<<i)) and (markerBits & (1<<i)):
+ self.MarkerDelete(line,i)
+ def GetGroupingSlice(self,line_num=None):
+ """Get the start/stop lines for the slice based on any line in the slice"""
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ num_lines=self.GetLineCount()
+
+ for i in range(line_num,-1,-1):
+ if self.MarkerGet(i) & (1<<GROUPING_START | 1<<GROUPING_START_FOLDED):
+ break
+ start_line=i
+
+ addition=0
+
+ for i in range(line_num,num_lines):
+ if self.MarkerGet(i) & 1<<GROUPING_END:
+ break
+ elif (i>line_num) and ( self.MarkerGet(i)
+ & (1<<GROUPING_START | 1<<GROUPING_START_FOLDED) ):
+ addition=-1
+ break # the solo case...
+ stop_line=i+addition
+
+ return start_line,stop_line
+
+ def GetIOSlice(self,line_num=None):
+ """Get the start/stop lines for the slice based on any line in the slice"""
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ num_lines=self.GetLineCount()
+
+ for i in range(line_num,-1,-1):
+ if self.MarkerGet(i) & IO_ANY_START_MASK:
+ break
+ start_line=i
+
+ addition=0
+
+ for i in range(line_num,num_lines):
+ if self.MarkerGet(i) & IO_END_MASK:
+ break
+ elif (i>line_num) and (self.MarkerGet(i) & IO_ANY_START_MASK):
+ addition=-1
+ break # the solo case...
+ stop_line=i+addition
+
+ return start_line,stop_line
+
+ def FoldGroupingSlice(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ start,end=self.GetGroupingSlice(line_num)
+ self.HideLines(start+1,end)
+ marker=self.MarkerGet(start)
+ self.clearGroupingMarkers(start)
+ self.MarkerAdd(start,GROUPING_START_FOLDED)
+ self.clearIOMarkers(start)
+ if marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
+ self.MarkerAdd(start,INPUT_START_FOLDED)
+ elif marker & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
+ self.MarkerAdd(start,OUTPUT_START_FOLDED)
+ self.MarkerAdd(start,OUTPUT_BG)
+ else:
+ pass #print 'Bad Markers!!!'
+ def FoldIOSlice(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ start,end=self.GetIOSlice(line_num)
+ self.HideLines(start+1,end)
+ marker=self.MarkerGet(start)
+ if (self.MarkerGet(start) & \
+ (1<<GROUPING_START | 1<<GROUPING_START_FOLDED )) and \
+ (self.MarkerGet(end) & 1<<GROUPING_END):
+ self.clearGroupingMarkers(start)
+ self.MarkerAdd(start,GROUPING_START_FOLDED)
+ self.clearIOMarkers(start)
+ if marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
+ self.MarkerAdd(start,INPUT_START_FOLDED)
+ elif marker & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
+ self.MarkerAdd(start,OUTPUT_START_FOLDED)
+ self.MarkerAdd(start,OUTPUT_BG)
+ else:
+ pass #print 'Bad Markers!!!'
+ def UnFoldGroupingSlice(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ start,end=self.GetGroupingSlice(line_num)
+ self.ShowLines(start+1,end)
+ self.clearGroupingMarkers(start)
+ self.MarkerAdd(start,GROUPING_START)
+ for i in range(start,end):
+ marker=self.MarkerGet(i)
+ if marker & (1<<INPUT_START | 1<<INPUT_START_FOLDED):
+ self.clearIOMarkers(i)
+ self.MarkerAdd(i,INPUT_START)
+ elif marker & (1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED):
+ self.clearIOMarkers(i)
+ self.MarkerAdd(i,OUTPUT_START)
+ self.MarkerAdd(i,OUTPUT_BG)
+
+ def UnFoldIOSlice(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ start,end=self.GetIOSlice(line_num)
+ self.ShowLines(start+1,end)
+ marker=self.MarkerGet(start)
+ if (self.MarkerGet(start) & \
+ (1<<GROUPING_START | 1<<GROUPING_START_FOLDED )) and \
+ (self.MarkerGet(end) & 1<<GROUPING_END):
+ self.clearGroupingMarkers(start)
+ self.MarkerAdd(start,GROUPING_START)
+ self.clearIOMarkers(start)
+ if marker & 1<<INPUT_START_FOLDED:
+ self.MarkerAdd(start,INPUT_START)
+ elif marker & 1<<OUTPUT_START_FOLDED:
+ self.MarkerAdd(start,OUTPUT_START)
+ self.MarkerAdd(start,OUTPUT_BG)
+
+ def DeleteOutputSlicesAfter(self,line_num=None):
+ """Delete all outputs after an input"""
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ num_lines=self.GetLineCount()
+
+ if self.MarkerGet(line_num) & OUTPUT_MASK:
+ #print 'You can only run "DeleteOutputSlicesAfter" from an Input slice!'
+ return
+
+ startIn,endIn=self.GetIOSlice(line_num)
+ startGrouping,endGrouping=self.GetGroupingSlice(line_num)
+
+ if endIn<endGrouping:
+ self.SetSelection(self.PositionFromLine(endIn+1),
+ self.PositionFromLine(endGrouping+1))
+ self.ReplaceSelection('',sliceDeletion=True)
+
+ new_pos=self.GetLineEndPosition(line_num)
+ self.SetCurrentPos(new_pos)
+ self.SetSelection(new_pos,new_pos)
+
+ def SplitSlice(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+
+ start_num,end_num=self.GetIOSlice(line_num)
+
+ if self.MarkerGet(line_num) & INPUT_MASK:
+ type='Input'
+ start=INPUT_START
+ end=INPUT_END
+ splitGrouping=True
+ elif self.MarkerGet(line_num) & OUTPUT_MASK:
+ type='Output'
+ start=OUTPUT_START
+ end=OUTPUT_END
+ splitGrouping=False
+
+ if start_num==end_num:
+ return # Can't split one line!
+ elif start_num==line_num:
+ self.clearIOMarkers(line_num+1)
+ self.MarkerAdd(line_num+1,start)
+ if type=='Output': self.MarkerAdd(line_num+1,OUTPUT_BG)
+ if splitGrouping:
+ self.clearGroupingMarkers(line_num+1)
+ self.MarkerAdd(line_num+1,GROUPING_START)
+ else:
+ self.clearIOMarkers(line_num)
+ self.MarkerAdd(line_num,start)
+ if type=='Output': self.MarkerAdd(line_num,OUTPUT_BG)
+ if splitGrouping:
+ self.clearGroupingMarkers(line_num)
+ self.MarkerAdd(line_num,GROUPING_START)
+ if line_num-1>start_num:
+ self.clearIOMarkers(line_num-1)
+ self.MarkerAdd(line_num-1,end)
+ if type=='Output': self.MarkerAdd(line_num-1,OUTPUT_BG)
+ if splitGrouping:
+ self.clearGroupingMarkers(line_num-1)
+ self.MarkerAdd(line_num-1,GROUPING_END)
+
+ def BackspaceWMarkers(self,force=False):
+ # Warning: This is not good at checking for bad markers!
+ c_before=self.GetCharAt(self.GetCurrentPos() - 1)
+ c_after=self.GetCharAt(self.GetCurrentPos())
+
+ if c_before==0:
+ # Disallow deleting the first line or it will destroy the markers...
+ return False
+ elif c_before in (ord('\n'),ord('\r')):
+ line_num=self.GetCurrentLine()
+
+ marker=self.MarkerGet(line_num)
+ marker_before=self.MarkerGet(line_num-1)
+ marker_after=self.MarkerGet(line_num+1)
+ if marker_before & ( 1<<GROUPING_END ) :
+ return False # Disallow deleting lines between slices...
+ elif marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
+ return False # Disallow deleting lines between slices...
+ else:
+ if marker_before & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
+ self.clearGroupingMarkers(line_num)
+ elif marker & ( 1<<GROUPING_END ) :
+ self.clearGroupingMarkers(line_num-1)
+
+ if (marker_before & 1<<INPUT_END) and force:
+ # Special case for use in processLine
+ self.clearIOMarkers(line_num)
+ elif marker_before & (1<<INPUT_END | 1<<OUTPUT_END):
+ return False # Disallow deleting lines between slices...
+ elif marker & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ) :
+ return False # Disallow deleting lines between slices...
+ else:
+ if marker_before & (1<<INPUT_START | 1<<INPUT_START_FOLDED |
+ 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED):
+ self.clearIOMarkers(line_num)
+ elif marker & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
+ self.clearIOMarkers(line_num-1)
+
+ return True # If everything went well, return True and do the delete...
+
+ def ForwardDeleteWMarkers(self):
+ c_before=self.GetCharAt(self.GetCurrentPos() - 1)
+ c_after=self.GetCharAt(self.GetCurrentPos())
+ if c_after==0:
+ # Disallow deleting the first line or it will destroy the markers...
+ return False
+ elif c_after in (ord('\n'),ord('\r')):
+ line_num=self.GetCurrentLine()
+
+ marker=self.MarkerGet(line_num)
+ marker_before=self.MarkerGet(line_num-1)
+ marker_after=self.MarkerGet(line_num+1)
+ if marker & ( 1<<GROUPING_END ) :
+ return False # Disallow deleting lines between slices...
+ elif marker_after & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
+ return False # Disallow deleting lines between slices...
+ else:
+ if marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
+ self.clearGroupingMarkers(line_num+1)
+ elif marker_after & ( 1<<GROUPING_END ) :
+ self.clearGroupingMarkers(line_num)
+
+ if marker & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
+ return False # Disallow deleting lines between slices...
+ elif marker_after & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ) :
+ return False # Disallow deleting lines between slices...
+ else:
+ if marker & (1<<INPUT_START | 1<<INPUT_START_FOLDED |
+ 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED) :
+ self.clearIOMarkers(line_num+1)
+ elif marker_after & ( 1<<INPUT_END | 1<<OUTPUT_END ) :
+ self.clearIOMarkers(line_num)
+
+ return True
+
+ def GetIOSelection(self):
+ started=False
+ start=0
+ end=self.GetLineCount()-1
+ type=None
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<IO_SELECTING:
+ if started==False:
+ start=i
+ if self.MarkerGet(i) & INPUT_MASK:
+ type='input'
+ elif self.MarkerGet(i) & OUTPUT_MASK:
+ type='output'
+ else:
+ if self.MarkerGet(i) & INPUT_MASK:
+ if type=='output':
+ end=i-1
+ break
+ elif self.MarkerGet(i) & OUTPUT_MASK:
+ if type=='input':
+ end=i-1
+ break
+ started=True
+ elif started==True:
+ end=i-1
+ break
+
+ if started==False:
+ #print 'No Selection!!'
+ self.SliceSelection=False
+
+ return start,end
+
+ def MergeAdjacentSlices(self):
+ """This function merges all adjacent selected slices.\n""" + \
+ """Right now, only IO Merging is allowed."""
+ started=False
+ start=0
+ end=self.GetLineCount()-1
+ type=None
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<IO_SELECTING:
+ if started==False:
+ start=i
+ if self.MarkerGet(i) & INPUT_MASK:
+ type='input'
+ elif self.MarkerGet(i) & OUTPUT_MASK:
+ type='output'
+ else:
+ if self.MarkerGet(i) & INPUT_MASK:
+ if type=='output':
+ end=i-1
+ break
+ else:
+ self.clearIOMarkers(i)
+ self.clearGroupingMarkers(i)
+ self.MarkerAdd(i,INPUT_MIDDLE)
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+ elif self.MarkerGet(i) & OUTPUT_MASK:
+ if type=='input':
+ end=i-1
+ break
+ else:
+ self.clearIOMarkers(i)
+ self.clearGroupingMarkers(i)
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
+ self.MarkerAdd(i,OUTPUT_BG)
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+ started=True
+ elif started==True:
+ end=i-1
+ break
+
+ if started and end!=start:
+ self.clearIOMarkers(end)
+ self.clearGroupingMarkers(end)
+ if type=='input':
+ self.MarkerAdd(end,INPUT_END)
+ if end+1<self.GetLineCount():
+ if self.MarkerGet(end+1) & OUTPUT_MASK:
+ self.MarkerAdd(end,GROUPING_MIDDLE)
+ else:
+ self.MarkerAdd(end,GROUPING_END)
+ else:
+ self.MarkerAdd(end,GROUPING_END)
+ else:
+ if self.MarkerGet(start) & 1<<GROUPING_END:
+ self.clearGroupingMarkers(start)
+ self.MarkerAdd(start,GROUPING_MIDDLE)
+ self.MarkerAdd(end,OUTPUT_END)
+ self.MarkerAdd(end,OUTPUT_BG)
+ self.MarkerAdd(end,GROUPING_END)
+
+
+ def SliceSelectionDelete(self):
+ """Deletion of any selected and possibly discontinuous slices."""
+ if not self.SliceSelection:
+ return
+
+ # collect the line numbers to be deleted...
+ selectedSlices=[]
+ start,end=None,None
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & (1<<GROUPING_SELECTING | 1<<IO_SELECTING):
+ if start==None:
+ start=i
+ end=i
+ elif start!=None:
+ selectedSlices.append([start,end])
+ start,end=None,None
+ if start!=None:
+ selectedSlices.append([start,end])
+
+ # Unselect everything
+ self.MarginUnselectAll()
+ self.SliceSelection=False
+
+ # Going in reverse, delete the selections, fixing the markers as we go...
+ for i in range(len(selectedSlices)-1,-1,-1):
+ self.SetSelection(self.PositionFromLine(selectedSlices[i][0]),
+ self.GetLineEndPosition(selectedSlices[i][1])+1)
+
+ markerNext = self.MarkerGet(selectedSlices[i][1]+1)
+
+ self.ReplaceSelection('',sliceDeletion=True)
+
+ cur_line=self.GetCurrentLine()
+
+ # If we've made a mess of the grouping markers, clean it up...
+ if ((self.MarkerGet(cur_line-1) & 1<<GROUPING_END) and
+ (self.MarkerGet(cur_line) & ( 1<<GROUPING_MIDDLE | 1<<GROUPING_END ) )):
+ self.clearGroupingMarkers(cur_line)
+ self.MarkerAdd(cur_line,GROUPING_START)
+ elif (( self.MarkerGet(cur_line-1) & 1<<GROUPING_MIDDLE ) and
+ ( self.MarkerGet(cur_line) &
+ ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) )):
+ self.clearGroupingMarkers(cur_line-1)
+ self.MarkerAdd(cur_line-1,GROUPING_END)
+
+ if markerNext & 1<<OUTPUT_START:
+ self.clearIOMarkers(cur_line)
+ self.MarkerAdd(cur_line,OUTPUT_START)
+ self.MarkerAdd(cur_line,OUTPUT_BG)
+ elif markerNext & 1<<OUTPUT_START_FOLDED:
+ self.clearIOMarkers(cur_line)
+ self.MarkerAdd(cur_line,OUTPUT_START_FOLDED)
+ self.MarkerAdd(cur_line,OUTPUT_BG)
+
+ return
+
+ 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 output slices
+ if not self.CanEdit():
+ return
+ key = event.GetKeyCode()
+ currpos = self.GetCurrentPos()
+ stoppos = self.PositionFromLine(self.GetCurrentLine())
+
+ # Return (Enter) needs to be ignored in this handler.
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ pass
+ elif key in self.autoCompleteKeys:
+ # Usually the dot (period) key activates auto completion.
+ # Get the command between the prompt and the cursor. Add
+ # the autocomplete character to the end of the command.
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ command = self.GetTextRange(stoppos, currpos) + chr(key)
+
+ # write with undo wrapper...
+ cpos=self.GetCurrentPos()
+ s=chr(key)
+ #ADD UNDO
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
+ forceNewAction=False)
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+ if self.autoComplete:
+ self.autoCompleteShow(command)
+ elif key == ord('('):
+ # The left paren activates a call tip and cancels an
+ # active auto completion.
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ # Get the command between the prompt and the cursor. Add
+ # the '(' to the end of the command.
+ self.ReplaceSelection('')
+ command = self.GetTextRange(stoppos, currpos) + '('
+
+ # write with undo wrapper...
+ cpos=self.GetCurrentPos()
+ s='('
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
+ forceNewAction=True)
+ self.undoHistory[self.undoIndex]['allowsAppend']=True
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+ self.autoCallTipShow(command,
+ self.GetCurrentPos() == self.GetTextLength())
+ else:
+ # Allow the normal event handling to take place.
+ # Use undo wrapper
+ cpos=self.GetCurrentPos()
+ try:
+ s=chr(key)
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
+ event.Skip()
+ self.UpdateUndoHistoryAfter()
+ except:
+ event.Skip()
+
+ def AutoCompActiveCallback(self):
+ numChars=self.GetTextLength()-self.TotalLengthForAutoCompActiveCallback
+ if numChars==0:
+ self.undoIndex-=1
+ del(self.undoHistory[-1])
+ else:
+ uH=self.undoHistory
+ uI=self.undoIndex
+ cpos=uH[uI]['posStart']
+ s=''.join([chr(self.GetCharAt(cpos+i)) for i in range(numChars)])
+ s.replace(os.linesep,'\n')
+ self.undoHistory[self.undoIndex]['charList'] = s
+ self.undoHistory[self.undoIndex]['posEnd'] = cpos + numChars
+ self.undoHistory[self.undoIndex]['numLines'] = len(s.split('\n'))
+ self.UpdateUndoHistoryAfter()
+
+ def OnKeyDown(self, event):
+ """Key down event handler."""
+
+ key = event.GetKeyCode()
+ # If the auto-complete window is up let it do its thing.
+ if self.AutoCompActive():
+ if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+ cpos=self.GetCurrentPos()
+ self.UpdateUndoHistoryBefore('insert','dummy',cpos,cpos+5,
+ forceNewAction=True)
+ self.undoHistory[self.undoIndex]['allowsAppend'] = True
+ self.TotalLengthForAutoCompActiveCallback=self.GetTextLength()
+ event.Skip()
+ wx.CallAfter(self.AutoCompActiveCallback)
+ if key in [wx.WXK_DELETE,wx.WXK_BACK]:
+ self.AutoCompCancel()
+ else:
+ event.Skip()
+ return
+
+ #DNM
+ # Prevent modification of output slices
+ controlDown = event.ControlDown()
+ altDown = event.AltDown()
+ shiftDown = event.ShiftDown()
+ currpos = self.GetCurrentPos()
+ endpos = self.GetTextLength()
+ selecting = self.GetSelectionStart() != self.GetSelectionEnd()
+
+ if key == wx.WXK_F12: #seb
+ if self.noteMode:
+ # self.promptPosStart not used anyway - or ?
+## # We don't need to do this any more!
+## 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
+
+ doLineBreak=False
+ doSubmitCommand=False
+ doPass=False
+ # Return is used to insert a line break.
+ # In Shell Mode, hit Return or Enter twice to submit a command
+ if ((not controlDown and not shiftDown and not altDown) and
+ key in [wx.WXK_RETURN,]):
+ if self.mode=='SlicesMode':
+ doLineBreak=True
+ elif self.mode=='ShellMode':
+ startLine,endLine = self.GetIOSlice()
+ startpos = self.PositionFromLine(startLine)
+ endpos = self.GetLineEndPosition(endLine)
+ command = self.GetTextRange(startpos, endpos)
+ strCont,indentBlock,lineCont,parenCont = testForContinuations(command,ignoreErrors=True)
+
+ lastLine = command.split('\n')[-1]
+ if lastLine.lstrip()=='': # all whitespace...
+ stillIndented=False
+ elif lastLine[0]==' ':
+ stillIndented=True
+ else:
+ stillIndented=False
+
+ if strCont[-1] or indentBlock[-1] or lineCont[-1] or \
+ parenCont[-1]:
+ doLineBreak=True
+ elif stillIndented:
+ new_pos=self.GetLineEndPosition(endLine)
+ self.SetCurrentPos(new_pos)
+ self.SetSelection(new_pos,new_pos)
+ doLineBreak=True
+ elif self.GetCurrentLine()!=endLine:
+ new_pos=self.GetLineEndPosition(endLine)
+ self.SetCurrentPos(new_pos)
+ self.SetSelection(new_pos,new_pos)
+ doPass = True
+ else:
+ doSubmitCommand=True
+ # Enter (Shift/Ctrl + Enter/Return) submits a command to the interpreter.
+ # In Shell Mode, hit Return or Enter twice to submit a command
+ elif ( key in [wx.WXK_NUMPAD_ENTER,] or
+ ( (shiftDown or controlDown) and key in [wx.WXK_RETURN,
+ wx.WXK_NUMPAD_ENTER] ) ):
+ if self.mode=='SlicesMode':
+ doSubmitCommand=True
+ elif self.mode=='ShellMode':
+ doLineBreak=True
+
+ #Only relevant in ShellMode...
+
+ if doPass:
+ pass
+ elif doLineBreak or doSubmitCommand:
+ if self.CallTipActive():
+ self.CallTipCancel()
+ elif self.SliceSelection:
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
+ self.DoMarginClick(i, 2, shiftDown, controlDown)
+ break
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
+ self.DoMarginClick(i, 3, shiftDown, controlDown)
+ break
+ elif doLineBreak:
+ self.insertLineBreak()
+ #Only relevant in ShellMode...
+ elif doSubmitCommand:
+ self.DeleteOutputSlicesAfter()
+ self.processLine()
+
+ # Let Ctrl-Alt-* get handled normally.
+ elif controlDown and altDown:
+ event.Skip()
+
+ # Clear the current, unexecuted command.
+ elif key == wx.WXK_ESCAPE:
+ if self.CallTipActive():
+ event.Skip()
+ # Clear the current command
+ elif key == wx.WXK_BACK and controlDown and shiftDown:
+ self.clearCommand()
+
+ # Increase font size.
+ elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
+ dispatcher.send(signal='FontIncrease')
+
+ # Decrease font size.
+ elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
+ dispatcher.send(signal='FontDecrease')
+
+ # Default font size.
+ elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
+ dispatcher.send(signal='FontDefault')
+
+ # Cut to the clipboard.
+ elif (controlDown and key in (ord('X'), ord('x'))) \
+ or (shiftDown and key == wx.WXK_DELETE):
+ self.Cut()
+
+ # Copy to the clipboard.
+ elif controlDown and not shiftDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.Copy()
+
+ # Copy to the clipboard, including prompts.
+ elif controlDown and shiftDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.CopyWithPrompts()
+
+ # Copy to the clipboard, including prefixed prompts.
+ elif altDown and not controlDown \
+ and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+ self.CopyWithPromptsPrefixed()
+
+ # Home needs to be aware of the prompt.
+ elif controlDown and key == wx.WXK_HOME:
+ # Go to the beginning of the IO Slice
+ curLine = self.GetCurrentLine()
+ IOstart = self.GetIOSlice(curLine)[0]
+ home = self.PositionFromLine(IOstart)
+ if currpos == home and \
+ IOstart > 0:
+ home = self.PositionFromLine(self.GetIOSlice(curLine-1)[0])
+ self.SetCurrentPos(home)
+ if not selecting and not shiftDown:
+ self.SetAnchor(home)
+ self.EnsureCaretVisible()
+
+ elif controlDown and key == wx.WXK_END:
+ curLine = self.GetCurrentLine()
+ IOend = self.GetIOSlice(curLine)[1]
+ end = self.GetLineEndPosition(IOend)
+ if currpos == end and \
+ IOend < self.GetLineCount()-1:
+ end = self.GetLineEndPosition(self.GetIOSlice(curLine+1)[1])
+ self.SetCurrentPos(end)
+ if not selecting and not shiftDown:
+ self.SetAnchor(end)
+ self.EnsureCaretVisible()
+
+ elif controlDown and key == wx.WXK_PAGEUP:
+ pos=0
+ if currpos > pos:
+ self.SetCurrentPos(pos)
+ if not selecting and not shiftDown:
+ self.SetAnchor(pos)
+ self.EnsureCaretVisible()
+
+ elif controlDown and key == wx.WXK_PAGEDOWN:
+ pos = self.GetLineEndPosition(self.GetLineCount()-1)
+ if currpos < pos:
+ self.SetCurrentPos(pos)
+ if not selecting and not shiftDown:
+ self.SetAnchor(pos)
+ self.EnsureCaretVisible()
+
+ elif selecting and key not in NAVKEYS and not self.CanEdit():
+ pass
+
+ # Paste from the clipboard.
+ elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
+ or (shiftDown and not controlDown and key == wx.WXK_INSERT):
+ self.Paste()
+
+ # Paste from the clipboard, run commands.
+ elif controlDown and shiftDown and \
+ key in (ord('V'), ord('v')) and self.CanEdit():
+ self.PasteAndRun()
+
+ # Replace with the previous command from the history buffer.
+ elif (controlDown and not shiftDown and key == wx.WXK_UP) \
+ or (altDown and key in (ord('P'), ord('p'))) and self.CanEdit():
+ self.OnHistoryReplace(step=+1)
+
+ # Replace with the next command from the history buffer.
+ elif (controlDown and not shiftDown and key == wx.WXK_DOWN) \
+ or (altDown and key in (ord('N'), ord('n'))) and self.CanEdit():
+ self.OnHistoryReplace(step=-1)
+
+ # Insert the previous command from the history buffer.
+ elif (controlDown and shiftDown and key == wx.WXK_UP) and \
+ self.CanEdit():
+ self.OnHistoryInsert(step=+1)
+
+ # Insert the next command from the history buffer.
+ elif (controlDown and shiftDown and key == wx.WXK_DOWN) and \
+ self.CanEdit():
+ self.OnHistoryInsert(step=-1)
+
+ # Ctrl-Space shows Auto Completion
+ # Ctrl-Shift-Space shows CallTips
+ elif controlDown and key == wx.WXK_SPACE:
+ self.OnCallTipAutoCompleteManually(shiftDown)
+
+ # Ctrl+Shift+H is used to complete Text (from already typed words)
+ elif controlDown and shiftDown and key in [ord('H')]:
+ self.OnShowCompHistory()
+
+ # Search up the history for the text in front of the cursor.
+ elif key == wx.WXK_F8:
+ self.OnHistorySearch()
+
+ # Don't backspace over the latest non-continuation prompt.
+ elif key == wx.WXK_BACK:
+ if self.SliceSelection:
+ self.SliceSelectionDelete()
+ wx.CallAfter(self.RestoreFirstMarker)
+ elif selecting and self.CanEdit():
+ self.ReplaceSelection('')
+ #event.Skip()
+ elif self.CanEdit():
+ doDelete=True
+ cur_line=self.GetCurrentLine()
+ if not cur_line==0 and \
+ self.GetCurrentPos()==self.PositionFromLine(cur_line):
+ if self.MarkerGet(cur_line-1) & OUTPUT_MASK:
+ doDelete=False
+
+ if doDelete:
+ cpos=self.GetCurrentPos()
+ s=chr(self.GetCharAt(cpos-1))
+ self.UpdateUndoHistoryBefore('delete',s,cpos-1,cpos)
+ if self.BackspaceWMarkers():
+ event.Skip()
+
+ wx.CallAfter(self.RestoreFirstMarker)
+
+ elif key == wx.WXK_DELETE:
+ if self.SliceSelection:
+ self.SliceSelectionDelete()
+ wx.CallAfter(self.RestoreFirstMarker)
+ elif selecting and self.CanEdit():
+ self.ReplaceSelection('')
+ #event.Skip()
+ elif self.CanEdit():
+ doDelete=True
+ cur_line=self.GetCurrentLine()
+ if not cur_line==self.GetLineCount()-1 and \
+ self.GetCurrentPos()==self.GetLineEndPosition(cur_line):
+ if self.MarkerGet(cur_line+1) & OUTPUT_MASK:
+ doDelete=False
+
+ if doDelete:
+ cpos=self.GetCurrentPos()
+ s=chr(self.GetCharAt(cpos))
+ self.UpdateUndoHistoryBefore('delete',s,cpos,cpos+1)
+ if self.ForwardDeleteWMarkers():
+ event.Skip()
+
+ wx.CallAfter(self.RestoreFirstMarker)
+
+ # Only allow these keys after the latest prompt.
+ elif key == wx.WXK_TAB and self.CanEdit():
+ # use the same mechanism as with autocmplete...
+ cpos=self.GetCurrentPos()
+ self.UpdateUndoHistoryBefore('insert','dummy',cpos,cpos+5,
+ forceNewAction=True)
+ self.undoHistory[self.undoIndex]['allowsAppend'] = True
+ self.TotalLengthForAutoCompActiveCallback=self.GetTextLength()
+ event.Skip()
+ wx.CallAfter(self.AutoCompActiveCallback)
+
+ # Don't toggle between insert mode and overwrite mode.
+ elif key == wx.WXK_INSERT:
+ pass
+
+ # Don't allow line deletion.
+ #elif controlDown and key in (ord('L'), ord('l')):
+ # TODO : Allow line deletion eventually ??
+ #event.Skip()
+ # pass
+
+ # Don't allow line transposition.
+ # Toggle Shell Mode / Slices Mode
+ elif controlDown and key in (ord('T'), ord('t')):
+ self.ToggleShellMode()
+
+ #Open and Save now work when using CrustSlicesFrames
+ elif controlDown and key in (ord('L'), ord('l')):
+ #print 'Load it'
+ file=wx.FileSelector("Load File As New Slice")
+ if file!=u'':
+ fid=open(file,'r')
+ self.LoadPyFileAsSlice(fid)
+ fid.close()
+
+ elif controlDown and key in (ord('D'), ord('d')):
+ #Disallow line duplication in favor of divide slices
+ if self.MarkerGet(self.GetCurrentLine()) & INPUT_MASK:
+ #ADD UNDO
+ cpos=self.GetCurrentPos()
+ start,end = map(self.PositionFromLine,
+ self.GetGroupingSlice(self.LineFromPosition(cpos)))
+ self.UpdateUndoHistoryBefore('marker','',start,end,
+ forceNewAction=True)
+ self.SplitSlice()
+ # Turn off selecting
+ self.SetSelection(cpos,cpos)
+ self.ReplaceSelection('')
+ self.UpdateUndoHistoryAfter()
+
+ elif controlDown and key in (ord('M'), ord('m')):
+ #ADD UNDO
+ if self.SliceSelection:
+ cpos=self.GetCurrentPos()
+ ioSel=self.GetIOSelection()
+ if self.SliceSelection:
+ start,end = map(self.PositionFromLine,ioSel)
+ self.UpdateUndoHistoryBefore('marker','',start,end,
+ forceNewAction=True)
+ self.MergeAdjacentSlices()
+ # Turn off selecting
+ self.SetSelection(cpos,cpos)
+ self.ReplaceSelection('')
+ self.UpdateUndoHistoryAfter()
+
+
+ # Change arrow keys to allow margin behaviors...
+ elif self.SliceSelection and \
+ key in [wx.WXK_UP,wx.WXK_DOWN,wx.WXK_RIGHT,wx.WXK_LEFT]:
+ # TODO : This is useful, but not optimal!
+ if key==wx.WXK_UP:
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
+ if i>0: #Grouping
+ self.DoMarginClick(i-1, 2, shiftDown, controlDown)
+ break
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
+ if i>0: #IO
+ self.DoMarginClick(i-1, 3, shiftDown, controlDown)
+ break
+ elif key==wx.WXK_DOWN:
+ for i in range(self.GetLineCount()-1,-1,-1):
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
+ if i<self.GetLineCount()-1: #Grouping
+ self.DoMarginClick(i+1, 2, shiftDown, controlDown)
+ break
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
+ if i<self.GetLineCount()-1: #IO
+ self.DoMarginClick(i+1, 3, shiftDown, controlDown)
+ break
+ elif key==wx.WXK_RIGHT:
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
+ self.DoMarginClick(i, 3, shiftDown, controlDown)
+ break
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
+ self.MarginUnselectAll()
+ # Go to the beginning of the IO Slice
+ self.SetCurrentPos(self.PositionFromLine(i))
+ if not selecting and not shiftDown:
+ self.SetAnchor(self.PositionFromLine(i))
+ self.EnsureCaretVisible()
+ break
+ elif key==wx.WXK_LEFT:
+ for i in range(self.GetLineCount()):
+ if self.MarkerGet(i) & 1<<GROUPING_SELECTING:
+ break
+ elif self.MarkerGet(i) & 1<<IO_SELECTING:
+ self.DoMarginClick(i, 2, shiftDown, controlDown)
+ break
+ # Basic navigation keys should work anywhere.
+ elif key in NAVKEYS:
+ event.Skip()
+ # Protect the readonly portion of the slices shell.
+ elif not self.CanEdit():
+ pass
+ else:
+ # Check to see if we're selecting
+ if self.GetSelectionEnd()>self.GetSelectionStart():
+ # Check to see if a normal input took place
+ if not controlDown and not altDown and key<256:
+ self.ReplaceSelection('') # This seems to work...
+ event.Skip()
+
+ if self.SliceSelection:
+ if key not in [wx.WXK_UP,wx.WXK_DOWN,wx.WXK_RIGHT,wx.WXK_LEFT,
+ wx.WXK_ALT,wx.WXK_COMMAND,wx.WXK_CONTROL,wx.WXK_SHIFT]:
+ self.MarginUnselectAll()
+
+
+ def MarginSelectAll(self):
+ num_lines=self.GetLineCount()
+ for i in range(num_lines):
+ self.MarkerAdd(i,GROUPING_SELECTING)
+ self.MarkerDelete(i,IO_SELECTING)
+
+ def MarginUnselectAll(self):
+ num_lines=self.GetLineCount()
+ for i in range(num_lines):
+ self.MarkerDelete(i,IO_SELECTING)
+ self.MarkerDelete(i,GROUPING_SELECTING)
+ self.SliceSelection=False
+
+ def DoMarginClick(self, lineClicked, margin, shiftDown, controlDown):
+ num_lines=self.GetLineCount()
+
+ if margin==1:
+ pass # these events are not sent right now...
+ if margin==2:
+ self.SliceSelection=True
+ start,end=self.GetGroupingSlice(lineClicked)
+ startPos=self.PositionFromLine(start)
+ self.SetCurrentPos(startPos)
+ self.SetSelection(startPos,startPos)
+ start_marker=self.MarkerGet(start)
+ if self.MarkerGet(lineClicked) & 1<<GROUPING_SELECTING:
+ toggle=self.MarkerDelete
+ if not shiftDown:
+ if start_marker & 1<<GROUPING_START:
+ self.FoldGroupingSlice(lineClicked)
+ elif start_marker & 1<<GROUPING_START_FOLDED:
+ self.UnFoldGroupingSlice(lineClicked)
+ else:
+ toggle=self.MarkerAdd
+
+ if not shiftDown:
+ self.MarginUnselectAll()
+
+ for i in range(start,end+1):
+ toggle(i,GROUPING_SELECTING)
+ elif margin==3:
+ self.SliceSelection=True
+ start,end=self.GetIOSlice(lineClicked)
+ startPos=self.PositionFromLine(start)
+ self.SetCurrentPos(startPos)
+ self.SetSelection(startPos,startPos)
+ start_marker=self.MarkerGet(start)
+ if self.MarkerGet(lineClicked) & 1<<IO_SELECTING:
+ toggle=self.MarkerDelete
+ if not shiftDown:
+ if start_marker & IO_START_MASK:
+ self.FoldIOSlice(lineClicked)
+ elif start_marker & IO_START_FOLDED_MASK:
+ self.UnFoldIOSlice(lineClicked)
+ else:
+ toggle=self.MarkerAdd
+
+ if not shiftDown:
+ self.MarginUnselectAll()
+
+ for i in range(start,end+1):
+ toggle(i,IO_SELECTING)
+
+ #print start,end
+
+ elif margin==4:
+ # TODO : Folding ??
+ if 1:#self.MarkerGet(lineClicked) & ( 1<<7 | 1<<8 ):
+ if shiftDown:
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 1)
+ elif controlDown:
+ if self.GetFoldExpanded(lineClicked):
+ self.SetFoldExpanded(lineClicked, False)
+ self.Expand(lineClicked, False, True, 0)
+ else:
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 100)
+ else:
+ self.ToggleFold(lineClicked)
+ else:
+ self.MarginUnselectAll()
+ if margin in [2,3]:
+ if toggle==self.MarkerDelete and not shiftDown:
+ self.SliceSelection=False
+ else:
+ self.SliceSelection=True
+
+ def OnMarginClick(self, evt):
+
+ # fold and unfold as neededNAVKEYS
+ lineClicked = self.LineFromPosition(evt.GetPosition())
+ self.DoMarginClick(lineClicked,evt.GetMargin(),evt.GetShift(),evt.GetControl())
+ evt.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 ReplaceSelection(self,text,sliceDeletion=False,*args,**kwds):
+ startIO,endIO=self.GetIOSlice()
+ startGrouping,endGrouping=self.GetGroupingSlice()
+ startSel = self.LineFromPosition(self.GetSelectionStart())
+ endSel = self.LineFromPosition(self.GetSelectionEnd())
+
+ #ADD UNDO
+ cpos=self.GetSelectionStart()
+ s=self.GetSelectedText()
+ if s!='':
+ self.UpdateUndoHistoryBefore('delete',s,cpos,cpos+len(s),
+ forceNewAction=True)
+ editwindow.EditWindow.ReplaceSelection(self,'',*args,**kwds)
+ if s!='' and not sliceDeletion:
+ self.UpdateUndoHistoryAfter()
+
+ if endSel-startSel>0 and not sliceDeletion:
+ if endSel==endIO and startIO!=self.GetCurrentLine():
+ self.clearIOMarkers()
+ self.MarkerAdd(self.GetCurrentLine(),INPUT_END)
+
+ if endSel==endGrouping and startGrouping!=self.GetCurrentLine():
+ self.clearGroupingMarkers()
+ self.MarkerAdd(self.GetCurrentLine(),GROUPING_END)
+
+ cpos=self.GetSelectionStart()
+ s=text
+ if s!='':
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s),
+ forceNewAction=True)
+ self.write(text)
+ self.UpdateUndoHistoryAfter()
+
+ self.ensureSingleGroupingMarker()
+ self.ensureSingleIOMarker()
+
+
+ def clearCommand(self):
+ """Delete the current, unexecuted command."""
+ if not self.CanEdit():
+ return
+ start,end=self.GetIOSlice()
+ startpos = self.PositionFromLine(start)
+ endpos = self.GetLineEndPosition(end)
+ self.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+ self.more = False
+
+ def OnHistoryReplace(self, step):
+ """Replace with the previous/next command from the history buffer."""
+ if not self.CanEdit():
+ return
+ self.clearCommand()
+ self.replaceFromHistory(step)
+
+ def replaceFromHistory(self, step):
+ """Replace selection with command from the history buffer."""
+ if not self.CanEdit():
+ return
+ self.ReplaceSelection('')
+ newindex = self.historyIndex + step
+ if -1 <= newindex <= len(self.history):
+ self.historyIndex = newindex
+ if 0 <= newindex <= len(self.history)-1:
+ command = self.history[self.historyIndex]
+ command = command.replace('\n', os.linesep)# + ps2)
+ self.ReplaceSelection(command)
+
+ def OnHistoryInsert(self, step):
+ """Insert the previous/next command from the history buffer."""
+ if not self.CanEdit():
+ return
+ startpos = self.GetCurrentPos()
+ self.replaceFromHistory(step)
+ endpos = self.GetCurrentPos()
+ self.SetSelection(endpos, startpos)
+
+ # TODO: Fix Me!
+ def OnHistorySearch(self):
+ """Search up the history buffer for the text in front of the cursor."""
+ if not self.CanEdit():
+ return
+ startpos = self.GetCurrentPos()
+ # The text up to the cursor is what we search for.
+ numCharsAfterCursor = self.GetTextLength() - startpos
+ searchText = self.getCommand(rstrip=False)
+ #print 'history search', startpos,numCharsAfterCursor,searchText
+ if numCharsAfterCursor > 0:
+ searchText = searchText[:-numCharsAfterCursor]
+ if not searchText:
+ return
+ # Search upwards from the current history position and loop
+ # back to the beginning if we don't find anything.
+ if (self.historyIndex <= -1) \
+ or (self.historyIndex >= len(self.history)-2):
+ searchOrder = range(len(self.history))
+ else:
+ searchOrder = range(self.historyIndex+1, len(self.history)) + \
+ range(self.historyIndex)
+ for i in searchOrder:
+ command = self.history[i]
+ if command[:len(searchText)] == searchText:
+ # Replace the current selection with the one we found.
+ self.ReplaceSelection(command[len(searchText):])
+ endpos = self.GetCurrentPos()
+ self.SetSelection(endpos, startpos)
+ # We've now warped into middle of the history.
+ self.historyIndex = i
+ break
+
+ def setStatusText(self, text):
+ """Display status information."""
+
+ # This method will likely be replaced by the enclosing app to
+ # do something more interesting, like write to a status bar.
+ print text
+
+ def insertLineBreak(self):
+ """Insert a new line break."""
+ if not self.CanEdit():
+ return
+ elif self.reader.isreading:
+ self.processLine()
+ return
+
+
+ # write with undo wrapper...
+ cpos=self.GetCurrentPos()
+ s=os.linesep
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+1)
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+ self.more = True
+ self.prompt()
+
+ def processLine(self):
+ """Process the line of text at which the user hit Enter or Shift+RETURN."""
+ # The user hit ENTER (Shift+RETURN) (Shift+ENTER) and we need to
+ # decide what to do. They could be sitting on any line in the slices shell.
+ thepos = self.GetCurrentPos()
+ cur_line = self.GetCurrentLine()
+ marker=self.MarkerGet(cur_line)
+ if marker & INPUT_MASK:
+ pass
+ elif marker & OUTPUT_MASK:
+ return
+ else:
+ pass #print 'BLANK LINE!!'
+
+ startline,endline=self.GetIOSlice(cur_line)
+
+ if startline==0:
+ startpos=0
+ else:
+ startpos=self.PositionFromLine(startline)
+
+ endpos=self.GetLineEndPosition(endline)
+
+ # If they hit ENTER inside the current command, execute the command.
+ if self.CanEdit():
+ self.SetCurrentPos(endpos)
+ self.interp.more = False
+ command = self.GetTextRange(startpos, endpos)
+ lines = command.split(os.linesep)
+ lines = [line.rstrip() for line in lines]
+ command = '\n'.join(lines)
+ if self.reader.isreading:
+ if not command:
+ # Match the behavior of the standard Python shell
+ # when the user hits return without entering a value.
+ command = '\n'
+ self.reader.input = command
+ self.write(os.linesep,'Input')
+ self.MarkerSet(self.GetCurrentLine(),READLINE_BG)
+ self.MarkerSet(self.GetCurrentLine(),INPUT_READLINE)
+ else:
+ self.runningSlice = (startline,endline)
+ self.push(command,useMultiCommand=True)
+ #print 'command: ',command
+ wx.FutureCall(1, self.EnsureCaretVisible)
+ self.runningSlice=None
+
+ skip=self.BackspaceWMarkers(force=True)
+ if skip:
+ self.DeleteBack()
+
+ if self.GetCurrentLine()==self.GetLineCount()-1:
+ self.write(os.linesep,type='Input')
+ cpos=self.GetCurrentLine()
+ if self.MarkerGet(cpos-1) & OUTPUT_MASK:
+ self.MarkerAdd(cpos-1,OUTPUT_BG)
+ self.SplitSlice()
+ else:
+ cur_line=self.GetCurrentLine()
+ new_pos=self.GetLineEndPosition(cur_line+1)
+ self.SetSelection(new_pos,new_pos)
+ self.SetCurrentPos(new_pos)
+
+ self.EmptyUndoBuffer()
+ self.NeedsCheckForSave=True
+ if self.hasSyntaxError:
+ pos=self.GetLineEndPosition(self.syntaxErrorRealLine)
+ self.SetCurrentPos(pos)
+ self.SetSelection(pos,pos)
+
+ # Not Used!!
+ def getMultilineCommand(self, rstrip=True):
+ """Extract a multi-line command from the editor.
+
+ The command may not necessarily be valid Python syntax."""
+ # DNM
+ # XXX Need to extract real prompts here. Need to keep track of
+ # the prompt every time a command is issued.
+ text = self.GetCurLine()[0]
+ line = self.GetCurrentLine()
+ # Add Marker testing here...
+ while text == '' and line > 0: # Need to add markers handling...
+ line -= 1
+ self.GotoLine(line)
+ text = self.GetCurLine()[0]
+ if text=='':
+ line = self.GetCurrentLine()
+ self.GotoLine(line)
+ startpos = self.GetCurrentPos()
+ line += 1
+ self.GotoLine(line)
+ while self.GetCurLine()[0]=='':
+ line += 1
+ self.GotoLine(line)
+ stoppos = self.GetCurrentPos()
+ command = self.GetTextRange(startpos, stoppos)
+ command = command.replace(os.linesep, '\n')
+ command = command.rstrip()
+ command = command.replace('\n', os.linesep)
+ else:
+ command = ''
+ if rstrip:
+ command = command.rstrip()
+ return command
+
+ def getCommand(self, text=None, rstrip=True):
+ """Extract a command from text which may include a shell prompt.
+
+ The command may not necessarily be valid Python syntax."""
+ if not text:
+ text = self.GetCurLine()[0]
+ # Strip the prompt off the front leaving just the command.
+ command = self.lstripPrompt(text)
+ # Change this -- Nothing has prompts!
+ #if command == text:
+ # command = '' # Real commands have prompts.
+ if rstrip:
+ command = command.rstrip()
+ return command
+
+ def lstripPrompt(self, text):
+ """Return text without a leading prompt."""
+ ps1 = str(sys.ps1)
+ ps1size = len(ps1)
+ ps2 = str(sys.ps2)
+ ps2size = len(ps2)
+ # Strip the prompt off the front of text.
+ if text[:ps1size] == ps1:
+ text = text[ps1size:]
+ elif text[:ps2size] == ps2:
+ text = text[ps2size:]
+ return text
+
+ def push(self, command, silent = False,useMultiCommand=False):
+ """Send command to the interpreter for execution."""
+ if not silent:
+ self.write(os.linesep,type='Output')
+ # TODO : What other magic might we insert here?
+ # TODO : Is there a good reason not to include magic?
+ if USE_MAGIC:
+ command=magic(command)
+
+ # Allows multi-component commands...
+ self.hasSyntaxError=False
+ if useMultiCommand:
+ result = self.BreakTextIntoCommands(command)
+ if result[0] == None:
+ commands=[command]
+ self.hasSyntaxError=True
+ syntaxErrorLine=result[1]+1
+ self.syntaxErrorRealLine = self.GetCurrentLine()+result[1]-len(command.split('\n'))
+ else:
+ commands=result
+ else:
+ commands=[command]
+
+ busy = wx.BusyCursor()
+ self.waiting = True
+ self.lastUpdate=None
+
+ for i in commands:
+ if self.hasSyntaxError:
+ lineno=syntaxErrorLine
+ offset=0 # not sure how to easily recover this information...
+ self.write(' File "<input>", line '+str(lineno)+'\n '+i.split('\n')[lineno-1]+'\n'+' '*offset+' ^\nSyntaxError: invalid syntax\n','Error')
+ else:
+ self.more = self.interp.push(i+'\n')
+ # (the \n stops many things from bouncing at the interpreter)
+ # I could do the following, but I don't really like it!
+ #if useMultiCommand:
+ # self.SplitSlice()
+ self.lastUpdate=None
+
+ if not silent:
+ self.MarkerAdd(self.GetIOSlice()[0],OUTPUT_BG)
+
+ self.waiting = False
+ del busy
+ if not self.more: # could loop-add to history, too, but I don't like it!
+ self.addHistory(command.rstrip())
+
+ if not silent:
+ self.prompt()
+
+ def addHistory(self, command):
+ """Add command to the command history."""
+ # Reset the history position.
+ self.historyIndex = -1
+ # Insert this command into the history, unless it's a blank
+ # line or the same as the last command.
+ if command!='' and ( len(self.history)==0 or command!=self.history[0] ):
+ self.history.insert(0, command)
+ dispatcher.send(signal="SlicesShell.addHistory", command=command)
+
+ def clearGroupingMarkers(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+ self.MarkerDelete(line_num,GROUPING_START)
+ self.MarkerDelete(line_num,GROUPING_START_FOLDED)
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
+ self.MarkerDelete(line_num,GROUPING_END)
+ def clearIOMarkers(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+ self.MarkerDelete(line_num,INPUT_START)
+ self.MarkerDelete(line_num,INPUT_START_FOLDED)
+ self.MarkerDelete(line_num,INPUT_MIDDLE)
+ self.MarkerDelete(line_num,INPUT_END)
+ self.MarkerDelete(line_num,OUTPUT_START)
+ self.MarkerDelete(line_num,OUTPUT_START_FOLDED)
+ self.MarkerDelete(line_num,OUTPUT_MIDDLE)
+ self.MarkerDelete(line_num,OUTPUT_END)
+ self.MarkerDelete(line_num,OUTPUT_BG)
+ self.MarkerDelete(line_num,READLINE_BG)
+ self.MarkerDelete(line_num,INPUT_READLINE)
+ def ensureSingleGroupingMarker(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+ marker=self.MarkerGet(line_num)
+ if marker & 1<<GROUPING_START:
+ self.MarkerDelete(line_num,GROUPING_START_FOLDED)
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
+ self.MarkerDelete(line_num,GROUPING_END)
+ elif marker & 1<<GROUPING_START_FOLDED:
+ self.MarkerDelete(line_num,GROUPING_MIDDLE)
+ self.MarkerDelete(line_num,GROUPING_END)
+ elif marker & 1<<GROUPING_MIDDLE:
+ self.MarkerDelete(line_num,GROUPING_END)
+ elif marker & 1<<GROUPING_END:
+ pass
+ else:
+ #print 'ERROR! NO GROUPING MARKERS!'
+ return 1 # Blank marker
+
+ return 0
+
+ def ensureSingleIOMarker(self,line_num=None):
+ if line_num==None:
+ line_num=self.GetCurrentLine()
+ marker=self.MarkerGet(line_num)
+ if marker & INPUT_MASK:
+ self.MarkerDelete(line_num,OUTPUT_START)
+ self.MarkerDelete(line_num,OUTPUT_START_FOLDED)
+ self.MarkerDelete(line_num,OUTPUT_MIDDLE)
+ self.MarkerDelete(line_num,OUTPUT_END)
+ self.MarkerDelete(line_num,OUTPUT_BG)
+ [start,start_folded] = [INPUT_START,INPUT_START_FOLDED]
+ [middle,end] = [INPUT_MIDDLE,INPUT_END]
+ elif marker & OUTPUT_MASK:
+ self.MarkerDelete(line_num,INPUT_START)
+ self.MarkerDelete(line_num,INPUT_START_FOLDED)
+ self.MarkerDelete(line_num,INPUT_MIDDLE)
+ self.MarkerDelete(line_num,INPUT_END)
+ [start,start_folded] = [OUTPUT_START,OUTPUT_START_FOLDED]
+ [middle,end] = [OUTPUT_MIDDLE,OUTPUT_END]
+ else:
+ #print 'ERROR! NO IO MARKERS!'
+ return 1 # Blank marker
+
+ if marker & 1<<start:
+ self.MarkerDelete(line_num,start_folded)
+ self.MarkerDelete(line_num,middle)
+ self.MarkerDelete(line_num,end)
+ elif marker & 1<<start_folded:
+ self.MarkerDelete(line_num,middle)
+ self.MarkerDelete(line_num,end)
+ elif marker & 1<<middle:
+ self.MarkerDelete(line_num,end)
+ elif marker & 1<<end:
+ pass
+
+ return 0
+
+ def RestoreFirstMarker(self):
+ first_marker=self.MarkerGet(0)
+ self.clearGroupingMarkers(0)
+ self.clearIOMarkers(0)
+
+ if first_marker & 1<<GROUPING_START :
+ self.MarkerAdd(0,GROUPING_START)
+ elif first_marker & 1<<GROUPING_START_FOLDED :
+ self.MarkerAdd(0,GROUPING_START_FOLDED)
+ else:
+ self.MarkerAdd(0,GROUPING_START)
+
+ if first_marker & 1<<INPUT_START :
+ self.MarkerAdd(0,INPUT_START)
+ elif first_marker & 1<<INPUT_START_FOLDED :
+ self.MarkerAdd(0,INPUT_START_FOLDED)
+ elif first_marker & 1<<OUTPUT_START :
+ self.MarkerAdd(0,OUTPUT_START)
+ #self.MarkerAdd(0,OUTPUT_BG) # More harm than good??
+ elif first_marker & 1<<OUTPUT_START_FOLDED :
+ self.MarkerAdd(0,OUTPUT_START_FOLDED)
+ #self.MarkerAdd(0,OUTPUT_BG) # More harm than good??
+ else:
+ self.MarkerAdd(0,INPUT_START)
+
+ if self.doHistUpdate:
+ self.UpdateUndoHistoryAfter()
+
+ def IsAllowedPair(self,m1,m2):
+ """This testing function ensures that two adjacent markers are valid"""
+ i_s = 1<<INPUT_START | 1<<INPUT_START_FOLDED
+ o_s = 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED
+ g_s = 1<<GROUPING_START | 1<<GROUPING_START_FOLDED
+ i_m,o_m,g_m = 1<<INPUT_MIDDLE, 1<<OUTPUT_MIDDLE, 1<<GROUPING_MIDDLE
+ i_e,o_e,g_e = 1<<INPUT_END, 1<<OUTPUT_END, 1<<GROUPING_END
+
+ if (m1 & i_s) and (m1 & g_s): #1
+ if (m2 & i_s) and (m2 & g_s): return True #1
+ elif (m2 & i_m) and (m2 & g_m): return True #2
+ elif (m2 & i_e) and (m2 & g_m): return True #3
+ elif (m2 & i_e) and (m2 & g_e): return True #4
+ elif (m2 & o_s) and (m2 & g_s): return False #5
+ elif (m2 & o_s) and (m2 & g_m): return True #6
+ elif (m2 & o_s) and (m2 & g_e): return True #7
+ elif (m2 & o_m) and (m2 & g_m): return False #8
+ elif (m2 & o_e) and (m2 & g_e): return False #9
+ else: return False
+ elif (m1 & i_m) and (m1 & g_m): #2
+ if (m2 & i_m) and (m2 & g_m): return True #2
+ elif (m2 & i_e) and (m2 & g_m): return True #3
+ elif (m2 & i_e) and (m2 & g_e): return True #4
+ else: return False
+ elif (m1 & i_e) and (m1 & g_m): #3
+ if (m2 & o_s) and (m2 & g_m): return True #6
+ elif (m2 & o_s) and (m2 & g_e): return True #7
+ else: return False
+ elif (m1 & i_e) and (m1 & g_e): #4
+ if (m2 & i_s) and (m2 & g_s): return True #1
+ elif (m2 & o_s) and (m2 & g_s): return True #5
+ else: return False
+ elif (m1 & o_s) and (m1 & g_s): #5
+ if (m2 & i_s) and (m2 & g_s): return True #1
+ elif (m2 & i_m) and (m2 & g_m): return False #2
+ elif (m2 & i_e) and (m2 & g_m): return False #3
+ elif (m2 & i_e) and (m2 & g_e): return False #4
+ elif (m2 & o_s) and (m2 & g_s): return True #5
+ elif (m2 & o_s) and (m2 & g_m): return False #6
+ elif (m2 & o_s) and (m2 & g_e): return False #7
+ elif (m2 & o_m) and (m2 & g_m): return True #8
+ elif (m2 & o_e) and (m2 & g_e): return True #9
+ else: return False
+ elif (m1 & o_s) and (m1 & g_m): #6
+ if (m2 & o_m) and (m2 & g_m): return True #8
+ elif (m2 & o_e) and (m2 & g_e): return True #9
+ else: return False
+ elif (m1 & o_s) and (m1 & g_e): #7
+ if (m2 & i_s) and (m2 & g_s): return True #1
+ elif (m2 & o_s) and (m2 & g_s): return True #5
+ else: return False
+ elif (m1 & o_m) and (m1 & g_m): #8
+ if (m2 & o_m) and (m2 & g_m): return True #8
+ elif (m2 & o_e) and (m2 & g_e): return True #9
+ else: return False
+ elif (m1 & o_e) and (m1 & g_e): #9
+ if (m2 & i_s) and (m2 & g_s): return True #1
+ elif (m2 & o_s) and (m2 & g_s): return True #5
+ else: return False
+ else:
+ return False
+
+
+ def CleanAllMarkers(self):
+ self.RestoreFirstMarker()
+ first_marker=self.MarkerGet(0)
+ last_line_num=self.GetLineCount()-1
+
+ for i in range(1,last_line_num):
+ self.ensureSingleGroupingMarker(i)
+ self.ensureSingleIOMarker(i)
+
+ previous_marker=self.MarkerGet(i-1)
+ marker=self.MarkerGet(i)
+
+ if not self.IsAllowedPair(previous_marker,marker):
+ pass # FIX MARKER!!
+ # FIX ME
+
+ def write(self, text,type='Input',silent=False):
+ """Display text in the slices shell.
+
+ Replace line endings with OS-specific endings."""
+ text = self.fixLineEndings(text)
+ split=text.split(os.linesep)
+ self.AddText(text)
+
+ # This part handles all the marker stuff that accompanies
+ # adding or removing new lines of text...
+ # Get the total number of lines in the Document == last line number
+ last_line_num=self.GetLineCount()-1
+ # Get the line number we ended on in the write
+ end_line_num=self.GetCurrentLine()
+ # Get the number of returns we are using == number of lines we pasted -1
+ num_new_lines=text.count(os.linesep)
+ # So if num_new_lines==0, start_line_num and end_line_num are the same
+ start_line_num=end_line_num-num_new_lines+1
+
+ # This is a little unnecessary because there will always
+ # be a line before if we just inserted a newline!
+ if start_line_num == 0:
+ previous_line_num=None
+ else:
+ previous_line_num=start_line_num-1
+
+ #However, this is very important...
+ if end_line_num == last_line_num:
+ next_line_num=None
+ else:
+ next_line_num=end_line_num+1
+
+ if type=='Input':
+ start = INPUT_START
+ start_folded = INPUT_START_FOLDED
+ middle = INPUT_MIDDLE
+ end = INPUT_END
+ # preparation for more io types...
+ opposite_start_mask = 1<<OUTPUT_START
+ opposite_start_folded_mask = 1<<OUTPUT_START_FOLDED
+ opposite_middle_mask = 1<<OUTPUT_MIDDLE # To test for bad writes...
+ opposite_end_mask = 1<<OUTPUT_END # To test for bad writes...
+ elif type in ['Output','Error']:
+ #self.MarkerAdd(start_line_num,GROUPING_START_FOLDED)
+ start=OUTPUT_START
+ start_folded=OUTPUT_START_FOLDED
+ middle=OUTPUT_MIDDLE
+ end=OUTPUT_END
+ # preparation for more io types...
+ opposite_start_mask = 1<<INPUT_START
+ opposite_start_folded_mask = 1<<INPUT_START_FOLDED
+ opposite_middle_mask = 1<<INPUT_MIDDLE # To test for bad writes...
+ opposite_end_mask = 1<<INPUT_END # To test for bad writes...
+
+ if num_new_lines>0: #Do nothing if typing within a line...
+ # Update the Grouping Markers
+ # For the previous line and the start_line
+ # Test to make sure we can write ... but not here ...
+ # test this before we call write or before we add text...
+ # So we assume it already obeys the rules
+
+ badMarkers=False
+ fixIOEnd=True
+
+ if previous_line_num==None:
+ # This is an impossible case, here just for completeness...
+ self.clearGroupingMarkers(start_line_num)
+ self.MarkerAdd(start_line_num,GROUPING_START)
+
+ self.clearIOMarkers(start_line_num)
+ self.MarkerAdd(start_line_num,start)
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
+ else:
+ previous_marker=self.MarkerGet(previous_line_num)
+ if previous_marker & opposite_middle_mask:
+ badMarkers=True
+
+ if next_line_num==None:
+ self.MarkerAdd(end_line_num,GROUPING_END)
+ self.MarkerAdd(end_line_num,end)
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
+ fixEndMarkers=False
+ # May be overwritten below if start_line_num==end_line_num...
+ else:
+ next_marker=self.MarkerGet(next_line_num)
+ fixEndMarkers=True
+ if next_marker & ( opposite_middle_mask | opposite_end_mask ):
+ badMarkers=True
+
+ if not badMarkers:
+ # ensure previous_line only has one marker & turn end into middle
+ if previous_line_num!=None:
+ # Adjust previous line appropriately, ensure only one marker
+ # Only print errors if we are on input!
+ blank=False
+ blank=blank or self.ensureSingleGroupingMarker(previous_line_num)
+ blank=blank or self.ensureSingleIOMarker(previous_line_num)
+
+ if blank:
+ #if type=='Input' and not silent: print 'BLANK LINE!' # BAD CASE
+ pass
+
+ if previous_marker & 1<<GROUPING_END :
+ # Make GROUPING slice continue unless we hit
+ # an output end and are starting a new input...
+ if (previous_marker & OUTPUT_MASK) and type=='Input':
+ pass
+ else:
+ self.MarkerDelete(previous_line_num,GROUPING_END)
+ # ONLY CHANGING CASE
+ self.MarkerAdd(previous_line_num,GROUPING_MIDDLE)
+
+ if previous_marker & 1<<end :
+ self.MarkerDelete(previous_line_num,end)
+ self.MarkerAdd(previous_line_num,middle) # ONLY CHANGING CASE
+ if type in ['Output','Error']: self.MarkerAdd(previous_line_num,OUTPUT_BG)
+ elif previous_marker & opposite_middle_mask :
+ # BAD CASE
+ if type=='Input' and not silent:
+ #print 'Should have been a bad marker!'
+ pass
+
+ # We can only add input to an input slice
+ # And can only add output to an output slice
+
+ if previous_marker & ( opposite_start_mask |
+ opposite_start_folded_mask |
+ opposite_end_mask ):
+ if type=='Input':
+ self.clearGroupingMarkers(start_line_num)
+ self.MarkerAdd(start_line_num,GROUPING_START)
+ if start_line_num==end_line_num:
+ fixEndMarkers=False
+ else:
+ if start_line_num==end_line_num:
+ fixIOEnd=False
+ self.clearIOMarkers(start_line_num)
+ self.MarkerAdd(start_line_num,start)
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
+ else:
+ if next_line_num!=None:
+ self.clearGroupingMarkers(start_line_num)
+ self.clearIOMarkers(start_line_num)
+ self.MarkerAdd(start_line_num,GROUPING_MIDDLE)
+ self.MarkerAdd(start_line_num,middle)
+ if type in ['Output','Error']: self.MarkerAdd(start_line_num,OUTPUT_BG)
+ # This may be overwritten if start_line_num==end_line_num
+
+ # Take care of all the middle lines...
+ # Does nothing for only one line...
+ for i in range(start_line_num,end_line_num):
+ self.clearGroupingMarkers(i)
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+
+ self.clearIOMarkers(i)
+ self.MarkerAdd(i,middle)
+ if type in ['Output','Error']: self.MarkerAdd(i,OUTPUT_BG)
+
+ if fixEndMarkers:
+ # Take care of the end_line if we haven't already done so...
+ blank=False
+ blank=blank or self.ensureSingleGroupingMarker(next_line_num)
+ blank=blank or self.ensureSingleIOMarker(next_line_num)
+
+ if blank:
+ if type=='Input' and not silent:
+ #print 'BLANK LINE!' # BAD CASE
+ pass
+
+ self.clearGroupingMarkers(end_line_num)
+ if fixIOEnd:
+ self.clearIOMarkers(end_line_num)
+
+ if next_marker & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ) :
+ self.MarkerAdd(end_line_num,GROUPING_END)
+ elif next_marker & ( 1<<GROUPING_MIDDLE | 1<<GROUPING_END ) :
+ self.MarkerAdd(end_line_num,GROUPING_MIDDLE)
+
+ if fixIOEnd:
+ if next_marker & ( 1<<start | 1<<start_folded ) :
+ self.MarkerAdd(end_line_num,end)
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
+ elif next_marker & ( 1<<middle | 1<<end ) :
+ self.MarkerAdd(end_line_num,middle)
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
+ elif next_marker & ( opposite_start_mask |
+ opposite_start_folded_mask ):
+ self.MarkerAdd(end_line_num,end)
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
+ else:
+ self.MarkerAdd(end_line_num,start_folded)
+ if type in ['Output','Error']: self.MarkerAdd(end_line_num,OUTPUT_BG)
+ if type=='Input' and not silent:
+ #print 'BAD MARKERS!'
+ pass
+ else:
+ if type=='Input' and not silent:
+ #print 'BAD MARKERS!!!'
+ pass
+
+ self.EnsureCaretVisible()
+
+ if self.waiting:
+ if self.lastUpdate==None:
+ self.lastUpdate=time.time()
+ if time.time()-self.lastUpdate > PRINT_UPDATE_MAX_TIME:
+ self.Update()
+ self.lastUpdate=time.time()
+
+ def fixLineEndings(self, text):
+ """Return text with line endings replaced by OS-specific endings."""
+ lines = text.split('\r\n')
+ for l in range(len(lines)):
+ chunks = lines[l].split('\r')
+ for c in range(len(chunks)):
+ chunks[c] = os.linesep.join(chunks[c].split('\n'))
+ lines[l] = os.linesep.join(chunks)
+ text = os.linesep.join(lines)
+ return text
+
+ def prompt(self): # Autoindent added!!!
+ """Display proper prompt for the context: ps1, ps2 or ps3.
+
+ If this is a continuation line, autoindent as necessary."""
+ # TODO : How much of this can I do away with now without prompts??
+
+ isreading = self.reader.isreading
+
+ skip = True
+ if isreading:
+ prompt = str(sys.ps3)
+ elif self.more:
+ prompt = str(sys.ps2)
+ else:
+ prompt = str(sys.ps1)
+ pos = self.GetCurLine()[1]
+ if pos > 0:
+ if isreading:
+ skip = True
+ else:
+ self.write(os.linesep,type='Input')
+ if not self.more:
+ # Not needed anymore! # self.promptPosStart = self.GetCurrentPos()
+ pass
+ if not skip:
+ self.write(prompt,type='Input')
+ if not self.more:
+ # Not needed anymore! # self.promptPosEnd = self.GetCurrentPos()
+ # Clear the undo history after running a command.
+ self.EmptyUndoBuffer()
+
+ #DNM/CP
+ # Autoindent magic
+ # Match the indent of the line above
+ # UNLESS the line above ends in a colon...then add four spaces
+ # (after valid keywords (if, else, etc...) only)
+ if self.more:
+ line_num=self.GetCurrentLine()
+ currentLine=self.GetLine(line_num)
+ previousLine=self.GetLine(line_num-1)
+ pstrip=previousLine.strip()
+ lstrip=previousLine.lstrip()
+
+ if pstrip == '':
+ # because it is all whitespace!
+ indent=previousLine.strip('\n').strip('\r')
+ else:
+ indent=previousLine[:(len(previousLine)-len(lstrip))]
+ if testForContinuations(previousLine,ignoreErrors=True)[1][0]:
+ indent+=' '*4
+
+ #ADD UNDO
+ cpos=self.GetCurrentPos()
+ s=indent
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+
+ self.EnsureCaretVisible()
+ self.ScrollToColumn(0)
+
+ def readline(self):
+ """Replacement for stdin.readline()."""
+ input = ''
+ reader = self.reader
+ reader.isreading = True
+ self.prompt()
+
+ # Ensure that we get a new line and that it's got an input marker...
+ # Also need to temporarily block any other action...
+ cLine = self.GetCurrentLine()
+ self.clearIOMarkers(cLine)
+ self.MarkerAdd(cLine,INPUT_START)
+ self.MarkerAdd(cLine,READLINE_BG)
+ self.MarkerAdd(cLine,INPUT_READLINE)
+
+ try:
+ while not reader.input:
+ wx.YieldIfNeeded()
+ input = reader.input
+ finally:
+ start,end = self.GetIOSlice()
+ start = self.runningSlice[1] + 1
+ for i in range(start,end+1):
+ self.clearIOMarkers(i)
+ self.clearGroupingMarkers(i)
+ self.MarkerAdd(i,OUTPUT_BG)
+ if i == start: self.MarkerAdd(i,OUTPUT_START)
+ elif i==end: self.MarkerAdd(i,OUTPUT_END)
+ else: self.MarkerAdd(i,OUTPUT_MIDDLE)
+
+ if i==end: self.MarkerAdd(i,GROUPING_END)
+ else: self.MarkerAdd(i,GROUPING_MIDDLE)
+ reader.input = ''
+ reader.isreading = False
+ input = str(input) # In case of Unicode.
+ return input
+
+ def readlines(self):
+ """Replacement for stdin.readlines()."""
+ lines = []
+ while lines[-1:] != ['\n']:
+ lines.append(self.readline())
+ return lines
+
+ def raw_input(self, prompt=''):
+ """Return string based on user input."""
+ if prompt:
+ self.write(prompt,type='Output')
+ return self.readline()
+
+ def ask(self, prompt='Please enter your response:'):
+ """Get response from the user using a dialog box."""
+ dialog = wx.TextEntryDialog(None, prompt,
+ 'Input Dialog (Raw)', '')
+ try:
+ if dialog.ShowModal() == wx.ID_OK:
+ text = dialog.GetValue()
+ return text
+ finally:
+ dialog.Destroy()
+ return ''
+
+ def pause(self):
+ """Halt execution pending a response from the user."""
+ self.ask('Press enter to continue:')
+
+ def clear(self):
+ """Delete all text from the slices shell."""
+ self.ClearAll()
+ self.MarkerAdd(0,GROUPING_START)
+ self.MarkerAdd(0,INPUT_START)
+
+ def run(self, command, prompt=True, verbose=True):
+ """Execute command as if it was typed in directly.
+ >>> shell.run('print "this"')
+ >>> print "this"
+ this
+ >>>
+ """
+ # Go to the very bottom of the text.
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ command = command.rstrip()
+ if prompt: self.prompt()
+ if verbose: self.write(command,type='Input')
+ self.push(command)
+
+ # TODO : Will have to fix this to handle other kinds of errors mentioned before...
+ def runfile(self, filename):
+ """Execute all commands in file as if they were typed into the shell."""
+ file = open(filename)
+ try:
+ self.prompt()
+ for command in file.readlines():
+ if command[:6] == 'shell.':
+ # Run shell methods silently.
+ self.run(command, prompt=False, verbose=False)
+ else:
+ self.run(command, prompt=False, verbose=True)
+ finally:
+ file.close()
+
+ def autoCompleteShow(self, command, offset = 0):
+ """Display auto-completion popup list."""
+ self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
+ self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+ list = self.interp.getAutoCompleteList(command,
+ includeMagic=self.autoCompleteIncludeMagic,
+ includeSingle=self.autoCompleteIncludeSingle,
+ includeDouble=self.autoCompleteIncludeDouble)
+ if list:
+ options = ' '.join(list)
+ #offset = 0
+ self.AutoCompShow(offset, options)
+
+ 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='SlicesShell.calltip', sender=self, calltip=tip)
+ if not self.autoCallTip and not forceCallTip:
+ return
+ startpos = self.GetCurrentPos()
+ if argspec and insertcalltip and self.callTipInsert:
+ # write with undo history...
+ cpos=self.GetCurrentPos()
+ s=argspec + ')'
+ self.UpdateUndoHistoryBefore('insert',s,cpos,cpos+len(s))
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+ endpos = self.GetCurrentPos()
+ self.SetSelection(startpos, endpos)
+ if tip:
+ tippos = startpos - (len(name) + 1)
+ fallback = startpos - self.GetColumn(startpos)
+ # In case there isn't enough room, only go back to the 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.PositionFromLine(self.GetIOSlice()[0])
+
+ 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.PositionFromLine(self.GetIOSlice()[0])
+ 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."""
+ self.write(text,type='Output')
+ # TODO : FLUSH?? How to make this update real-time...
+
+ def writeErr(self, text):
+ """Replacement for stderr."""
+ self.write(text,type='Error')
+
+ def redirectStdin(self, redirect=True):
+ """If redirect is true then sys.stdin will come from the shell."""
+ if redirect:
+ sys.stdin = self.reader
+ else:
+ sys.stdin = self.stdin
+
+ def redirectStdout(self, redirect=True):
+ """If redirect is true then sys.stdout will go to the shell."""
+ if redirect:
+ sys.stdout = PseudoFileOut(self.writeOut)
+ else:
+ sys.stdout = self.stdout
+
+ def redirectStderr(self, redirect=True):
+ """If redirect is true then sys.stderr will go to the shell."""
+ if redirect:
+ sys.stderr = PseudoFileErr(self.writeErr)
+ else:
+ sys.stderr = self.stderr
+
+ # Take a spashot of the WHOLE grouping slice (or slices)
+ # The argument s is either what got added or deleted
+ def UpdateUndoHistoryBefore(self,actionType,s,posStart,posEnd,
+ forceNewAction=False):
+ uH=self.undoHistory
+ uI=self.undoIndex
+
+ s=s.replace(os.linesep,'\n')
+ startLine=self.LineFromPosition(posStart)
+
+ if actionType=='marker':
+ numLines = self.LineFromPosition(posEnd) - startLine
+ else:
+ numLines=s.count('\n')
+
+ makeNewAction=forceNewAction
+
+ if forceNewAction:
+ makeNewAction=True
+ elif self.undoIndex==-1:
+ makeNewAction=True
+ elif not uH[uI]['allowsAppend']:
+ makeNewAction=True
+ elif actionType!=uH[uI]['actionType']:
+ makeNewAction=True
+ elif actionType=='insert':
+ if posStart!=uH[uI]['posEnd']:
+ makeNewAction=True
+ else: # This is a continuation of the previous insert
+ uH[uI]['charList'] = uH[uI]['charList']+s
+ uH[uI]['posEnd'] = posEnd # posStart cannot move
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
+ elif actionType=='delete':
+ # This is a forward continuation of the previous delete
+ if posStart==uH[uI]['posStart']:
+ uH[uI]['charList'] = uH[uI]['charList']+s
+ uH[uI]['posEnd'] = posEnd
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
+ # This is a backward continuation of the previous delete
+ elif posEnd==uH[uI]['posStart']:
+ uH[uI]['charList'] = s+uH[uI]['charList']
+ uH[uI]['posStart'] = posStart
+ uH[uI]['startLine'] = startLine
+ uH[uI]['numLines'] = uH[uI]['numLines']+numLines
+ else:
+ makeNewAction=True
+
+ elif actionType=='marker':
+ makeNewAction=True
+ else:
+ pass #print 'Unsupported Action Type!!'
+
+ if makeNewAction:
+ del(self.undoHistory[uI+1:]) # remove actions after undoIndex
+
+ uH.append({
+ 'actionType' : actionType, # Action type ('insert','delete','marker')
+ 'allowsAppend': not forceNewAction, # Can action be joined with others?
+ 'charList' : s, # Character list
+ 'posStart' : posStart, # Cursor poition at the start of the action
+ 'posEnd' : posEnd, # Cursor position at the end of the action
+ 'startLine' : startLine, # Start line number,
+ 'numLines' : numLines, # Number of newlines involved
+ 'mBStart' : None, # Starting line for markers BEFORE action
+ 'mAStart' : None, # Starting line for markers AFTER action
+ 'markersBefore' : None, # [markers BEFORE action]
+ 'markersAfter' : None # [markers AFTER action]
+ })
+
+ self.undoIndex+=1
+
+ # Only update the before when starting a new action
+ start = startLine
+ if actionType=='insert':
+ end = start
+ else:
+ end = start + numLines
+
+ # Update Marker Info
+ newStart=self.GetGroupingSlice(start)[0]
+ newEnd=self.GetGroupingSlice(end)[1]
+ self.undoHistory[self.undoIndex]['markersBefore'] = \
+ [self.MarkerGet(i) for i in range(newStart,newEnd+1)]
+ self.undoHistory[self.undoIndex]['mBStart']=newStart
+
+ self.doHistUpdate=True
+
+ def UpdateUndoHistoryAfter(self): # s is either what got added or deleted
+ start = self.undoHistory[self.undoIndex]['startLine']
+ if self.undoHistory[self.undoIndex]['actionType']=='delete':
+ end = start
+ else:
+ end = start + self.undoHistory[self.undoIndex]['numLines']
+
+ newStart=min(self.GetGroupingSlice(start)[0]-1, 0)
+ newEnd=max(self.GetGroupingSlice(end)[1]+1, self.GetLineCount()-1)
+ self.undoHistory[self.undoIndex]['markersAfter'] = \
+ [self.MarkerGet(i) for i in range(newStart,newEnd+1)]
+ self.undoHistory[self.undoIndex]['mAStart']=newStart
+
+ self.doHistUpdate=False
+
+ def Undo(self):
+ #ADD UNDO
+ #Skip undo if there are no actions...
+ if self.undoIndex==-1:
+ return
+
+ uHI=self.undoHistory[self.undoIndex]
+
+ if uHI['actionType'] in ['insert','delete']:
+ # This will perform the opposite of the action given
+ editwindow.EditWindow.Undo(self)
+ elif uHI['actionType']=='marker': # No text changed, don't pass to STC
+ pass
+ else:
+ #print 'Unsupported actionType in undoHistory!!'
+ return
+
+ numLines=len(uHI['markersBefore'])
+ for i in range(numLines):
+ self.MarkerSet( uHI['mBStart']+i , uHI['markersBefore'][i] )
+
+ self.undoIndex-=1
+
+ def Redo(self):
+ #ADD UNDO
+ # First check to see if there are any redo operations available
+ # Note that for redo, undoIndex=-1 is a valid input
+ if self.undoIndex >= len(self.undoHistory)-1:
+ return
+ self.undoIndex+=1
+ uHI=self.undoHistory[self.undoIndex]
+
+ if uHI['actionType'] in ['insert','delete']:
+ # This will re-perform the given action
+ editwindow.EditWindow.Redo(self)
+ elif uHI['actionType']=='marker': # No text changed, don't pass to STC
+ pass
+ else:
+ #print 'Unsupported actionType in undoHistory!!'
+ return
+
+ numLines=len(uHI['markersAfter'])
+ for i in range(numLines):
+ self.MarkerSet( uHI['mAStart']+i , uHI['markersAfter'][i] )
+
+ def EmptyUndoBuffer(self):
+ editwindow.EditWindow.EmptyUndoBuffer(self)
+ self.undoIndex=-1
+ self.undoHistory=[]
+ self.doHistUpdate=False
+
+ def CanCut(self):
+ return self.CanEdit() and \
+ (self.GetSelectionStart() != self.GetSelectionEnd())
+
+ def CanPaste(self):
+ """Return true if a paste should succeed."""
+ if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
+ return True
+ else:
+ return False
+
+ def CanEdit(self):
+ """Return true if editing should succeed."""
+ marker=self.MarkerGet(self.GetCurrentLine())
+
+ if marker & OUTPUT_MASK:
+ return False
+ elif marker & INPUT_MASK:
+ if self.reader.isreading and not \
+ (self.MarkerGet(self.GetCurrentLine()) & 1<<INPUT_READLINE ):
+ return False
+ start,end=self.GetIOSlice()
+ sliceStartPos=self.PositionFromLine(start)
+ sliceEndPos=self.GetLineEndPosition(end)
+ """Return true if text is selected and can be cut."""
+ if self.GetSelectionStart() == self.GetSelectionEnd():
+ return True
+ elif self.GetSelectionStart() != self.GetSelectionEnd() \
+ and self.GetSelectionStart() >= sliceStartPos \
+ and self.GetSelectionEnd() >= sliceStartPos \
+ and self.GetSelectionStart() <= sliceEndPos \
+ and self.GetSelectionEnd() <= sliceEndPos:
+ return True
+ else:
+ return False
+
+ def Cut(self):
+ """Remove selection and place it on the clipboard."""
+ if self.CanCut() and self.CanCopy():
+ if self.AutoCompActive():
+ self.AutoCompCancel()
+ if self.CallTipActive():
+ self.CallTipCancel()
+ self.Copy()
+ self.ReplaceSelection('')
+
+ def Copy(self):
+ """Copy selection and place it on the clipboard."""
+ if self.CanCopy():
+ ps1 = str(sys.ps1)
+ ps2 = str(sys.ps2)
+ command = self.GetSelectedText()
+ command = command.replace(os.linesep + ps2, os.linesep)
+ command = command.replace(os.linesep + ps1, os.linesep)
+ command = self.lstripPrompt(text=command)
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def CopyWithPrompts(self):
+ """Copy selection, including prompts, and place it on the clipboard."""
+ if self.CanCopy():
+ command = self.GetSelectedText()
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def CopyWithPromptsPrefixed(self):
+ """Copy selection, including prompts prefixed with four
+ spaces, and place it on the clipboard."""
+ if self.CanCopy():
+ command = self.GetSelectedText()
+ spaces = ' ' * 4
+ command = spaces + command.replace(os.linesep,
+ os.linesep + spaces)
+ data = wx.TextDataObject(command)
+ self._clip(data)
+
+ def _clip(self, data):
+ if wx.TheClipboard.Open():
+ wx.TheClipboard.UsePrimarySelection(False)
+ wx.TheClipboard.SetData(data)
+ wx.TheClipboard.Flush()
+ wx.TheClipboard.Close()
+
+ def Paste(self):
+ """Replace selection with clipboard contents."""
+
+ #ADD UNDO
+ if self.CanPaste() and wx.TheClipboard.Open():
+ ps2 = str(sys.ps2)
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+ data = wx.TextDataObject()
+ if wx.TheClipboard.GetData(data):
+ self.ReplaceSelection('')
+ command = data.GetText()
+ command = command.rstrip()
+ command = self.fixLineEndings(command)
+ command = self.lstripPrompt(text=command)
+ # TODO : This is still useful... Add it back other places?
+ command = command.replace(os.linesep + ps2, '\n')
+ command = command.replace(os.linesep, '\n')
+ #DNM--Don't use '... '
+ command = command.replace('\n', os.linesep)# + ps2)
+
+ cpos=self.GetCurrentPos()
+ s=command
+ self.UpdateUndoHistoryBefore('insert', s, cpos,
+ cpos+len(s), forceNewAction=True)
+ self.write(s,type='Input')
+ self.UpdateUndoHistoryAfter()
+
+ # Makes paste -> type -> undo consistent with other STC apps
+ self.ReplaceSelection('')
+ wx.TheClipboard.Close()
+
+
+ def PasteAndRun(self):
+ """Replace selection with clipboard contents, run commands."""
+ text = ''
+ if wx.TheClipboard.Open():
+ if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+ data = wx.TextDataObject()
+ if wx.TheClipboard.GetData(data):
+ text = data.GetText()
+ wx.TheClipboard.Close()
+ if text:
+ self.Execute(text)
+
+
+ def Execute(self, text):
+ """Replace selection with text and run commands."""
+ start,end=self.GetIOSlice()
+ startpos=self.PositionFromLine(start)
+ endpos=self.GetLineEndPosition(end)
+
+ self.SetCurrentPos(endpos)
+ self.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+
+ hasSyntaxError=False
+ result = self.BreakTextIntoCommands(command)
+ if result[0] == None:
+ commands=[command]
+ hasSyntaxError=True
+ else:
+ commands=result
+
+ for command in commands:
+ command = command.replace('\n', os.linesep)
+ self.write(command)
+ self.processLine()
+
+ def wrap(self, wrap=True):
+ """Sets whether text is word wrapped."""
+ try:
+ self.SetWrapMode(wrap)
+ except AttributeError:
+ return 'Wrapping is not available in this version.'
+
+ def zoom(self, points=0):
+ """Set the zoom level.
+
+ 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))
+
+ 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('View/WrapMode', self.GetWrapMode())
+ config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
+ config.WriteInt('View/Zoom/Shell', self.GetZoom())
+
+ def GetContextMenu(self):
+ """
+ Create and return a context menu for the slices shell.
+ This is used instead of the scintilla default menu
+ in order to correctly respect our immutable buffer.
+ """
+ menu = wx.Menu()
+ menu.Append(wx.ID_UNDO, "Undo")
+ menu.Append(wx.ID_REDO, "Redo")
+
+ menu.AppendSeparator()
+
+ menu.Append(wx.ID_CUT, "Cut")
+ menu.Append(wx.ID_COPY, "Copy")
+ menu.Append(frame.ID_COPY_PLUS, "Copy Plus")
+ menu.Append(wx.ID_PASTE, "Paste")
+ menu.Append(frame.ID_PASTE_PLUS, "Paste Plus")
+ menu.Append(wx.ID_CLEAR, "Clear")
+
+ menu.AppendSeparator()
+
+ menu.Append(wx.ID_SELECTALL, "Select All")
+ return menu
+
+ def OnContextMenu(self, evt):
+ menu = self.GetContextMenu()
+ self.PopupMenu(menu)
+
+ def OnUpdateUI(self, evt):
+ id = evt.Id
+ if id in (wx.ID_CUT, wx.ID_CLEAR):
+ evt.Enable(self.CanCut())
+ elif id in (wx.ID_COPY, frame.ID_COPY_PLUS):
+ evt.Enable(self.CanCopy())
+ elif id in (wx.ID_PASTE, frame.ID_PASTE_PLUS):
+ evt.Enable(self.CanPaste())
+ elif id == wx.ID_UNDO:
+ evt.Enable(self.CanUndo())
+ elif id == wx.ID_REDO:
+ evt.Enable(self.CanRedo())
+
+ def LoadPySlicesFile(self,fid):
+ invalidFileString = 'Not a valid input format'
+ lineCount=0
+ groupingStartLines=[0]
+ ioStartLines=[0]
+ ioStartTypes=[]
+ removeComment=False
+
+ # Read the initial three (or four) lines that have version and marker information
+ line=fid.readline()
+ if line == usrBinEnvPythonText:
+ line=fid.readline() # Add the option to place #!/usr/bin/env python2 at the top
+ if line not in pyslicesFormatHeaderText: print invalidFileString ; return
+ line=fid.readline()
+ if line != groupingStartText: print invalidFileString ; return
+ line=fid.readline()
+ if line == inputStartText: ioStartTypes.append('input');removeComment=False
+ elif line == outputStartText: ioStartTypes.append('output');removeComment=True
+ else: print invalidFileString ; return
+
+ self.ClearAll()
+
+ # Write the file's text to the text area
+ # Capture Marker information to
+ for i in fid:
+ if i==groupingStartText:
+ groupingStartLines.append(lineCount)
+ elif i==inputStartText:
+ ioStartLines.append(lineCount)
+ ioStartTypes.append('input')
+ removeComment=False
+ elif i==outputStartText:
+ ioStartLines.append(lineCount)
+ ioStartTypes.append('output')
+ removeComment=True
+ else:
+ if removeComment: w=i[1:].replace(os.linesep,'\n')
+ else: w=i.replace(os.linesep,'\n')
+ self.write(w,'Input',silent=True)
+ lineCount+=1
+
+ if w[-1]=='\n':
+ lineCount+=1
+
+ for i in range(lineCount+1):
+ self.clearGroupingMarkers(i)
+ self.clearIOMarkers(i)
+
+ doMiddle=False
+ doEnd=False
+ if groupingStartLines!=[]:
+ if i == groupingStartLines[0]:
+ self.MarkerAdd(i,GROUPING_START)
+ del groupingStartLines[0]
+ elif i+1 == groupingStartLines[0]:
+ doEnd=True
+ else:
+ doMiddle=True
+ elif i==lineCount-1:
+ doEnd=True
+ else:
+ doMiddle=True
+
+ if doMiddle:
+ self.MarkerAdd(i,GROUPING_MIDDLE)
+ elif doEnd:
+ self.MarkerAdd(i,GROUPING_END)
+
+ doMiddle=False
+ doEnd=False
+ if ioStartLines!=[]:
+ if i == ioStartLines[0]:
+ # Delete the old ioStartTypes (keep the current copy for later use)
+ if i>0: del ioStartTypes[0]
+
+ if ioStartTypes[0]=='input':
+ self.MarkerAdd(i,INPUT_START)
+ elif ioStartTypes[0]=='output':
+ self.MarkerAdd(i,OUTPUT_START)
+ self.MarkerAdd(i,OUTPUT_BG)
+ else:
+ #print 'Invalid Type!';
+ return
+
+ # Only delete markers we are totally finished with...
+ # Keep one more "StartTypes" than "StartLines"
+ del ioStartLines[0]
+ elif i+1 == ioStartLines[0]:
+ doEnd=True
+ else:
+ doMiddle=True
+ elif i==lineCount-1:
+ doEnd=True
+ else:
+ doMiddle=True
+
+ if doMiddle:
+ if ioStartTypes[0]=='input':
+ self.MarkerAdd(i,INPUT_MIDDLE)
+ elif ioStartTypes[0]=='output':
+ self.MarkerAdd(i,OUTPUT_MIDDLE)
+ self.MarkerAdd(i,OUTPUT_BG)
+ else:
+ #print 'Invalid Type!';
+ return
+ elif doEnd:
+ if ioStartTypes[0]=='input':
+ self.MarkerAdd(i,INPUT_END)
+ elif ioStartTypes[0]=='output':
+ self.MarkerAdd(i,OUTPUT_END)
+ self.MarkerAdd(i,OUTPUT_BG)
+ else:
+ #print 'Invalid Type!';
+ return
+
+ self.EmptyUndoBuffer() # maybe not?
+
+
+ def SavePySlicesFile(self,fid):
+ addComment=False
+ fid.write(usrBinEnvPythonText.replace('\n',os.linesep))
+ fid.write(pyslicesFormatHeaderText[-1].replace('\n',os.linesep))
+ for i in range(self.GetLineCount()):
+ markers=self.MarkerGet(i)
+ if markers & ( 1<<GROUPING_START | 1<<GROUPING_START_FOLDED ):
+ fid.write(groupingStartText.replace('\n',os.linesep))
+ if markers & ( 1<<INPUT_START | 1<<INPUT_START_FOLDED ):
+ fid.write(inputStartText.replace('\n',os.linesep))
+ addComment=False
+ if markers & ( 1<<OUTPUT_START | 1<<OUTPUT_START_FOLDED ):
+ fid.write(outputStartText.replace('\n',os.linesep))
+ addComment=True
+ if addComment: fid.write('#')
+ fid.write(self.GetLine(i).replace('\n',os.linesep))
+
+ # FIX ME!!
+ def LoadPyFileAsSlice(self,fid):
+ curpos=self.GetCurrentPos()
+ start,end = self.GetGroupingSlice()
+
+ endpos=self.GetLineEndPosition(end)
+ self.SetCurrentPos(endpos)
+ self.SetSelection(endpos, endpos)
+
+ text='\n'+fid.read()
+ self.write(text,'Input')
+ newpos=self.GetCurrentPos()
+
+ self.SetCurrentPos(curpos)
+ self.SetSelection(curpos,curpos)
+ self.SplitSlice()
+ #self.SetCurrentPos(newpos)
+ #self.SetSelection(newpos,newpos)
+
+ def hasChanged(self):
+ """Return True if contents have changed."""
+ return self.GetModify() or self.NeedsCheckForSave
+
+
+
+## NOTE: The DnD of file names is disabled until we 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, sliceshell):
+## wx.DropTarget.__init__(self)
+## self.sliceshell = sliceshell
+## 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.sliceshell.AppendText(txt)
+## pos = self.sliceshell.GetCurrentPos()
+## self.sliceshell.SetCurrentPos( pos )
+## self.sliceshell.SetSelection( pos, pos )
+
+## return result
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/py/version.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/version.py
new file mode 100644
index 0000000..d47909d
--- /dev/null
+++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/py/version.py
@@ -0,0 +1,9 @@
+"""Provides an object representing the current 'version' or 'release'
+of Py as a whole. Individual classes, such as the shell, filling and
+interpreter, each have a revision property based on the CVS Revision."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+VERSION = '0.9.8'