spe-0.8.4.h/0000755000175000017500000000000011004131466011552 5ustar stanistanispe-0.8.4.h/spe.sgml0000644000175000017500000001126410763615034013242 0ustar stanistani manpage.1'. You may view the manual page with: `docbook-to-man manpage.sgml | nroff -man | less'. A typical entry in a Makefile or Makefile.am is: manpage.1: manpage.sgml docbook-to-man $< > $@ The docbook-to-man binary is found in the docbook-to-man package. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include docbook-to-man in your Build-Depends control field. --> Stefano"> Canepa"> November 25, 2007"> 1"> <sc@linux.it>"> SPE"> Debian"> GNU"> GPL"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2007 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; Platform independent pluggable Python IDE &dhpackage; <script-name1> <script-name2> DESCRIPTION This manual page documents briefly spe. This manual page was written for the &debian; distribution because the original program does not have a manual page. spe (Stani's Python Editor) is an Integrated Development Editor for the Python programming language (fully compatible with Blender). spe has an editor with syntax highligthing and code completion, can generate UML diagram and code documentation using pydoc. spe is written using wxWidgets and integrate wxGlade and XRCed as plugins to make GUI creation easier. spe can also use pychecker for code check and winpdb to debug python code. OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Prints debug information usefull to add to bug report. Start spe with the selected workspace. If none spe opens the default workspace. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2, as published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License, Version 2, can be found in /usr/share/common-licenses/GPL-2.
spe-0.8.4.h/spe.desktop0000644000175000017500000000041010772215244013737 0ustar stanistani [Desktop Entry] Name=SPE (Stani's Python Editor) Comment=Integrated Python Development Environment Exec=/usr/bin/spe Icon=spe Terminal=false Type=Application Categories=Development;IDE;Debugger;GUIDesigner; StartupNotify=true MimeType=text/x-python; GenericName= spe-0.8.4.h/NEWS0000644000175000017500000012326111003655422012260 0ustar stanistaniThese are the changes of the public releases: Spe 0.8 ------- [4.g] Fixes: * fix "browse folder" * fix wxglade on fedora * fix warning when a file has been deleted [4.h] Fixes: * XRCed is now optional * file permissions and mixed line endings [4.f] Fixes: * SPE.py crashed with IndexError in OnProcessEnded() * can't turn off remember files * Class Definition below an if statement * Deleted files are not seen as changed * spaces in filenames... gronk! * Unnecessary question on closing empty file * Recent filename in the titlebar after closing all files * SPE.py crashed with IndexError in onFrameTab() (Closes LP #200439) * SPE.py crashed with PyDeadObjectError in __getattr__() (Closes LP #202481) * SPE.py crashed with ValueError in SetPageText() (Closes LP #207024) * Fix copy in output window [4.e] New features: * SPE blender server: interact in realtime with Blender through PyCrust or Ipython shell Major bugfix release: * Comment and Uncomment keyboard shortcuts fixed for Mac * Finding in Folded Items Fixed (closes Berlios #10688) * Launching Kiki when installed on the system * Index tab in sidebar (closes launchpad #204751) * pychecker integration * XRCed integration [4.d] Major bugfix release: * Rewrite of internal code to fix cpu leak when SPE is not in focus * Blender fix (Witold) * Kiki Windows path [4.c] New features: * new versions of WinPdb debugger, PyChecker, wxGlade & XRCed gui designer * clear output pane * support for wxPython 2.8 * linux support for nautilus, gnome-terminal, konqueror, konsole, thunar * improved blender support up to 2.45 (by Witold) Fixes: * sidebar sash more tolerant * show path in title (linux) * run with filename with spaces * nicer debug dialog box * kill process fix * notebook * insert signature * numpad keys (by isolationism) * find tab with nonexisting files * add environment to SPE.py (linux) * better warning for documentation for unsaved files * better handling of new empty files * many more... Spe 0.7 ------- [4.a] Major bugfix release for wxPython 2.6+ (This version doesn't work for sure with wxPython versions lower than 2.5.4.1) Bug reports which are related to wxPython <2.6 will be ignored. [3.a] Major bugfix release for wxPython 2.5.4.1 [2.a] The sidebar now features a file browser. I'm now trying to form a team for future development of SPE. Besides me four people will join the project: - Sam Widmer for CVS and bugfixes. So soon more collaboration on SPE will be possible. - Nir Aides (author of rpdb) for helping implementing the remote debugger - Kevin Walzer for the OS X Port of SPE. Please contact him for Mac specific issues. Spe for the Mac will be distributed through: http://www.wordtech-software.com/spe.html - Jelle Feringa for documentation. The goal is to provide a pdf manual with the SPE distribution based on the SPE wiki: http://www.stani.be/spe/wiki Anyone who has comments or wants to edit the wiki as well can contact Jelle. If you like SPE, please contribute by coding, writing documentation or donating. I would like to thank especially Michael Balk, who gave the largest donation ever to SPE. Also I would like to thank Michael Foord, who made SPE part of a new Python distribution, called "movable python". It gives you the possibility to carry your favorite developping environment on a USB stick. So you can continue your work on any computer or test your modules for different python versions. This distribution opens a lot of new possibilities, check it out!! For more info, visit http://www.voidspace.org.uk/python/programs.shtml#movpy [1.a] I asked the ubuntu people for a python bounty in order to be get some funding to implement a debugger in SPE. Please support this. Also I want to put up a sponsering plan for SPE, comparable to eg Blender or PyCon. Till now I only receive sponsering from zettai_ Is there anyone with some experience who could give some advice? There were a lot of nice reactions on the previous release. Mario Lacunza even gave me my first gmail account and offered help to translate SPE in Spanish. Anyway here you get another SPE release with again a new feature: XRCed_, an xrc editor. Just like wxGlade, it is a tool to design GUIs with wxPython_. A bug prevented the uml view when there was only one class. This is fixed now. [0.a] As a christmas present SPE offers you a built-in Python UML viewer. An Uml diagram is hierarchal 2d map of your classes. See http://spe.pycs.net/pictures/800x600/11.html for a nice screenshot. Attentive users notice that the uml view also uses the separators of the class explorer for a better outline. Once you get used to it, you can't live without. Recently I also have been helping Michael Foord with 'movable python', a python distro (including SPE!) which can run from a usb stick with no need for installing. It's more handy than a laptop to carry your favorite Python environment around. More about that later... I see that still a lot of people are unfortunately downloading old tar.gz versions. This makes absolutely no sense!! Because of problems with tar.gz archives on the blender website, Linux and Mac users must download the zip archive. I release them especially for that purpose. The exe installer is of course for Windows. Also from now on blenpy will be discontinued. Nobody seems to use it anyway. If you don't know what blenpy is, ... that's exactly what I mean. A special thanks for everyone who donates. That always pushes me to next release (hint,hint,...) :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: [4.y] - editor: close pages by double or middle-clicking on their tab - Mac OsX: single and multiple document interface [4.a] - editor: call-tips for classes - preferences: configurable shortcuts (see shortcuts/__init__.py) - preferences: word characters for autocompletion and calltips - sidebar: realtime updating now works - sidebar: improved browser with filters [2.a] - sidebar browser (iniated by Attila Magyar) [1.a] - XRC editor [0.a] - Uml viewer :Bug fixes: [4.y] - Blender: SPE runs inside Blender again [4.q] - preferences: possible patch - menu: close [4.p] - menu: open [4.a] - major bugfix for wxpython 2.6+ - major bugfix for Mac OS X - notebooksizer deprecations - blender: support only exposed if run inside blender - editor: autocompletion (case sensitive) - editor: correctly scrolling to lines - editor: encoding - editor: improved call tips for classes - editor: no sash, no crash - editor: save checks if file exists - editor: scrollbars (no invisible source anymore) - editor: source gets focus properly - editor: find dialog gets focus if already opened - editor: shortcut for dedent is now Shift+Tab - preferences: added word characters - sdi: Tool pane has no toolbar - shell: pressing Tab no longer inserts a tab in the editor - sidebar: realtime updating - tool: find now also executes on enter - tool: find doesn't use notebooksizer anymore - tool: find now also executes on enter (Yoyong Hernan) - tool: browser add new folder starts from current folder (Yoyong Hernan) [3.a] - major bugfix for wxpython 2.5.4.1 [2.c] - right click menu now works (Thurston Stone) - pychecker tab - window handling (maximize etc...) [2.b] - launch wxGlade GUI designer and XRC editor [2.a] - segfaults in Browser - indentation can now be different from 4 - mac osx fixes for kiki, wxGlade & XRC - scrollbars of UML view - initial sizing and positioning are now restored [1.a] - uml view crashed when only 1 class was present - mac menu fix for preferences, about & exit - some icons are fixed by Jeff Grimmett :Requirements: - full python 2.3+ - wxpython 2.5.4.1+ - optional blender 2.35 :Donations: [3.a] (20 euro) - Gerard Blais [2.c] (50 euro) - Mike (Partner2Partner) [2.a] (177.20euro) - Michael Balk (60euro!) - Jason Powell - David Ko Feng - Winchell Chung - Matthias Haberkorn - Kristjan Kannike - Robert Cowham - Andre Roberge - Chris S [0.a] (10euro) - Brendan Simons :Contributors: - Yoyong Hernan - Sam Widmer - Attila Magyar - Kevin Walzer - Thurston Stone Spe 0.6.0 --------- I'm happy to announce the first SPE release aimed for the Mac Os X platform. There might be still some minor issues, but if reported they might be fixed soon. All mac feedback is welcome. This release was possible by Xavier Nora who offered me access to his Mac through VNC. If SPE doesn't startup on your Mac, probably your wxPython version is too old. Now SPE also has real built-in support for encoding, so SPE can now deal with the most strange languages in the world. If the encoding is defined in the file it will appear in the sidebar. :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: [a] - encoding - toolBar for Mac OS X - blender script spe_blender.py to register spe in Blender script menu (copy to .blender/scripts) :Bug fixes: [a] - new icons :Requirements: - full python 2.3+ - wxpython 2.5.2.8+ - optional blender 2.35 :Contributors: [a] - Xavier Noria (http://www.hashref.com) - Jean Montambeault (blender script) :Donations (thanks!): - Oliver Tomic Spe 0.5.2 --------- Release adapted to the latest wxGlade and Blender. :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: [a] - wxGlade 0.3.5.1 - Blender: Sound and Registry support in Blender Browser :Bug fixes: [a] - Blender browser - anti-aliasing for Mac OS X - find wxPython 2.5.3 documentation (Windows only) :Requirements: - full python 2.3+ - wxpython 2.5.2.8+ - optional blender 2.35 :Donations (thanks!): - April Atkinson Spe 0.5.1 --------- Stable release for wxPython 2.5 :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: [h] - wxGlade 0.3.5.1 [b] - context-fed auto completion (Ctrl+Space) - drag & drop support for \*.tpy files [a] - both MDI/SDI support - Mac OS X support (probably still need a lot of debugging, volunteers needed) - tabs with open files - realtime sidebar (class explorer, todo & index update as you type!) - wxPython 2.5 support (latest 2.4 also still supported) - option to limit calltips to first paragraph - speed improvements, SPE runs now more fast, especially the sidebar - dynamic sash window for source code (allowing simultaneous splitted views) - Pychecker has been smoothly integrated in the sidebar :Bug fixes: [h] - double scrollbars [g] - better tab indentation fix - activepython documentation can be combined with the enthought distribution - jump to source fix - function names def* truncated in explore - "Save changes to" doesn't show document - File|Exit should use X as accel key - Ctrl-F doesn't switch to open "Find" dlg - bug in importing modules to shell - Edit Preferences [f] - tab indentation fix - htmlWindow fix [e] - This release works with the new wxPython 2.5.2.7 [b] - maximize new windows in MDI - recent files are now alphabetically ordered - uncomment now works properly - spe scripts should now install properly - menu links to files (mac issue) - better save method to prevent data loss [a] - Blender support is again enabled - Icon transparencies on certain platforms - setup.py doesn't have line endings anymore :Requirements: - full python 2.2.2+ - wxpython 2.4.1.2+ - optional blender 2.31+ :Donations (thanks!): - Manuel Ulloa - Anne Ebel - Eino Makitalo - Michael Balk - Kyle Odom - Dov Nir Aides - Frederick Lim - John Fabiani - Dagur Ammendrup Spe 0.5.0 --------- This is a major rewrite because of wxPython 2.5. WARNING: This is a prerelease, use it at its own risk (as I do myself). It's already quite stable for Windows XP and Linux, but probably for Mac OS X a lot of debugging should be done. If you've used SPE before, remove the file 'defaults.cfg' from your user path (see Help>About if you don't know your path) before installing . Also remove the 'sm' module folder from the site-packages path. Otherwise this will cause errors. Out of the box SPE chooses automatically the framework: - MDI for Windows XP - SDI for Linux and Mac Os X However you can override these settings in the preferences dialog box, but Mac doesn't really support MDI. The Blender support is currently not available, but that should be fixed soon. PS. Alberto Griggio about current version of wxGlade (http://wxglade.sourceforge.net): WARNING: There have been reported many problems running wxGlade with the just released wxPython 2.5.1.5: we know this, and we're trying to do our best to fix them as soon as possible. In the meantime, we recommend to use wxPython 2.4: the generated code will be compatible with 2.5 anyway. Sorry for this... :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: [a] - both MDI/SDI support - Mac OS X support (probably still need a lot of debugging, volunteers needed) - tabs with open files - realtime sidebar (class explorer, todo & index update as you type!) - wxPython 2.5 support (latest 2.4 also still supported) - option to limit calltips to first paragraph - speed improvements, SPE runs now more fast, especially the sidebar - dynamic sash window for source code (allowing simultaneous splitted views) - Pychecker has been smoothly integrated in the sidebar :Bug fixes: [a] - cut, copy and paste shortcuts work now in shell - True and False are now also highlighted :Requirements: - full python 2.2.2+ - wxpython 2.4.1.2+ - optional blender 2.31+ Spe 0.4.2 --------- After some hibernation, spe is alive again. As I don't have Linux, I would like to get feedback if it is possible to run programs in terminal emulators. I would like to thank Chu-Ching Huang for including spe in livezope, his knoppix distro (bootabel Linux cd-rom). This makes it possible to run Linux and spe in Linux on any PC, without the need of installing Linux on the hard drive. You can download livezope from ftp://math.cgu.edu.tw/pub/KNOPPIX Huang is looking for mirror sites. I think this is VERY interesting to have a bootable Linux CD rom filled with all the important Python stuff, so please help him. Anyone interested can contact me :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.freezope.org/kiki/index.html - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: - Ignore list for autocompletion in preferences dialog to prevent spe crashing eg with 'gtk' autocompletion - Blender browser contains now Lattices and Textures sections - Preferences has a new tab 'Paths', which allows you to specify which html browser should be used and where documentation can be found. It also should allow *nix users to run programs outside spe in terminal emulators (this was already possible for windows). - Class browser: todo and separators definitions can now be located anywhere in the source code, thanks to a patch of Paul Evans. :Fixes: [d] - Linux spe script line endings [c] - blender python manual is updated to 2.31 - unicode bug in preferences dialog - pychecker is upgraded to latest version (0.8.13) [a] - Linux setup improved (Tina Hirsch) - info.py improved (Tina Hirsch) - unixUninstall improved (Tina Hirsch) - Blender menu was improved :Requirements: - full python_ 2.2.2+ - wxpython_ 2.4.1.2+ - optional blender_ 2.31 :Contributors: - Tina Hirsch (various patches) - Paul Evans (todo & separator patch) - Chu-Ching Huang (livezope) Spe 0.4.1 --------- Better integration with wxGlade :Batteries included: - Kiki: Regular Expression (regex) console. For more info: http://project5.tk - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: - Autoloading of externally modified files. This works very well with wxGlade! You can disable this feature in the preferences. - When 'find in files' path is empty, searches in open files - Added 'Current folder' in browsertab - Preferences entry 'Auto redraw Blender every [sec]' :Fixes: [e] - Linux setup improved (Tina Hirsch) - info.py improved (Tina Hirsch) - unixUninstall improved (Tina Hirsch) [d] - trailing spaces fix - redraw blender fix [c] - checkTime fix for closed files [b] - revert fix - unnamed.py checktime fix [a] - tab key was not working in linux - install problem as root in linux - redirectshell problem :Requirements: - full python_ 2.2.2+ - wxpython_ 2.4.1.2+ - optional blender_ 2.28c :Contributors: - Tina Hirsch (various patches) Spe 0.4.0 --------- Spe nows ships with PyChecker, for more info see: http://www.unixreview.com/documents/s=2426/uni1018986621203/0204h.htm I'm afraid spe will fail to work with Python 2.2.1, so please upgrade! :Batteries included: - Kiki: Regular Expression (regex) console. Altough still a pre-alpha release, it might be already usefull. For more info: http://project5.tk - PyChecker: PyChecker is a tool for finding bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is similar to lint. For more info: http://pychecker.sourceforge.net - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: - PyChecker - Block comment in Extra menu :Fixes: [e] - improved preferences dialog box [d] - spe now always open non-existing files as empty scripts - better icon implementation for windows [c] - plugin (kiki,wxGlade) fix [b] - winInstall fix - focus fix [a] - all Alt shortcuts are replaced by Ctrl+Alt shortcuts - improved userPath retrieval (by Greg Brunet) - editor gets focus when shifting between child windows - some minor fixes... :Requirements: - full python_ 2.3 or 2.2.2 - wxpython_ 2.4.1.2+ - optional blender_ 2.28c :Wanted: - people to help implementing new features, documenting, ... :Contributors: - Nicodemus (PyChecker integration) - Greg Brunet Spe 0.3.0 --------- Spe now ships with a minimal preference dialog box, which will be further extended. The most important editor settings can now be set, so spe can now also be used by those who prefer tabs instead of spaces. I'm afraid spe will fail to work with Python 2.2.1, so please upgrade! :Batteries included: - Kiki: Regular Expression (regex) console. Altough still a pre-alpha release, it might be already usefull. For more info: http://project5.tk - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: - preference dialog :Fixes: [c] - blenpy webbrowser fix for Linux - find dialog imports selected text (Nicodemus) - SPE_.pyw fixed [b] - sm.zfill fix - options of find tab now work - find tab layout fixed for Linux - no syntax check on python files :Requirements: - full python_ 2.3 or 2.2.2 (updated!) - wxpython_ 2.4.1.2 - optional blender_ 2.28c :Wanted: - people to help implementing new features, documenting, ... :Contributors: [c] - Nicodemus - Stuart Stock (Mac Os X screenshot) - Greg Brunet (bug report) [b] - Tina Hirsch Spe 0.2.0 --------- Spe now ships with wxGlade, a GUI designer! Screenshots are at http://wxglade.sourceforge.net/img/group.png A tutorial is included in the help menu.Now it acts independantly from spe, but the purpose is to integrate it tighter. The find tab is an example of how to extend spe with wxGlade. Spe runs now also fine inside Blender2.28c Andrei compares wxGlade to Boa: *"I like Boa and as Delphi programmer it was my first choice when I looked into GUIs. But as Python user, I find wxGlade suits my needs better, because it doesn't encourage integration of GUI and code and because of its excellent support for sizers, which are a must-have for cross-platform development. Those non-resizeable frames we are used to in Windows seem really weird to Linux users - and with good reason."* :Batteries included: - Kiki: Regular Expression (regex) console. Altough still a pre-alpha release, it might be already usefull. For more info: http://project5.tk - wxGlade: wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWindows/wxPython user interfaces. As you can guess by the name, its model is Glade, the famous GTK+/GNOME GUI builder, with which wxGlade shares the philosophy and the look & feel (but not a line of code). For more info: http://wxglade.sourceforge.net :New features: - opening an non existing files opens a new file with that filename - find tab: find recursively text in files - wxGlade: see above :Fixes: [c] - sm.zfill fix - options of find tab now work - find tab layout fixed for Linux - no syntax check on python files [b] - new Kiki version - wxGlade missing files are now included - wxGlade didn't start in Linux - setup root fix - redirect fix - todoMax error - os.path.exists typo :Requirements: - full python_ 2.2 or 2.3 - wxpython_ 2.4.1.2 - optional blender_ 2.28c :Contributors: [c] - Tina Hirsch [b] - Tina Hirsch (linux bug fixing) - Andrei (new kiki version) http://come.to/project5 [a] - the wxGlade team http://wxglade.sourceforge.net Spe 0.1.8 --------- Hopefully this release can be a milestone. For the first time it contains a plugin from an user. I would be happy if this would happen more. Any wxDialog, wxFrame or wxPanel can be easily integrated in spe. So many thanks to Andrei (http://project5.tk), who contributed Kiki, a regular expression console. :New features: [a] - Kiki: *"Kiki is a Regex tool which I think could be useful in Spe for the idiots who, like me, aren't capable of Thinking In Regex. It's inspired by - but has no code at all in common with - a Tkinter tool called Recon (regex console). I've attached the current snapshot, which is very much not the finished product, even though it does work. Planned features include: colored parentheses showing the start/end of groups in re matches (currently parens just wrap the match), overviews of all named and unnamed groups for every match, docs in the Help."* Andrei :Fixes: [c] - SetColumnWidth(-1,...) maybe fixed (Linux) - sys.system_info fix (Linux) - open files on command line was not working - sys.argv error when spe is started from Blender - blenpy send to fix - spe.INFO problem - improved user path retrieval [a] - @ was shortcut for contact, now it is Ctrl+@ :Requirements: - full python_ 2.2 or 2.3 - wxpython_ 2.4.1.2 - optional blender_ 2.28 :Contributors: [c] - Tina Hirsch (feedback) - Andrei (improved user path retrieval) http://come.to/project5 [a] - Andrei (new feature: kiki) http://come.to/project5 Spe 0.1.7 --------- This release ships with a much improved installation/uninstallation procedure and an extended help and popup menu. :New features: [d] - new popup menu - command line option '--debug', if spe fails to start and ends silently. [c] - windows executable installer with extra winInstall and winUninstall.py (linux stays the same) [b] - 'browse to' in edit menu and toolbar button to locate modules automatically based on the cursor position, this works not only for import statements but also for external classes and functions. - help menu enriched with internet links to tutorial, forums, ... - option to create shortcut on desktop during setup (windows only) - registering in windows explorer context menu (windows only) - automatical uninstall script to remove spe from your computer - setup.py is now executable and doesn't require anymore the 'python setup.py install' procedure :Fixes: [g] - autocomplete and calltip were disabled [f] - spe starts now more centered (Linux) - key issues (Guillermo Fernandez) [e] - SPE.pyw was missing - some other small fixes [d] - indentation fix - menu problem with 'www' - startup problem because of fileList - removed unnecessary png handlers - Alt+C and Alt+V are copy and paste shortcuts for shell - double click in shell jumps to error source code - auto-indentation was not functioning after Enter is pressed - ... [c] - python help menu for linux - spe.blend can load spe from Blender in Linux, if Blender is compiled with the right libpng (1.2.x) [b] - improved setup installation - running files path problem fixed - sidebar updates whenever the editor control looses focus - sidebar fix for python 2.2.1 because of rstrip problem - international keyboard fix (Guillermo Fernandez) - separator fix because of zfill error (Guillermo Fernandez) - find & replace issues (Guillermo Fernandez) [a] - drag&drop works now also on the editor window - help windows appear more left-up so that they are more visible - shortcuts reference dialog: now resizable and corrected - indent and dedent added to Edit menu - improved about window showing where spe is installed and other relevant info :Known Issues: - tabs in shell are stolen by editor. :Requirements: - full python_ 2.2 or 2.3 - wxpython_ 2.4.1.2 - optional blender_ 2.28a :Contributors: [f] - Guillermo Fernandez (patches) [c] - Tina Hirsch (Linux feedback) [b] - Guillermo Fernandez (patches) [a] - Andrei (feedback) http://project5.tk ----------------------------------------------------------- Spe 0.1.6 --------- This release normally should have been on the blender_ website. Unfortunately this is not possible. Therefore the latest release will be available from the link *Download latest release* under the calendar of http://spe.pycs.net The focus in the spe development for the recent time has been to make it as stable as possible for Linux. This release should run without (major) problems outside blender_ in Linux (see also *External bugs*). Following information is relative to 0.1.5.c: :New features: - Blender API documentation - linux wrapper script to launch spe from the console - spe updated for python_ 2.3 - spe help manual (Help menu>Manual) - help window resizable - blender_ python_ API documentation added to help menu - homepage: http://spe.pycs.net (thanks to pyds_ and pycs_) - webbrowser used for displaying bigger help files in blenpy and spe - keyboard shortcuts in separate configurable python file :Requirements: - full python_ 2.2 or 2.3 - wxpython_ 2.4.1.2 - optional blender_ 2.28a (updated!) :Known Issues: - Keyboard copy&paste operations in shell are stolen by editor. :External bugs: - the Linux blender_ binaries of blender_.org are unfortunately not compatible with spe. blender_ still uses an old version of the libpng (1.0.x), while spe requires a newer version. Therefore compile blender_ from the sources with libpng 1.2.x to make spe running in blender_. This problem doesn't apply to Windows users, as the windows blender_ binary ships strangely enough already with the new version of libpng. - View end of line marker fails (probably wxpython_ bug) :Fixes: - class browser fixed - usermenu problem - spe can now close without open documents - sidebar updates automatically when it gets focus - enter now doesn't generate extra spaces with auto-complete - blender_ 2.28a no longer crashes by exploring the Text window - no pycrust_ warnings anymore - todo tab: line scrolling - about.htm is included (was missing) - add your own menu help dialog typo - shortcuts dialog typo - busy cursor fix - recent files does not display longer not existing files - separators added between toolbar buttons - ...and some more 3 minor fixes - explore tab: text height (Linux) - font size text dialogs (Linux) - 11 fixes for visibility problems (mainly Linux) - README.txt with better instructions for Linux users. :Contributors: - Tina Hirsch (Linux bug fixing) - Andrei (feedback) http://project5.tk :Wanted: - MacOs X tester for MacOs X screenshot - wxpython_ programmers ----------------------------------------------------------- Spe 0.1.5 --------- :New features: - blender_ browser updated for blender_ 2.28 - Armature - Curve - Effect - IpoCurve - Metaball - Help windows improved with logo and html window. :Fixes: - blenpy has undergone numerous fixes and should run fine :Requirements: - full python_ 2.2 - wxpython_ 2.4.1.2 (updated!) - optional blender_ 2.28 (updated!) :Known issues: - Exploring Texts in blender_ browser crashes due to internal blender_ error. :Contributors: - Tina Hirsch (Linux bug fixing) ----------------------------------------------------------- Spe 0.1.4 --------- :Requirements: - full python_ 2.2 - wxpython_ 2.4.0.7u - optional blender_ 2.26 or 2.27 :Contributors: - Tina Hirsch (Linux bug fixing) - Wolfram Kraus (Linux feedback) ----------------------------------------------------------- .. This document is written in the reStructuredText format. For a quick reference of this specification see: http://docutils.sourceforge.net/docs/rst/quickref.html .. _blender: http://www.blender.org .. _boa: http://boa-constructor.sourceforge.net .. _email: http://www.pycs.net/system/mailto.py?usernum=0000167 .. _pyds: http://pyds.muensterland.org/ .. _pycrust: http://www.wxpython.org .. _pycs: http://www.pycs.net .. _python: http://www.activestate.com/Products/ActivePython/index.html .. _wxpython: http://www.wxpython.org .. _zettai: http://www.zettai.net .. _XRCed: http://xrced.sourceforge.net spe-0.8.4.h/COPYING0000644000175000017500000010451410763615034012623 0ustar stanistani GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . spe-0.8.4.h/setup.py0000644000175000017500000000141110767553033013276 0ustar stanistani#/usr/bin/python from distutils.core import setup setup(name = "spe", description = """Python IDE with UML, PyChecker Source Code Doctor, WinPdb Debugger, wxGlade and XRCed GUI designers and Blender support.""", author = "www.stani.be", author_email = "spe.stani.be@gmail.com", url = "http://pythonide.stani.be", license = "GPL", scripts = ['_spe/spe'], packages = ['_spe', '_spe.dialogs', '_spe.examples', '_spe.plugins', '_spe.shortcuts', '_spe.sidebar', '_spe.skins', '_spe.sm', '_spe.tabs', '_spe.view', '_spe.skins.default', '_spe.sm.wxp'], package_data = {'_spe': ['defaults.cfg', 'doc/donate.html', 'doc/about.htm', 'skins/default/*', 'images/*']} ) spe-0.8.4.h/_spe/0000755000175000017500000000000011004131466012500 5ustar stanistanispe-0.8.4.h/_spe/winpdb_blender.py0000644000175000017500000001003610715664650016046 0ustar stanistani#!BPY #""" #Name: 'Attach Winpdb debugger' #Blender: 243 #Group: 'System' #Tooltip: 'Enables a Python debugger for Blender scripts' #""" # # Copy this script to the .blender/scripts directory. or user scripts directory # __author__ = "Nir Aides" __url__ = ("http://www.digitalpeers.com/pythondebugger") __version__ = "1.3.1" __email__ = ("witold-jaworski@poczta.neostrada.pl") __bpydoc__ = """\ Winpdb, created by Nir Aides, is a platform independent GPL Python debugger,
with support for:
- multiple threads,
- namespace modification,
- embedded debugging
(and because of that it is suitable to use for Blender Python scripts), and is up to 20 times faster than pdb. This small script, written by Witold Jaworski, enables WinPdb to debug Python scripts that are running inside Blender.
It opens the Winpdb, and attaches it to the Blender Python environment. IMPORTANT:
When WinPdb window is opened for the first time in a Blender session, you have to press F5 (Continue) in WinPdb, to let Blender to continue (to "unfreeze" its screen). USAGE:
To break into a script:
- press "Break" button in WinPdb;
- load the script to Blender's Text Editor;
- run the script, pressing Alt-P The WindPdb window will appear. You can debug your script there. You can control, wheter the code has or not have to be debugged, by pressing the WinPdb "break" command button. Remember: Use Winpdb by setting the break mode when it is needed, as long, as you run Blender session. Always close Blender first, unless you have detached the WinPdb before (using "Detach" command from the File menu - it is preffered way, but not required). When you close Winpdb WITHOUT detaching it, Blender.exe will crash during shutdown. (Because in such case Winpdb tries to stop Blender's Python engine). """ import os import sys import subprocess # # helper parameters - usually you do not need to change them: # WAIT_TIMEOUT = 15 #time that this script will wait for attaching a Winpdb PASSWORD = 'blender' #Winpdb requires a password between the client and #the server, so this is the one we will use. # # We will try to load rpdb2 from implicit path. It may work for a standalone # Winpdb installation. This way this script may work with newer version of # Winpdb, than this one that is shipped with SPE: # try:#looking for the default/standalone winpdb installation: import rpdb2 except ImportError: #we will try localize it within SPE directories: import _spe.plugins.spe_winpdb #import this, to use winpdb packed with SPE from rpdb2 import start_embedded_debugger, __file__ as rpdb2_file def debug(what): # # We will form the argument list for Winpdb invocation: # # # Argument 1: Python executable name. # (We cannot utilize here os.executable, because it returns "Blender.exe", # instead "python.exe)" # if os.name in ("nt","mac"): args=["pythonw"] # On Windows and Mac use this else: args = ["python"] #On Linux and other systems - standard python # # Argument 2: full path to Winpdb.py script name # args.append(os.path.join(os.path.dirname(rpdb2_file),"winpdb.py")) # # Argument 3: -a(ttach) specified script # args.append("-a") # # Argument 4: -p(assword): it is only available on nt systems. # if os.name == "nt": args.append("-p" + PASSWORD) # # Argument 5: name of the debugged script # args.append(what) # # Finally: run WinPdb... # if os.name == "nt": pid = subprocess.Popen(args) else: # # On Linux systems: we have to pass the password with stdin! # pid = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE) pid.stdin.write(PASSWORD + "\n") pid.stdin.flush() # # ....and let it to connect, waiting for seconds: # start_embedded_debugger(PASSWORD, timeout = WAIT_TIMEOUT) # # Every script in Blender is represented by the same name: # debug("") spe-0.8.4.h/_spe/smdi.dwg0000644000175000017500000011414610272471120014146 0ustar stanistaniAC1018 h@* ߦ< >ڡH!C7BZ}%]lbE; ۮ2+P`x6I2}IܴO&fk0*;""+Fjs/ghJJWhvPVgRdAk6dAK6dAkRdAkRdAr~B%m6((W?D+bGP8b(^3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f333f3333f3ffffff3f̙3f3f3f333f3333f3ffffff3f̙3f3f (((555CCCPPP]]]kkkxxxڒ+b5bp2A6dA6dA6dAK6dAK6dA!\" Acad:TextAcad:PlotConfigCOUR.TTFC:\WINDOWS\FONTS\+26dA,7dAk7dA6dA6dAN}wq@8v7JDD~7FLF)Hoz;C!x7@@w<=z>><#b-sd>1o<>>= ?R>XT=?===T=??ePB C-.O(-d!#D-D"#$!+3;cAb dLL LHDN~@H\ J@LLML ] `H ;cA #| \3\m\] x|OPObjects   5\X :ObjFreeSpace Ys \X.PLolTemplat X]P`|7!lHandle ,X]ḣ\ \lClass ]egPP{.lAuxHeader ] 8.lo o;cAt!'iF`F`@P"{+ޡ@y G5B,  A r@=֮zQ Gu;EwEw~'z) &&MT#"2~K2]{*T1h94T188(@ $9 TVRGVS"7W7FdRFW6vVBvFwvFPss7'{&SZZE'&V):.M{-<.V ۚ#DŽ)  js{  a0o C s`QY \2TҐsR2ss¬} 7:cab\~-&2&$:^@`߁\\&,)&,)(')&&H& )C(G"4&X(%Q E/&q2&^X#B&4@#H@!HEP%'4@ hCK<"P3 ;DN;#T T@11"% IX5`&l&( " 7G&s")"HB/ D$HIBb4D#h*#)T #@#DI @"U,T(*"-$"66P6{fT15xU62{  '%'& '`8\@&%\8 ֖ׄ7' @F&R|: @1y AU" Het!Zv&XT*3XR1SQQL"ZD*a` J !"!LTd4:270Q @ "LP u2 ,@My@@DQE (0J ts n-̌.L%a" !iEʊp%NBB@E!:4:@ $& VBNfB@J*<67 k`Fj<0e h#P"eD"$l `J꬏QyI$ }"{~q@ (Dq  BQH~d 8 "?  @$$   E&mZ%m $mC"m!.J"F :c {d"|l JVEE#oB s# &Zac* T" C=ZP W@ mXP mQA1"Ut!4A}M DC%P V!t!5JTej (j#Psz*r ?A/T H%t!05dDB$}K0"2`*kt-V<2.22ՐU"B*27Fw2VFRF7V"BFW&f6%2$)&5Pa%&2,,b(H."H(,:6Th6LD@:& T" XWT@Td ̥UUH-RȃR/-( Pd.BtMMUU ( ((fU:jH h((fثTA@H!m̫쌮,lpH#2Pw`fL #}`a"tP%03;8#)i++Ʀ &% -m e5 5R4)lMPe@^z9`F쌭 `TE((|\MRSP\ F$) " "TD)`d?'j"H }]>b\Feрπǀ̀€ЀҀĀ ʠϠ Ơ Ҡ ĠѠ Ƞ̠ Р ǠFod )#l֮RI볦p/M+dA+dA+dAK+dAK+dAW$- L|n%2TAdpt )#l֮RI볦< >$^ P.n*dA*dA*dAk*dAk*dAM.*S N)#l֮RI볦< >$^ G.*dA+dA +dA*dA*dAi(z D~8v7JDD~7v8LF)Hoz;C!x7@@w<<>><#b-sd>x<>>= ?R>XT=?===T=??n M)#l0,(dAl*dA*dA (dA (dA{|)xĸĩ_϶>@@ 52"!,!0(,hH,n-.O*.. ""JJzr ʺ"2b@QdPObjectDBX ClassesCXXR\4D%4TDU!U2"舄@ 1&0 Ɉ+)ꪃE=dE= ` ͕AcDbDictionaryVarCQPSӐTUT T|Ȋ{S+"c +"ƈĦʆ*"*) &"0$4F$F767&GV7BFW634F%f"FV66` P WFFW62tT"FG&W7twwr "6$1ͽDIMASSOC`( 3Qr^;G;V:?# 0Iu \)#l֮RI볦< >$P)i-dA-dAk,dAk-dAk-dA8?&w/L P.\e( X/ n%}.n% l\` )#l֮RI볦< >$P(j,dA.dA.dAk,dAk,dAlŊ7{#8_|hNm3_UЕ@[j &`ZRH(`rjU!2 2 ҀIX  -UUU` Ġ;p!Jql ```aL)q@@C" "*"$#UTd/PxDT UUUUTVⷠs]`8Q E/gbt1E @p H`HML(^U n"{~q@ (Dq  BQH~d 8 h @$$" & F f !!&!J!"! J#J#*!-J-`P $hȈ(&ƦE&(E(&f(Fh&hϩ3)ɂ !iij)j*1"!!J* #"""ȩ?ft&0!VGTnl7 )#l֮RI;cADco tS xtl &bx^d|] x AcDb:Preview \\ c^ 5lFileDepLisB \F\ 1lOa|7RevHistory W$| \3\m\] x|P5Objects  NH 5\X :ObjFreeSpace  \X.PL&lTemplat X]P`|7!lHandle ,X]ḣ\ \lClass ]egPP{.lAuxHeader ] 8.lo o;cA)#l֮RI;cAX\\ QK dL`LLL\L L dAdAKdAdAdAz/v` L@@j lL` ɑܹD Mz DNaA\  O\A IEd [P` B* CPi@#* 42>dx&܀D#Gœ9 ?&!àO4CUL@ $Pt.xpx>q$\$R @(p. !AA@P PeEBX;1LQP8B CJC* R  "zbz/ !(h(*I()z` jbJr*b*"d P?&')," ,hJ.M,,M,n-.O(-d!#D-D"#$!+3JFd !!=iT1 C 2s{k faz~R'JP W@5B"Jj zBB‹"LrPNUj(02/0* AP1W1XQV}LtT G&2 X 1P1 1111111111111111111111112222222222222222222 2222221!Q"VK"b%t!UM1|fm@hTgXM++@uX 6B673J" "!+8Sk@D&et! !ٽx@l @ 9 ʠd!< oo`^0K\t!'iF`F`@P"{+ޡ@y G5B,  A r@=֮zQ Gu;EwEw~'z) &&MT#"2~K2]{*T1h94T188(@ $9 TVRGVS"7W7FdRFW6vVBvFwvFPss7'{&SZZE'&V):.M{-<.V ۚ#DŽ)  js{  a0o C s`QY \2TҐsR2ss¬} 7:cab\~-&2&$:^@`߁\\&,)&,)(')&&H& )C(G"4&X(%Q E/&q2&^X#B&4@#H@!HEP%'4@ hCK<"P3 ;DN;#T T@11"% IX5`&l&( " 7G&s")"HB/ D$HIBb4D#h*#)T #@#DI @"U,T(*"-$"66P6{fT15xU62{  '%'& '`8\@&%\8 ֖ׄ7' @F&R|: @1y AU" Het!Zv&XT*3XR1SQQL"ZD*a` J !"!LTd4:270Q @ "LP u2 ,@My@@DQE (0J ts n-̌.L%a" !iEʊp%NBB@E!:4:@ $& VBNfB@J*<67 k`Fj<0e h#P"eD"$l `J꬏QyI$ }"{~q@ (Dq  BQH~d 8 "?  @$$   E&mZ%m $mC"m!.J"F :c {d"|l JVEE#oB s# &Zac* T" C=ZP W@ mXP mQA1"Ut!4A}M DC%P V!t!5JTej (j#Psz*r ?A/T H%t!05dDB$}K0"2`*kt-V<2.22ՐU"B*27Fw2VFRF7V"BFW&f6%2$)&5Pa%&2,,b(H."H(,:6Th6LD@:& T" XWT@Td ̥UUH-RȃR/-( Pd.BtMMUU ( ((fU:jH h((fثTA@H!m̫쌮,lpH#2Pw`fL #}`a"tP%03;8#)i++Ʀ &% -m e5 5R4)lMPe@^z9`F쌭 `TE((|\MRSP\ F$) " "TD)`d?'j"H }]>b\Geрπǀ̀€ЀҀĀ ʠϠ Ơ Ҡ ĠѠ Ƞ̠ Р ǠFo'ք +Є蕝 @}6v&*&{'5:'_1`&7'_%8%t_Q(j'@BS#3# T mAk FB {-P| / o@Yd $) " "TD)`d?'j"H }]>b\Geрπǀ̀€ЀҀĀ ʠϠ Ơ Ҡ ĠѠ Ƞ̠ Р ǠFo'ք +Є蕝 @}6v&*&{'5:'_1`&7'_%8%t_Q(j'@BS#3# T mAk FB d h@* ߦ< >ڡH!C7BZ}%]lbE; ۮ2+P`x6I2}IܴO&fk0*;""+spe-0.8.4.h/_spe/workspace.reg.txt0000644000175000017500000000256210341055650016023 0ustar stanistaniWindows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.sws] @="Python.SPEWorkspace" Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Python.SPEWorkspace] Python.SPEWorkspace "EditFlags"=dword:00000000 "BrowserFlags"=dword:00000008 @="" [HKEY_CLASSES_ROOT\Python.SPEWorkspace\DefaultIcon] @="D:\\tools\\Python24\\Lib\\site-packages\\_spe\\skins\\default\\favicon.ico,0" [HKEY_CLASSES_ROOT\Python.SPEWorkspace\shell] @="Open" [HKEY_CLASSES_ROOT\Python.SPEWorkspace\shell\Open] [HKEY_CLASSES_ROOT\Python.SPEWorkspace\shell\Open\command] @="\"D:\\tools\\Python24\\pythonw.exe\" \"D:\\tools\\Python24\\lib\\site-packages\\_spe\\SPE.py\" --workspace=\"%1\"" spe-0.8.4.h/_spe/Child.py0000644000175000017500000016674511003655422014122 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info as info INFO=info.copy() INFO['description']=\ """File browser as tab.""" __doc__=INFO['doc']%INFO ####Modules--------------------------------------------------------------------- import codecs, compiler, inspect, os, sys, re, shutil, thread, time, types import wx from wx.lib.evtmgr import eventManager import sm, sm.osx, sm.spy, sm.uml, sm.wxp, sm.wxp.smdi from sm.wxp.stc import PythonSTC from sm.wxp.realtime import TreeCtrl, ListCtrl import view.documentation import _spe.help as help from Menu import STATUS import _spe.plugins.Pycheck as Pycheck from sidebar.Browser import Browser ####Constants------------------------------------------------------------------- DEFAULT = "" MAXINT = sys.maxint #for ListCtrl (should be long) NEWFILE = 'unnamed' SPE_ALLOWED_EXTENSIONS = ['.py','.pyw','.tpy','.txt','.htm','.html','.bak'] STYLE_LIST = wx.LC_REPORT STYLE_NOTEBOOK = wx.NO_BORDER STYLE_NOTES = wx.TE_MULTILINE if not info.DARWIN: STYLE_NOTES |= wx.TE_DONTWRAP STYLE_SPLIT = wx.SP_NOBORDER|wx.FULL_REPAINT_ON_RESIZE STYLE_TREE = wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT if info.LINUX: STYLE_TREE |= wx.TR_NO_LINES RE_DOCSTRING = re.compile(r'(\n|\n__doc__\s*=(\s*|\s*\\\s*\n))("""([^"]*)"""|\'\'\'([^\']*)\'\'\'|"([^"]*)"|\'([^\']*)\')') RE_DOCSTRING_FIRST = re.compile(r'(|__doc__\s*=(\s*|\s*\\\s*\n))("""([^"]*)"""|\'\'\'([^\']*)\'\'\'|"([^"]*)"|\'([^\']*)\')') RE_TODO = re.compile('.*#[ ]*TODO[ ]*:(.+)', re.IGNORECASE) RE_SEPARATOR = re.compile('^.*(#-{3})') RE_SEPARATOR_HIGHLIGHT = re.compile('^.*(#{4})') RE_ENCODING = re.compile('coding[:=]\s*([-\w.]+)', re.IGNORECASE) RE_DEF = re.compile('\s*def\s+(_*[^: ]+)') RE_CLASS = re.compile('\s*class\s+(_*[^: ]+)') RE_TRY = re.compile('try\s*:') RE_EXCEPT = re.compile('except\s*:') RE_FINALLY = re.compile('finally\s*:') UML_PAGE = 1 STATUS_TEXT_LINE_POS = 3 STATUS_TEXT_COL_POS = STATUS_TEXT_LINE_POS+1 BLENDER_REF_SIGNATURE = "Blender_signature.py" #you may customize this file BLENDER_REF_TRACE = "#!BPY" #required first characters of the Blender signature ####Utilities------------------------------------------------------------------- def umlAdd(classes, umlClass): """Add umlClass to classes dictionary""" if umlClass: classes[umlClass.name.split('(')[0]] = umlClass def isUtf8(text): try: if text.startswith('\xef\xbb\xbf'): return True else: return False except: return False ####Child Panel class----------------------------------------------------------- class Source(PythonSTC): def __init__(self,parent): child = parent while child.__class__ != Panel: child = child.GetParent() PythonSTC.__init__(self,parent=parent, namespace= child.parentPanel.shell.interp.locals, path=child._fileName,config=child.parentPanel.config) self.SetHelpText(help.CHILD_SOURCE) child.source = self class Panel(wx.SplitterWindow): ####Constructors------------------------------------------------------------ def __init__(self,parent,name='',fileName='',source='',*args,**kwds): self._fileName = fileName self.name = os.path.basename(fileName) self._source = source #initialize self.argumentsPrevious = [] self.changed = 0 self.checkBusy = False self.column = 1 self.eventChanged = False self.exitPrevious = True self.inspectPrevious = False self.line = 1 self.position = 0 self.sashPosition = [285,310][info.DARWIN] self.minSashPosition = [120,310][info.DARWIN] self.sidebarHidden = False self.saved = '' self.todoMax = 1 self.toggleExploreSelection = False self.warning = '' self.check_for_delete = False #delete when fixed self.updateBug = False #construct wx.SplitterWindow.__init__(self, id=-1, parent=parent,style=STYLE_SPLIT) self.SetMinimumPaneSize(1) if info.DARWIN: self.SetSashSize(6) #Remember if this file contains DOS line endings (\r\n) #Otherwise assume Unix (\n) self.dosLines = (source.find('\r\n') >= 0) self.sashDelta = 1 if os.path.exists(fileName) and fileName != NEWFILE: self.fileTime = os.path.getmtime(fileName) else: self.fileTime = 0 def __finish__(self): frame = self.frame if self._fileName not in self.parentPanel.workspace['openfiles']: #self.name = '~'+self.name frame.setTitle(page=self.name,extra=self._fileName) else: frame.setTitle(page=self.name,extra=self._fileName,colour=wx.WHITE) frame.SetIcon(sm.wxp.bitmap2Icon(self.app.bitmap('icon_py.png'))) self.__sideBar__() self.__source__(self._fileName,self._source) #update self.updateExplore() #events self.source.SetDropTarget(DropOpen(self.parentPanel.openList)) eventManager.Register(self.onSetFocus, wx.EVT_SET_FOCUS, self) #eventManager.Register(self.onSetSourceFocus, wx.EVT_SET_FOCUS, self.source) eventManager.Register(self.onSash,wx.EVT_SPLITTER_SASH_POS_CHANGED,self) #events self.source.SetModEventMask(wx.stc.STC_MOD_DELETETEXT | wx.stc.STC_PERFORMED_USER) eventManager.Register(self.onSourceChange,wx.stc.EVT_STC_CHANGE,self.source) eventManager.Register(self.onSourceFromExplore,wx.EVT_TREE_ITEM_ACTIVATED,self.explore) if info.WIN: #Mac has already always triangles eventManager.Register(self.onToggleExploreTree,wx.EVT_LEFT_DOWN,self.explore) eventManager.Register(self.onSourceFromExplore,wx.EVT_TREE_ITEM_MIDDLE_CLICK,self.explore) eventManager.Register(self.onSourceFromExplore,wx.EVT_TREE_ITEM_RIGHT_CLICK,self.explore) eventManager.Register(self.onSourceFromTodo,wx.EVT_LIST_ITEM_SELECTED,self.todo) eventManager.Register(self.onSourceFromTodo,wx.EVT_LIST_ITEM_RIGHT_CLICK,self.todo) eventManager.Register(self.onSourceFromIndex,wx.EVT_LIST_ITEM_RIGHT_CLICK,self.index) eventManager.Register(self.onSourceFromIndex,wx.EVT_LIST_ITEM_SELECTED,self.index) eventManager.Register(self.updateSidebar,wx.EVT_NOTEBOOK_PAGE_CHANGED,self.notebook) #split self.SplitVertically(self.notebook, self.main, self.sashPosition) def __sideBar__(self): """Create notebook contents.""" notebook = self.notebook = wx.Notebook(id=-1, parent=self, style=STYLE_NOTEBOOK) self.updateSidebarTab=[self.updateExplore,self.updateTodo,self.updateIndex,self.doNothing,self.doNothing] self.notebookLabel = ['Explore','Todo','Index','Notes','Check'] self.notebookIcons = wx.ImageList(16,16) self.exploreIcon = self.notebookIcons.Add(self.parentPanel.icons['explore.png']) self.browserIcon = self.notebookIcons.Add(self.parentPanel.icons['browser.png']) self.todoIcon = self.notebookIcons.Add(self.parentPanel.icons['todo.png']) self.indexIcon = self.notebookIcons.Add(self.parentPanel.icons['index.png']) self.notesIcon = self.notebookIcons.Add(self.parentPanel.icons['notes.png']) self.pycheckerIcon = self.notebookIcons.Add(self.parentPanel.icons['pychecker.png']) ## if info.LINUX: ## #todo: check with linux users if this is really necessary?! ## self.notebook.SetBackgroundColour(wx.WHITE) notebook.AssignImageList(self.notebookIcons) notebook.parentPanel=self.parentPanel #explore explore = self.explore = TreeCtrl(parent=self.notebook,style=STYLE_TREE)#wx.TreeCtrl explore.SetBackgroundColour(wx.WHITE) self.root = self.explore.AddRoot('Right click to locate') #explore.SetPyData(self.root,0) explore.SetImageList(self.parentPanel.iconsList) ## explore.SetItemImage(self.root,self.parentPanel.iconsListIndex['note.png']) ## explore.SetItemImage(self.root,self.parentPanel.iconsListIndex['note.png'],wx.TreeItemIcon_SelectedExpanded) ## explore.SetItemImage(self.root,self.parentPanel.iconsListIndex['note.png'],wx.TreeItemIcon_Expanded) ## explore.SetItemImage(self.root,self.parentPanel.iconsListIndex['note.png'],wx.TreeItemIcon_Selected) explore.SetHelpText(help.CHILD_EXPLORE) notebook.AddPage(page=self.explore, text='Explore',imageId=self.exploreIcon) #todo todo = self.todo = ListCtrl(parent=self.notebook,style=STYLE_LIST) todo.InsertColumn(col=0, format=wx.LIST_FORMAT_LEFT, heading='Line',width=40) todo.InsertColumn(col=1, format=wx.LIST_FORMAT_LEFT, heading='!',width=20) todo.InsertColumn(col=2, format=wx.LIST_FORMAT_LEFT, heading='Task',width=500) todo.SetHelpText(help.CHILD_TODO) self.previousTodoHighlights = [] notebook.AddPage(page=self.todo, text='',imageId=self.todoIcon) #index index = self.index = ListCtrl(parent=self.notebook,style=STYLE_LIST) index.SetImageList(self.parentPanel.iconsList,wx.IMAGE_LIST_SMALL) index.InsertColumn(col=0, format=wx.LIST_FORMAT_RIGHT, heading='Line',width=60) index.InsertColumn(col=1, format=wx.LIST_FORMAT_LEFT, heading='Entry',width=500) index.SetHelpText(help.CHILD_INDEX) notebook.AddPage(page=self.index, text='',imageId=self.indexIcon) if info.WIN: self.indexCharIcon = self.parentPanel.iconsListIndex['index_char_win.png'] else: self.indexCharIcon = self.parentPanel.iconsListIndex['index_char.png'] #notes self.notes = wx.TextCtrl(parent=self.notebook,id=-1, style=STYLE_NOTES) self.notes.SetHelpText(help.CHILD_NOTES) self.notebook.AddPage(page=self.notes, text='',imageId=self.notesIcon) #pyChecker self.pychecker = Pycheck.Panel(self.notebook,page=4) self.notebook.AddPage(page=self.pychecker, text='',imageId=self.pycheckerIcon) #browser if not info.DARWIN or wx.VERSION >= (2,6,2): self.sidebarAddBrowser() def sidebarAddBrowser(self): self.notebookLabel.append('Browse') self.updateSidebarTab.append(self.updateBrowser) browser = self.browser = Browser(self.notebook, -1, os.path.dirname ( self._fileName )) browser.open = self.onOpenFromBrowser self.notebook.AddPage(page=self.browser, text='', imageId=self.browserIcon) def __source__(self,fileName,source): #notebook self.main = wx.Notebook(id=-1, parent=self, #size=wx.Size(5000, 5000), style=wx.NO_BORDER) self.main.childPanel = self self.mainIcons = wx.ImageList(16,16) self.sashIcon = self.mainIcons.Add(self.parentPanel.icons['source.png']) self.umlIcon = self.mainIcons.Add(self.parentPanel.icons['uml.png']) self.documentationIcon = self.mainIcons.Add(self.parentPanel.icons['documentinfo.png']) self.main.AssignImageList(self.mainIcons) #sash self.sash = PythonSTC( parent = self.main, namespace = self.parentPanel.shell.interp.locals, path = os.path.dirname(fileName), config = self.parentPanel.config, menu = self.parentFrame.menuBar.edit) self.sash.SetHelpText(help.CHILD_SOURCE) self.source = self.sash #todo: implement this again with sashview #if wx.Platform == "__WXMAC__": # self.source = self.sash #else: # self.source = self.sash.view if fileName: self.fileName = fileName self.revert(source) else: self.fileName = NEWFILE self.notesText = '' self.frame.setTitle() self.name = os.path.basename(self.fileName) self.source.EmptyUndoBuffer() self.source.Colourise(0, -1) self.main.AddPage(page=self.sash, text='Source',imageId=self.sashIcon) #uml self.uml = sm.uml.Canvas(parent=self.main,style=wx.FULL_REPAINT_ON_RESIZE) self.main.AddPage(page=self.uml, text='Uml',imageId=self.umlIcon) #documentation self.documentation = view.documentation.Panel(parent=self.main,id=-1) self.main.AddPage(page=self.documentation, text='PyDoc',imageId=self.documentationIcon) #events eventManager.Register(self.onKillFocus, wx.EVT_KILL_FOCUS, self.source) eventManager.Register(self.updateMain,wx.EVT_NOTEBOOK_PAGE_CHANGED,self.main) ####Menu-------------------------------------------------------------------- #---file def save(self,fileName=None): """Saves the file.""" if fileName: self.setFileName(fileName) if self.fileName==NEWFILE or not(os.path.exists(os.path.dirname(self.fileName))): self.saveAs() else: #get & fix source self.source.assertEOL() if self.encoding: previous = wx.GetDefaultPyEncoding() wx.SetDefaultPyEncoding(self.encoding) source = self.source.GetText() wx.SetDefaultPyEncoding(previous) else: source = self.source.GetText() if self.parentPanel.getValue('StripTrailingSpaces'): source = '\n'.join([l.rstrip() for l in source.split('\n')]) if not self.dosLines: #convert to Unix lines source = source.replace('\r\n','\n') #get encoding self.getEncoding(source) #convert source to unicode if type(source) is types.UnicodeType: sourceUnicode = source else: sourceUnicode = source.decode(self.encoding) #check if source can be encoded, to avoid overwriting with empty file try: sourceUnicode.encode(self.encoding) except Exception, message: self.parentPanel.messageError(\ """Error: SPE is unable to save with "%s" encoding: %s Please save your file by Copying&Pasting it into another program to make sure you don't loose data and contact %s. Please try then to change the encoding or save it again."""%(self.encoding,message,INFO['author_email'])) return #backup file if self.parentPanel.getValue('Backup') and os.path.exists(self.fileName): backup = self.fileName + (sys.platform == 'win32' and '.bak' or '~') try: os.remove(backup) except: pass try: shutil.copy2(self.fileName,backup) except: self.setStatus('Warning: could not create backup.') #save the file try: #Note that the mode here must be "wb" to allow #line endings to be preserved. file = codecs.open(self.fileName,'wb',self.encoding) file.write(sourceUnicode) file.close() except Exception, message: #This is a serious bug (user looses its file) if it would happen self.parentPanel.messageError(\ """Fatal Error: SPE is unable to save with "%s" encoding: %s SPE probably overwrote your file with an empty file, but made a backup of the previous version as "%s". Please save your file by Copying&Pasting it into another program to make sure you don't loose data and contact %s. Please try then to change the encoding or save it again."""%(self.encoding,message,backup,INFO['author_email'])) return #save succesfull self.notesSave(file=1) self.changed = 0 self.saved = source self.parentPanel.recent.add([self.fileName]) if self.parentPanel.getValue('CheckFileOnSave'): if not self.check(): self.parentPanel.shell.prompt() else: self.SetStatusText("File '%s' saved"%self.fileName,1) if fileName: self.frame.setTitle(os.path.basename(fileName),fileName,colour=wx.WHITE) else: self.frame.setTitle() if os.path.exists(self.fileName): self.fileTime = os.path.getmtime(self.fileName) else: self.fileTime = 0 if self.parentPanel.get('UpdateSidebar')!='realtime': self.updateSidebar() def saveAs(self): defaultDir = os.path.dirname(self.fileName) dlg = wx.FileDialog(self, "Save As - www.stani.be", defaultDir = defaultDir, wildcard = info.WILDCARD, style = wx.SAVE|wx.OVERWRITE_PROMPT|wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPaths()[0] self.save(path) if hasattr(self,'browser'): self.browser.SetDefaultPath(os.path.dirname(path)) self.browser.ReCreateTree() dlg.Destroy() def saveCopy(self): """firstly save the current file, then make a copy of it""" self.save(self.fileName) defaultDir = os.path.dirname(self.fileName) dlg = wx.FileDialog(self, "Save a Copy - www.stani.be", defaultDir = defaultDir, wildcard = info.WILDCARD, style = wx.SAVE|wx.OVERWRITE_PROMPT|wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPaths()[0] try: shutil.copyfile(self.fileName, path) except IOError: self.parentPanel.messageError("Sorry, I was unable to copy %s to %s" % ( self.fileName, path)) dlg.Destroy() def saveUmlAs(self): self.main.SetSelection(UML_PAGE) self.uml.OnDoSave() def printUml(self): self.main.SetSelection(UML_PAGE) self.uml.OnDoPrint() def printUmlPreview(self): self.main.SetSelection(UML_PAGE) self.uml.OnPrintPreview() def printUmlSetup(self): self.main.SetSelection(UML_PAGE) self.uml.OnPrintSetup() #---edit def comment(self): """Comment section""" doc = self.source sel = doc.GetSelection() start = doc.LineFromPosition(sel[0]) end = doc.LineFromPosition(sel[1]) if end > start and doc.GetColumn(sel[1]) == 0: end = end - 1 doc.BeginUndoAction() for lineNumber in range(start, end + 1): firstChar = doc.PositionFromLine(lineNumber) doc.InsertText(firstChar, '##') doc.SetCurrentPos(doc.PositionFromLine(start)) doc.SetAnchor(doc.GetLineEndPosition(end)) doc.EndUndoAction() def uncomment(self): """Uncomment section""" doc = self.source sel = doc.GetSelection() start = doc.LineFromPosition(sel[0]) end = doc.LineFromPosition(sel[1]) if end > start and doc.GetColumn(sel[1]) == 0: end = end - 1 doc.BeginUndoAction() for lineNumber in range(start, end + 1): firstChar = doc.PositionFromLine(lineNumber) if chr(doc.GetCharAt(firstChar)) == '#': if chr(doc.GetCharAt(firstChar + 1)) == '#': # line starts with ## doc.SetCurrentPos(firstChar + 2) else: # line starts with # doc.SetCurrentPos(firstChar + 1) doc.DelLineLeft() doc.SetSelection(sel[0],doc.PositionFromLine(end+1)) doc.SetCurrentPos(doc.PositionFromLine(start)) doc.EndUndoAction() def insert_separator(self): from dialogs import separatorDialog separatorDialog.create(self).ShowModal() def insert_signature(self): '''Insert asignature into the current document''' signature = self.parentPanel.get('Signature') if not os.path.exists(signature): # No or invalid signature in preferences dlg = wx.FileDialog(self, message="SPE - Choose a signature file", #defaultDir = os.getcwd(), #defaultFile = "", wildcard = "Python source (*.py)|*.py|Text (*.txt)|*.txt|All files (*.*)|*.*", style = wx.OPEN | wx.FILE_MUST_EXIST ) answer = dlg.ShowModal() signature = dlg.GetPath() dlg.Destroy() if answer == wx.ID_CANCEL: return # Have a signature file try: self.source.ReplaceSelection(open(signature).read()+'\n') except: self.setStatus('SPE could not open signature "%s"!'% signature) return def go_to_line(self,scroll=1): """Go to line dialog & action""" line=self.parentPanel.messageEntry('Enter line number:') if line: self.scrollTo(int(line)-1) #---View def refresh(self): if self.parentPanel.redraw:self.parentPanel.redraw() if self.parentPanel.get('UpdateSidebar')!='realtime': self.updateSidebar() def onSash(self,event): if self.sidebarHidden: self.showSidebar() else: pos = event.GetSashPosition() if pos < self.minSashPosition: self.hideSidebar(self.minSashPosition) else: event.Skip() def toggle_sidebar(self,event): pos = self.GetSashPosition() show = pos <= 5 if show: self.showSidebar() else: self.hideSidebar(pos) if self.frame.menuBar: self.frame.menuBar.check_sidebar(show) else: self.parentFrame.menuBar.check_sidebar(show) def hideSidebar(self,pos): self.sidebarHidden = True self.sashPosition = pos self.notebook.Hide() self.SetSashPosition(1) def showSidebar(self): self.sidebarHidden = False self.notebook.Show() self.SetSashPosition(self.sashPosition) #---Tools def open_terminal_emulator(self): """Open terminal emulator""" path,fileName=os.path.split(self.fileName) params = {'file':fileName,'path':path} terminal=self.parentPanel.get('Terminal') if terminal==DEFAULT: if info.WIN: os.system('start "Spe console - Press Ctrl+Break to stop" /D"%(path)s"'%params) elif info.DARWIN: sm.osx.startAppleScript([['cd',params['path']]], activateFlag=True) elif os.path.exists('/usr/bin/urxvt'): os.system('cd "%(path)s"; /usr/bin/urxvt &'%params) elif os.path.isfile('/usr/bin/gnome-terminal'): os.system('/usr/bin/gnome-terminal --title SPE --working-directory="%(path)s" &'%params) elif os.path.isfile('/usr/bin/konsole'): os.system('/usr/bin/konsole --caption SPE --workdir "%(path)s" &'%params) else: os.system('cd %(path)s;xterm &'%params) else: os.system(terminal%params) def run(self): if not self.confirmSave(): return if self.isNew(): return from _spe.dialogs.runTerminalDialog import RunTerminalDialog runTerminalDialog = RunTerminalDialog(self.fileName, self.argumentsPrevious, self.inspectPrevious, self.exitPrevious, parent=self.app.parentFrame, id=-1) answer = runTerminalDialog.ShowModal() arguments = runTerminalDialog.arguments.GetValue() inspct = runTerminalDialog.inspect.GetValue() exit = runTerminalDialog.exit.GetValue() runTerminalDialog.Destroy() if answer == wx.ID_OK: self.argumentsPrevious.append(arguments) self.inspectPrevious = inspct self.exitPrevious = exit self.run_with_arguments(arguments,inspct,exit,confirm=False) def run_with_arguments(self,arguments='', inspct=False, exit=False, confirm=True): """Run in terminal emulator""" if confirm and not self.confirmSave(): return if self.isNew(): return # todo: input stuff from preferences dialog box! path, fileName = os.path.split(self.fileName) params = { 'file': fileName, 'path': path, 'arguments': arguments, 'python': info.PYTHON_EXEC+['',' -i'][inspct]} if exit: terminal=self.parentPanel.get('TerminalRunExit') else: terminal = self.parentPanel.get('TerminalRun') if terminal == DEFAULT: if info.WIN: if info.WIN98: params['start'] = 'start command' else: params['start'] = 'start "SPE - %(file)s - Press Ctrl+Break to stop" /D"%(path)s" cmd'%params if exit: os.system('%(start)s /c %(python)s "%(file)s" %(arguments)s'%params) else: os.system('%(start)s /k %(python)s "%(file)s" %(arguments)s'%params) elif info.DARWIN: commandList = [ ['cd', params['path']], [params['python'], params['file'], [params['arguments']]] ] if exit: commandList.append(['exit']) sm.osx.startAppleScript(commandList, activateFlag=True) elif os.path.isfile('/usr/bin/gnome-terminal'): if exit: os.system("""/usr/bin/gnome-terminal --title "SPE - %(file)s - %(path)s - Press Ctrl+C to stop" --working-directory="%(path)s" -e '%(python)s "%(file)s" %(arguments)s' &"""%params) else: os.system("""/usr/bin/gnome-terminal --title "SPE - %(file)s - %(path)s - Press Ctrl+C to stop" --working-directory="%(path)s" -x bash -c "%(python)s \\"%(file)s\\" %(arguments)s; cat" """%params) elif os.path.isfile('/usr/bin/konsole'): if exit: os.system("""/usr/bin/konsole --caption SPE --workdir "%(path)s" -e %(python)s "%(file)s" %(arguments)s &"""%params) else: os.system("""/usr/bin/konsole --caption SPE --noclose --workdir "%(path)s" -e %(python)s "%(file)s" %(arguments)s &"""%params) else: os.system('%(python)s "%(file)s" %(arguments)s'%params) else: os.system(terminal%params) def check_source_with_pychecker(self): """Check source with pychecker""" self.pychecker.check() #---Blender def load_in_blender(self): """Load into blender""" if self.parentPanel.checkBlender(): child = self.app.childActive #do we need to save this file, before? if self.changed or self.isNew(): child.confirmSave('Only saved contents will be loaded in Blender.') if self.changed or self.isNew(): #if it is saved here - it means that the user has cancelled self.setStatus( "File was not saved: operation cancelled.") else: import Blender #first: let's remove previous copies of this file from Blender's Texts for t in filter(lambda x: x.filename == child.fileName, Blender.Text.Get()) : Blender.Text.unlink(t) #second: let's load the just saved file. Blender.Text.Load(child.fileName) #BEWARE: this text will not be the selected text in Blender - #you still have to select it as the actual. self.setStatus(("File successfully loaded as a Blender's Text Editor item, named '%s'" % os.path.basename(child.fileName))) def reference_in_blender(self): """Reference in blender""" if self.parentPanel.checkBlender(): import Blender child = self.app.childActive msg = "" #message text, that will be displayed on the status bar #Check: maybe it is a completly new file?: if child.isNew(): child.saveAs() #It is still a new file, if the user has declined to reference it if child.isNew(): return #nothing to do - user has changed his mind #First: add the Blender signature at the beginning of the file doc = child.source #let's move to begining of the file and check, if the Blender signature already exists: doc.ScrollToLine(0) doc.SetSelection(0,len(BLENDER_REF_TRACE)) if doc.GetSelectedText() == BLENDER_REF_TRACE: msg = "File alread contains reference to Blender menus" else: template = os.path.join(child.parentPanel.path,BLENDER_REF_SIGNATURE) if not os.path.exists(template): child.parentPanel.messageError("Template file:\n%s\nnot found.\n\nCannot reference this script to Blender menu." % template) return else: #adding the content of Blender signature file to the source import getpass values = { 'Command':os.path.basename(child.fileName), \ 'Blender version':Blender.Get('version'), \ 'User':getpass.getuser() } text = open(template).read() text = text % values #apply values into signature doc.SetSelection(0,0) doc.ReplaceSelection(text + "\n") doc.ScrollToLine(0) #It looks better msg = "Blender's signature added." # Second: if the script is not located in Blender directory - move it there actdir = os.path.dirname(child.fileName) if actdir != Blender.Get('uscriptsdir') and actdir != Blender.Get('scriptsdir'): if Blender.Get('uscriptsdir')==None: varname = 'scriptsdir' else: varname = 'uscriptsdir' child.save(os.path.join(Blender.Get(varname),os.path.basename(child.fileName))) msg = ("File saved as '%s'" % child.fileName) + ", " + msg else: child.save() #we have save it, to be referenced in Blender menus. #Third: let the script appear in the Blender menu Blender.UpdateMenus() #Four: feedback for the user self.setStatus(msg) ####Events------------------------------------------------------------------ #---Smdi events def onActivate(self,event=None): self.check_for_delete = True if self.frame.menuBar: self.frame.menuBar.check_sidebar() else: self.parentFrame.menuBar.check_sidebar() self.updateStatus() if hasattr(self,'source'): self.source.SetFocus() def onDeactivate(self,event=None): if hasattr(self,'source'): self.source.AutoCompCancel() self.source.CallTipCancel() def onClose(self, event=None): if self.confirmSave(): eventManager.DeregisterWindow(self) self.frame.dead = 1 if len(self.app.children)==1: self.parentFrame.menuBar.enable(0) return True else: return False return True def onSize(self, event=None): self.source.SetFocus() #---Panel events def onSetFocus(self,event): event.Skip() self.checkTime() try: self.source.SetFocus() except: pass def onSetSourceFocus(self,event): if self.app.DEBUG: print 'Event: Child: %s: %s.onSetFocus(dead=%s)'%(self.fileName, self.__class__,self.frame.dead) event.Skip() if self.app.children and self.app.childActive != self and sm.wxp.smdi.MdiSplitChildFrame == self.frame.__class__: self.frame.onFrameActivate() #---Source events def onSourceChange(self,event): self.eventChanged = True def onSourcePositionChange(self,event=None): """Updates statusbar with current position.""" def idle(self,event=None,end=False): #if dead, return immediately if self.frame.dead or self.parentFrame.dead or not hasattr(self,'source'): return #update line & column in status pos = self.source.GetCurrentPos() if pos!= self.position: self.updateStatus(pos) ## if self.toggleExploreSelection: ## self.toggleExploreSelection = False ## self.onToggleExploreSelection() #only if source is changed... if self.eventChanged: self.eventChanged = False #title if self.changed == 0: self.changed = 1 self.frame.setTitle() elif self.changed < 0: self.changed+=1 #sidebar if self.parentPanel.get('UpdateSidebar')=='realtime': self.updateSidebar() if not end and self.parentPanel.get('CheckSourceRealtime')=='compiler': ## self._idleCheck(self.source.GetText()) thread.start_new(self.idleCheck,(self.source.GetText(), self.parentPanel.lock)) def idleCheck(self,source,lock): lock.acquire() try: self._idleCheck(source) except Exception, message: pass lock.release() def _idleCheck(self,source): length = len(source) source = source.replace('\r\n','\n') + '\n' try: tree = compiler.parse(source) warning = '' e = None except Exception, e: if hasattr(e,'text'): if type(e.text) in types.StringTypes: text= e.text.strip() else: text= '' warning = '%s: %s at line %s, col %s.'%(self.name,e.msg,e.lineno,e.offset) else: warning = repr(e) if warning != self.warning: #todo: how to implement indicators?!! if warning: wx.CallAfter(self.setStatus,warning) wx.CallAfter(self.statusBar.throbber.playFile,'warning.gif') if e and hasattr(e,'lineno') and not (e.lineno is None): wx.CallAfter(self.source.clearError,length) wx.CallAfter(self.source.markError,e.lineno,e.offset) else: wx.CallAfter(self.setStatus,STATUS) wx.CallAfter(self.statusBar.throbber.stop) if self.e and hasattr(self.e,'lineno'): wx.CallAfter(self.source.clearError,length) self.warning = warning self.e = e def onKillFocus(self,event=None): if self.app.DEBUG: print 'Event: Child: %s: %s.onKillFocus(dead=%s)'%(self.fileName, self.__class__,self.frame.dead) try: if not (self.frame.dead or self.parentFrame.dead): if hasattr(self.parentFrame,'tabs'): tabs = self.parentFrame.tabs index = self.frame.getIndex() - tabs.getZero() - 1 source = self.source.GetText() docstring = '%s\n\n%d lines | %d chars | %d classes | %d defs'%(os.path.dirname(self.fileName),source.count('\n'),len(source),source.count('class '),source.count('def ')) if source and source[0] in ["'",'"']: regex = RE_DOCSTRING_FIRST else: regex = RE_DOCSTRING match = regex.search(source) if match: match = match.group(3).strip('"\'').strip() if match: docstring = '%s\n\n%s'%(docstring,match) tabs.SetPageToolTip(index,docstring.replace('\r\n','\n'),1000,winsize=300) if self.parentPanel.get('UpdateSidebar')=='when clicked': self.source.SetSTCFocus(0) self.updateSidebar() event.Skip() except: pass #---Sidebar update methods & jump events def updateSidebar(self,event=None): if self.frame.dead: return if event: tab = event.GetSelection() old = event.GetOldSelection() if type(old) == int: try: self.notebook.SetPageText(old,'') except: pass if type(tab) == int: try: self.notebook.SetPageText(tab,self.notebookLabel[tab]) except: pass event.Skip() else: tab = self.notebook.GetSelection() self.updateSidebarTab[tab]() def updateBrowser(self): self.browser.update() def updateStatus(self,pos=None): if hasattr(self,'source'): source = self.source if not pos: pos = source.GetCurrentPos() self.position = pos line = source.LineFromPosition(pos) column = source.GetColumn(pos) if line != self.line: self.line = line self.SetStatusText('Line %05d'%(line+1),STATUS_TEXT_LINE_POS) if column != self.column: self.column=column self.SetStatusText('Column %03d'%column,STATUS_TEXT_COL_POS) else: self.SetStatusText('',STATUS_TEXT_LINE_POS) self.SetStatusText('',STATUS_TEXT_COL_POS) def updateTodo(self): """Update todo tab in sidebar.""" #get text try: text=self.source.GetText().split('\n') except: return #initialize tryMode = 0 #try, except are false indentations hierarchyIndex = 0 todoData = [] todoIndex = 0 self.todoMax = 1 self.todoHighlights = [] self.todoList = [] hierarchy = [(-1,self.root)] self.todo.DeleteAllItems() #loop through code wxPython.lib.evtmgr for line in range(len(text)): l = text[line].strip() todo_hit = RE_TODO.match(l) first = l.split(' ')[0] if first=='try:': tryMode += 1 elif first[:6]=='except': tryMode = max(0,tryMode-1) elif first[:7]=='finally': tryMode = max(0,tryMode-1) elif todo_hit: #todo entry task = todo_hit.group(1) urgency = task.count('!') self.todoList.append((line,urgency,task)) item = self.todo.InsertStringItem(todoIndex, str(line+1)) self.todo.SetStringItem(item, 1, str(urgency)) self.todo.SetStringItem(item, 2, task) self.todo.SetItemData(item,line+1) #highlights newMax = max(self.todoMax,urgency) if newMax>self.todoMax: self.todoMax = newMax self.todoHighlights = [item] elif urgency==self.todoMax: self.todoHighlights.append(item) todoIndex+=1 #highlight most urgent todos for i in self.todoHighlights: if i not in self.previousTodoHighlights: self.todo.SetItemBackgroundColour(i,wx.Colour(255,255,0)) ## item=self.todo.GetItem(i) ## item.SetBackgroundColour(wx.Colour(255,255,0)) ## self.todo.SetItem(item) for i in self.previousTodoHighlights: if i not in self.todoHighlights: self.todo.SetItemBackgroundColour(i,wx.Colour(255,255,255)) ## item=self.todo.GetItem(i) ## item.SetBackgroundColour(wx.Colour(255,255,255)) ## self.todo.SetItem(item) self.previousTodoHighlights = self.todoHighlights self.todo.Update() def updateIndex(self): """Update index tab in sidebar.""" #get code try: text = self.source.GetText().split('\n') except: return #initialize tryMode = 0 hierarchyIndex = 0 self.indexData = [] #loop through code for line in range(len(text)): l = text[line].split('#')[0] def_match = RE_DEF.match(l) if def_match: colour = wx.Colour(0,0,255) icon = 'def.png' l = def_match.group(1) else: class_match = RE_CLASS.match(l) if class_match: colour = wx.Colour(255,0,0) icon = 'class.png' l = class_match.group(1) else: continue stripped = l.replace('_','').strip().upper() #used for sorting if stripped: self.indexData.append((stripped,l,line+1,colour, self.parentPanel.iconsListIndex[icon],self.fileName)) #make index tab self.indexData.sort() firstLetter = '' self.index.DeleteAllItems() for element in self.indexData: stripped, entry, line, colour, icon, fileName = element if stripped[0]!=firstLetter: firstLetter = stripped[0] item = self.index.InsertImageStringItem(MAXINT, firstLetter, self.indexCharIcon) self.index.SetStringItem(item,1,' ') self.index.SetItemBackgroundColour(item,(230,230,230)) item = self.index.InsertImageStringItem(MAXINT, str(line), icon) self.index.SetStringItem(item, 1, entry) self.index.SetItemData(item,line-1) self.index.SetItemTextColour(item,colour) self.index.Update() #if self.parentPanel.indexVisible... def updateExplore(self,uml=0): """Updates explore in sidebar.""" classes = {} if not (self or self.explore): return classes #get text try: text=self.source.GetText().split('\n') except: return classes #initialize if uml: self.umlClass = None previous = 0 n = len(text) tryMode = 0 hierarchyIndex = 0 hierarchy = [(-1,self.root)] separators = [] self.encoding = None try: self.explore.CollapseAndReset(self.root) except: return classes for line in range(len(text)): l = text[line].strip() first = l.split(' ')[0] sepa_hit = RE_SEPARATOR.match(l) sepb_hit = RE_SEPARATOR_HIGHLIGHT.match(l) encode_hit = False if line < 3: if line == 0 and isUtf8(l): self.encoding = "utf8" encode_hit = True else: enc = RE_ENCODING.search(l) if enc: self.encoding = str(enc.group(1)) encode_hit = True if first in ['class','def','import'] or encode_hit or (first == 'from' and 'import' in l): if 1 or l.find('(')!=-1 or l.find(':') !=-1 or first in ['from','import'] or encode_hit: #indentation-------------------------------------------- indentation = max(0,len(text[line])- len(text[line].lstrip())-tryMode*4) #situate in hierachy------------------------------------ hierarchyIndex = 0 while hierarchyIndex+1self.fileTime: #file is modified self.fileTime=fileTime message=baseName+' is modified externally.\nDo you want to reload it%s?' if (self.changed>0 and self.parentPanel.messageConfirm(message%' and lose current changes')) or\ (not self.changed>0 and (self.parentPanel.getValue('AutoReloadChangedFile') or self.parentPanel.messageConfirm(message%''))): pos=self.source.GetCurrentPos() self.revert() self.source.GotoPos(pos) return 1 except: return 0 elif self.check_for_delete and self.fileName != NEWFILE: #file does not exist anymore if self.parentPanel.messageConfirm('Warning: the file "%s" has been deleted!\nDo you want to save it now?'%baseName): self.save() else: self.check_for_delete = False self.eventChanged = False def confirmSave(self, message=''): self.notesSave(file=1) if self.changed>0 or (self.fileName == NEWFILE and self.source.GetText()): self.Raise() message+='\nSave changes to "%s"?'%self.fileName answer=self.parentPanel.messageCancel(message) if answer==wx.ID_CANCEL: return 0 elif self.parentPanel.messageIsOk(answer): self.save() return 1 else:return 1 else:return 1 def refreshTitle(self): if self.app.DEBUG: print 'Method: Child: %s.refreshTitle("%s")'%(self.__class__,self.fileName) self.frame.setTitle() def revert(self,source=None): if not source: try: sourceFile = open(self.fileName,'rb') source = sourceFile.read() sourceFile.close() if self.parentPanel.getValue('ConvertTabsToSpaces'): source=source.replace('\t',' '.ljust(self.parentPanel.getValue('TabWidth'))) except IOError: source = '' self.getEncoding(source) try: if source and self.encoding: #read the source sourceFile = codecs.open(self.fileName,'rb',self.encoding) source = sourceFile.read() sourceFile.close() #set it with the right encoding previous = wx.GetDefaultPyEncoding() wx.SetDefaultPyEncoding(self.encoding) self.source.SetText(source) wx.SetDefaultPyEncoding(previous) else: self.source.SetText(source) except Exception, message: self.SetStatusText("Unicode Error for '%s' (%s)"%(self.fileName, message),1) self.source.assertEOL() if os.path.exists(self.fileName) and self.fileName != NEWFILE: self.fileTime = os.path.getmtime(self.fileName) else: self.fileTime = 0 try: self.notesText=open(self.notesFile()).read() except: self.notesText='' self.notes.SetValue(self.notesText) self.frame.setTitle() self.changed=0 self.eventChanged = False def setFileName(self,fileName): self.fileName = fileName self.name = os.path.basename(self.fileName) ## if fileName not in self.parentPanel.workspace['openfiles']: ## self.name = '~'+self.name index = self.frame.getIndex() mdi = self.app.mdi if not mdi:index+= 1 if hasattr(self.frame,'tabs'): self.frame.tabs.SetPageText(index,self.name) self.frame.setTitle() if not mdi: for child in self.app.children: child.frame.tabs.SetPageText(index,self.name) def setStatus(self,text,i=1): self.SetStatusText(text,i) def sidebarVisible(self): return self.GetSashPosition() > 5 def scrollTo(self,line=0,column=0,select='pos',scroll=0): source = self.source source.EnsureVisible(line) #line = source.VisibleFromDocLine(line) linePos = source.PositionFromLine(line) pos = linePos+column if select=='line': source.SetSelection(linePos, source.GetLineEndPosition(line)) else: #select=='pos': source.GotoPos(pos) source.ScrollToLine(line) source.ScrollToColumn(0) source.SetFocus() def notesFile(self): return os.path.splitext(self.fileName)[0]+'_notes.txt' def notesSave(self,file=0): if not hasattr(self,'notes'): return self.notesText=self.notes.GetValue() if file: try: if not self.notesText: os.remove(self.notesFile()) else: f=open(self.notesFile(),'w') f.write(self.notesText) f.close() except (OSError, IOError): pass # tolerate IO failure otherwise app hangs def selectLine(self,line): source=self.source def getEncoding(self,source): if isUtf8(source): self.encoding = "utf8" return first2lines = "".join(source.split("\n")[:2]) encode_hit = RE_ENCODING.search(first2lines) if encode_hit: #find in source self.encoding = encode_hit.group(1) else: #get default values if self.parentPanel.defaultEncoding == '': #wx.GetDefaultPyEncoding() when SPE was launched self.encoding = INFO['encoding'] else: #as in preferences self.encoding = self.parentPanel.defaultEncoding if self.encoding == 'ascii': #avoid obvious trap try: str(source) except: self.setStatus('Warning: SPE uses "utf8" instead of "ascii" codec.') self.encoding = 'utf8' self.encoding = str(self.encoding) class DropOpen(wx.FileDropTarget): """Opens a file when dropped on parent frame.""" def __init__(self,openList): wx.FileDropTarget.__init__(self) self.openList = openList def OnDropFiles(self,x,y,fileNames): fileNames = [script for script in fileNames if os.path.splitext(script)[-1].lower() in SPE_ALLOWED_EXTENSIONS] if fileNames: self.openList(fileNames) return 1 else:return 0 spe-0.8.4.h/_spe/wxgMenu.py0000644000175000017500000011337010772170467014530 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4cvs on Tue Jul 19 19:57:59 2005 import sys, wx def _(x): return x MENUS =[ OPEN_WORKSPACE, SAVE_WORKSPACE, SAVE_WORKSPACE_AS, SAVE_COPY, SAVE_UML_AS, PRINT_UML_SETUP, PRINT_UML_PREVIEW, PRINT_UML, CUT, COPY, PASTE, REMEMBER_OPEN_FILES, GO_TO_LINE, BROWSE_SOURCE, AUTO_COMPLETE, SHOW_DOCSTRING, INDENT, DEDENT, COMMENT, UNCOMMENT, INSERT_SEPARATOR, INSERT_SIGNATURE, EXECUTE, PREFERENCES, WHITESPACE, LINENUMBERS, INDENTATION_GUIDES, RIGHT_EDGE_INDICATOR, AS_NOTEBOOK, AS_COLUMNS, AS_ROWS, END_OF_LINE_MARKER, SIDEBAR, SHELL, TOOLBAR, CLEAR_OUTPUT, REFRESH, RUN, RUN_WITHOUT_ARGUMENTS, RUN_TERMINAL, RUN_TERMINAL_WITHOUT_ARGUMENTS, RUN_TERMINAL_WITHOUT_ARGUMENTS_EXIT, IMPORT, RUN_DEBUG, DEBUG, BROWSE_OBJECT_WITH_PYFILLING, TEST_REGULAR_EXPRESSION_WITH_KIKI, DESIGN_A_GUI_WITH_WXGLADE, DESIGN_A_GUI_WITH_XRC, CHECK_SOURCE_WITH_PYCHECKER, OPEN_TERMINAL_EMULATOR, BROWSE_FOLDER, RUN_IN_TERMINAL_EMULATOR, RUN_IN_TERMINAL_EMULATOR__EXIT, LOAD_IN_BLENDER, REFERENCE_IN_BLENDER, REDRAW_BLENDER_WINDOW, BLENDER_PYTHON_MANUAL, BLENDER_PYTHON_TUTORIAL, BLENDER_HOMEPAGE, DOWNLOAD_BLENDER, FORUM_BLENDER_PYTHON, FORUM_ELYSIUN_PYTHON, ADD_SPE_TO_BLENDER, SPE_HOMEPAGE, FORUM_SPE, AUTHORS_HOMEPAGE, CONTACT_AUTHOR, PYTHON_HOMEPAGE, PYTHON_ANNOUNCEMENTS, PYTHON_COOKBOOK, PYTHON_DAILY, PYTHON_FOR_ARTISTS, PYTHON_PACKAGE_INDEX, NEXT,PREVIOUS, MANUAL, KEYBOARD_SHORTCUTS, PYTHON_LIBRARY, PYTHON_REFERENCE, PYTHON_DOCUMENTATION_SERVER, WXGLADE_MANUAL, WXGLADE_TUTORIAL, WXWINDOWS_DOCUMENTATION, DONATE, ABOUT ] =\ [wx.NewId() for x in range(86)] CHILD_MENUS=[ wx.ID_SAVE, wx.ID_SAVEAS, SAVE_COPY, wx.ID_CLOSE, REMEMBER_OPEN_FILES, SAVE_UML_AS, PRINT_UML_SETUP, PRINT_UML_PREVIEW, PRINT_UML, wx.ID_UNDO, wx.ID_REDO, CUT, COPY, PASTE, wx.ID_REPLACE, wx.ID_FIND, GO_TO_LINE, BROWSE_SOURCE, AUTO_COMPLETE, INDENT, DEDENT, COMMENT, UNCOMMENT, INSERT_SEPARATOR, INSERT_SIGNATURE, EXECUTE, WHITESPACE, INDENTATION_GUIDES, RIGHT_EDGE_INDICATOR, AS_NOTEBOOK, AS_COLUMNS, AS_ROWS, END_OF_LINE_MARKER, SIDEBAR, RUN, RUN_WITHOUT_ARGUMENTS, IMPORT, RUN_DEBUG, DEBUG, CHECK_SOURCE_WITH_PYCHECKER, NEXT,PREVIOUS]#LINENUMBERS, BLENDER_MENUS = [LOAD_IN_BLENDER, REFERENCE_IN_BLENDER,] class Palette(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: Palette.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.logo = wx.StaticBitmap(self, -1, wx.Bitmap("skins/default/blenpy.png", wx.BITMAP_TYPE_ANY)) self.previous = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/tab_left.png", wx.BITMAP_TYPE_ANY)) self.next = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/tab_right.png", wx.BITMAP_TYPE_ANY)) self.find = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/viewmag.png", wx.BITMAP_TYPE_ANY)) self.goto = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/goto.png", wx.BITMAP_TYPE_ANY)) self.browse_source = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/thumbnail.png", wx.BITMAP_TYPE_ANY)) self.check = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/pychecker.png", wx.BITMAP_TYPE_ANY)) self.dedent = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/dedent.png", wx.BITMAP_TYPE_ANY)) self.indent = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/indent.png", wx.BITMAP_TYPE_ANY)) self.comment = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/comment.png", wx.BITMAP_TYPE_ANY)) self.uncomment = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/uncomment.png", wx.BITMAP_TYPE_ANY)) self.run = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/run.png", wx.BITMAP_TYPE_ANY)) self.imprt = wx.BitmapButton(self, -1, wx.Bitmap("skins\\default\\import.png", wx.BITMAP_TYPE_ANY)) self.sidebar = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/view_left_right.png", wx.BITMAP_TYPE_ANY)) self.run_verbose = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/debug.png", wx.BITMAP_TYPE_ANY)) self.shell = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/view_top_bottom.png", wx.BITMAP_TYPE_ANY)) self.donate = wx.BitmapButton(self, -1, wx.Bitmap("skins/default/donate.png", wx.BITMAP_TYPE_ANY)) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_BUTTON, self.evt_previous, self.previous) self.Bind(wx.EVT_BUTTON, self.evt_next, self.next) self.Bind(wx.EVT_BUTTON, self.evt_find, self.find) self.Bind(wx.EVT_BUTTON, self.evt_goto, self.goto) self.Bind(wx.EVT_BUTTON, self.evt_browse_source, self.browse_source) self.Bind(wx.EVT_BUTTON, self.evt_check, self.check) self.Bind(wx.EVT_BUTTON, self.evt_dedent, self.dedent) self.Bind(wx.EVT_BUTTON, self.evt_indent, self.indent) self.Bind(wx.EVT_BUTTON, self.evt_comment, self.comment) self.Bind(wx.EVT_BUTTON, self.evt_uncomment, self.uncomment) self.Bind(wx.EVT_BUTTON, self.evt_run, self.run) self.Bind(wx.EVT_BUTTON, self.evt_import, self.imprt) self.Bind(wx.EVT_BUTTON, self.evt_sidebar, self.sidebar) self.Bind(wx.EVT_BUTTON, self.evt_run_verbose, self.run_verbose) self.Bind(wx.EVT_BUTTON, self.evt_shell, self.shell) self.Bind(wx.EVT_BUTTON, self.evt_donate, self.donate) # end wxGlade def __set_properties(self): # begin wxGlade: Palette.__set_properties self.SetBackgroundColour(wx.Colour(255, 255, 255)) self.previous.SetBackgroundColour(wx.Colour(255, 255, 255)) self.previous.SetToolTipString(_("Previous window | Ctrl+Shift+`")) self.previous.SetSize(self.previous.GetBestSize()) self.next.SetBackgroundColour(wx.Colour(255, 255, 255)) self.next.SetToolTipString(_("Next window | Ctrl+`")) self.next.SetSize(self.next.GetBestSize()) self.find.SetBackgroundColour(wx.Colour(255, 255, 255)) self.find.SetToolTipString(_("Find & replace... | Ctrl+F")) self.find.SetSize(self.find.GetBestSize()) self.goto.SetBackgroundColour(wx.Colour(255, 255, 255)) self.goto.SetToolTipString(_("Go to line... | Ctrl+G")) self.goto.SetSize(self.goto.GetBestSize()) self.browse_source.SetBackgroundColour(wx.Colour(255, 255, 255)) self.browse_source.SetToolTipString(_("Browse source | Ctrl+Enter")) self.browse_source.SetSize(self.browse_source.GetBestSize()) self.check.SetBackgroundColour(wx.Colour(255, 255, 255)) self.check.SetToolTipString(_("Check source with pychecker | Ctrl+Alt+C")) self.check.SetSize(self.check.GetBestSize()) self.dedent.SetBackgroundColour(wx.Colour(255, 255, 255)) self.dedent.SetToolTipString(_("Dedent | Shift+Tab")) self.dedent.SetSize(self.dedent.GetBestSize()) self.indent.SetBackgroundColour(wx.Colour(255, 255, 255)) self.indent.SetToolTipString(_("Indent | Tab")) self.indent.SetSize(self.indent.GetBestSize()) self.comment.SetBackgroundColour(wx.Colour(255, 255, 255)) self.comment.SetToolTipString(_("Comment | Alt+3")) self.comment.SetSize(self.comment.GetBestSize()) self.uncomment.SetBackgroundColour(wx.Colour(255, 255, 255)) self.uncomment.SetToolTipString(_("Uncomment | Alt+4")) self.uncomment.SetSize(self.uncomment.GetBestSize()) self.run.SetBackgroundColour(wx.Colour(255, 255, 255)) self.run.SetToolTipString(_("Run | F9")) self.run.SetSize(self.run.GetBestSize()) self.imprt.SetBackgroundColour(wx.Colour(255, 255, 255)) self.imprt.SetToolTipString(_("Import | F10")) self.imprt.SetSize(self.imprt.GetBestSize()) self.sidebar.SetBackgroundColour(wx.Colour(255, 255, 255)) self.sidebar.SetToolTipString(_("Show/hide sidebar | F11")) self.sidebar.SetSize(self.sidebar.GetBestSize()) self.run_verbose.SetBackgroundColour(wx.Colour(255, 255, 255)) self.run_verbose.SetToolTipString(_("Run verbose | Ctrl+Alt+R")) self.run_verbose.SetSize(self.run_verbose.GetBestSize()) self.shell.SetBackgroundColour(wx.Colour(255, 255, 255)) self.shell.SetToolTipString(_("Show/hide shell | F12")) self.shell.SetSize(self.shell.GetBestSize()) self.donate.SetBackgroundColour(wx.Colour(255, 255, 255)) self.donate.SetToolTipString(_("Please donate, if you enjoy SPE.")) self.donate.SetSize(self.donate.GetBestSize()) # end wxGlade def __do_layout(self): # begin wxGlade: Palette.__do_layout sizer_main = wx.BoxSizer(wx.VERTICAL) sizer_palette = wx.GridSizer(1, 2, 0, 0) sizer_main.Add(self.logo, 0, 0, 0) sizer_palette.Add(self.previous, 0, 0, 0) sizer_palette.Add(self.next, 0, 0, 0) sizer_palette.Add(self.find, 0, 0, 0) sizer_palette.Add(self.goto, 0, 0, 0) sizer_palette.Add(self.browse_source, 0, 0, 0) sizer_palette.Add(self.check, 0, 0, 0) sizer_palette.Add(self.dedent, 0, 0, 0) sizer_palette.Add(self.indent, 0, 0, 0) sizer_palette.Add(self.comment, 0, 0, 0) sizer_palette.Add(self.uncomment, 0, 0, 0) sizer_palette.Add(self.run, 0, 0, 0) sizer_palette.Add(self.imprt, 0, 0, 0) sizer_palette.Add(self.sidebar, 0, 0, 0) sizer_palette.Add(self.run_verbose, 0, 0, 0) sizer_palette.Add(self.shell, 0, 0, 0) sizer_palette.Add(self.donate, 0, 0, 0) sizer_main.Add(sizer_palette, 1, wx.EXPAND, 0) self.SetSizer(sizer_main) sizer_main.Fit(self) # end wxGlade def evt_indent(self, event): # wxGlade: Palette. event.Skip() def evt_dedent(self, event): # wxGlade: Palette. event.Skip() def evt_comment(self, event): # wxGlade: Palette. event.Skip() def evt_uncomment(self, event): # wxGlade: Palette. event.Skip() def evt_run(self, event): # wxGlade: Palette. event.Skip() def evt_import(self, event): # wxGlade: Palette. event.Skip() def evt_find(self, event): # wxGlade: Palette. event.Skip() def evt_goto(self, event): # wxGlade: Palette. event.Skip() def evt_browse_source(self, event): # wxGlade: Palette. event.Skip() def evt_shell(self, event): # wxGlade: Palette. event.Skip() def evt_check(self, event): # wxGlade: Palette. event.Skip() def evt_donate(self, event): # wxGlade: Palette. event.Skip() def evt_previous(self, event): # wxGlade: Palette. event.Skip() def evt_next(self, event): # wxGlade: Palette. event.Skip() def evt_sidebar(self, event): # wxGlade: Palette. event.Skip() def evt_run_verbose(self, event): # wxGlade: Palette. event.Skip() # end of class Palette class Bar(wx.MenuBar): def __init__(self, *args, **kwds): # begin wxGlade: Bar.__init__ wx.MenuBar.__init__(self, *args, **kwds) self.file = wx.Menu() self.file.Append(wx.ID_NEW, _("&New\tCtrl+N"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_OPEN, _("&Open file(s)...\tCtrl+O"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_SAVE, _("&Save\tCtrl+S"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_SAVEAS, _("Save &As...\tCtrl+Alt+S"), "", wx.ITEM_NORMAL) self.file.Append(SAVE_COPY, _("Sa&ve a Copy...\tShift+Ctrl+Alt+S"), "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.file.Append(OPEN_WORKSPACE, _("Open &Workspace"), "", wx.ITEM_NORMAL) self.file.Append(SAVE_WORKSPACE, _("Save Workspace"), "", wx.ITEM_NORMAL) self.file.Append(SAVE_WORKSPACE_AS, _("Save Workspace As..."), "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.file.Append(SAVE_UML_AS, _("Save Uml As...\tCtrl+Shift+S"), "", wx.ITEM_NORMAL) self.file.Append(PRINT_UML_SETUP, _("Page Uml Setup..."), "", wx.ITEM_NORMAL) self.file.Append(PRINT_UML_PREVIEW, _("Print Uml Preview..."), "", wx.ITEM_NORMAL) self.file.Append(PRINT_UML, _("Print Uml..."), "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.file.Append(wx.ID_CLOSE, _("&Close\tCtrl+W"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_EXIT, _("&Exit\tAlt+F4"), "", wx.ITEM_NORMAL) self.file.AppendSeparator() self.file.Append(REMEMBER_OPEN_FILES, _("&Remember open file(s)"), "", wx.ITEM_CHECK) self.Append(self.file, _("&File")) self.edit = wx.Menu() self.edit.Append(wx.ID_UNDO, _("&Undo\tCtrl+Z"), "", wx.ITEM_NORMAL) self.edit.Append(wx.ID_REDO, _("&Redo\tCtrl+Y"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(CUT, _("Cut"), "", wx.ITEM_NORMAL) self.edit.Append(COPY, _("&Copy"), "", wx.ITEM_NORMAL) self.edit.Append(PASTE, _("&Paste"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(EXECUTE, _("&Execute in shell\tCtrl+Shift+E"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(wx.ID_REPLACE, _("&Find && replace...\tCtrl+F"), "", wx.ITEM_NORMAL) self.edit.Append(wx.ID_FIND, _("Find &Next\tF3"), "", wx.ITEM_NORMAL) self.edit.Append(GO_TO_LINE, _("&Go to line...\tCtrl+G"), "", wx.ITEM_NORMAL) self.edit.Append(BROWSE_SOURCE, _("&Browse source\tCtrl+Enter"), "", wx.ITEM_NORMAL) self.edit.Append(AUTO_COMPLETE, _("&Auto complete\tCtrl+Space"), "", wx.ITEM_NORMAL) self.edit.Append(SHOW_DOCSTRING, _("&Show docstring\tCtrl+Shift+Space"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(INDENT, _("&Indent"), "", wx.ITEM_NORMAL) self.edit.Append(DEDENT, _("&Dedent\tShift+Tab"), "", wx.ITEM_NORMAL) self.edit.Append(COMMENT, _("Co&mment\tCtrl+3"), "", wx.ITEM_NORMAL) self.edit.Append(UNCOMMENT, _("U&nComment\tCtrl+4"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(INSERT_SEPARATOR, _("Insert &separator...\tAlt+I"), "", wx.ITEM_NORMAL) self.edit.Append(INSERT_SIGNATURE, _("Insert &signature\tCtrl+Shift+I"), "", wx.ITEM_NORMAL) self.edit.AppendSeparator() self.edit.Append(PREFERENCES, _("&Preferences...\tCtrl+Alt+P"), "", wx.ITEM_NORMAL) self.Append(self.edit, _("&Edit")) self.view = wx.Menu() self.view.Append(WHITESPACE, _("&Whitespace"), "", wx.ITEM_CHECK) self.view.Append(INDENTATION_GUIDES, _("&Indentation guides"), "", wx.ITEM_CHECK) self.view.Append(RIGHT_EDGE_INDICATOR, _("Ri&ght edge indicator"), "", wx.ITEM_CHECK) self.view.Append(END_OF_LINE_MARKER, _("&End-of-line marker"), "", wx.ITEM_CHECK) self.view.AppendSeparator() self.view.Append(AS_NOTEBOOK, _("As ¬ebook"), "", wx.ITEM_NORMAL) self.view.Append(AS_COLUMNS, _("As &columns"), "", wx.ITEM_NORMAL) self.view.Append(AS_ROWS, _("As &rows"), "", wx.ITEM_NORMAL) self.view.AppendSeparator() self.view.Append(SIDEBAR, _("&Sidebar\tCtrl+F12"), "", wx.ITEM_CHECK) self.view.Append(SHELL, _("S&hell\tF12"), "", wx.ITEM_CHECK) self.view.AppendSeparator() self.view.Append(CLEAR_OUTPUT, _("Clear &output"), "", wx.ITEM_NORMAL) self.view.Append(REFRESH, _("&Refresh\tF5"), "", wx.ITEM_NORMAL) self.Append(self.view, _("&View")) self.tools = wx.Menu() self.tools.Append(RUN, _("Run\\Stop\tCtrl+R"), "", wx.ITEM_NORMAL) self.tools.Append(RUN_WITHOUT_ARGUMENTS, _("Run without arguments/Stop\tCtrl+Shift+R"), "", wx.ITEM_NORMAL) self.tools.AppendSeparator() self.tools.Append(RUN_DEBUG, _("Run/Stop with &WinPdb\tCtrl+F9"), "", wx.ITEM_NORMAL) self.tools.Append(DEBUG, _("&Debug with winpdb...\tAlt+F9"), "", wx.ITEM_NORMAL) self.tools.AppendSeparator() self.tools.Append(RUN_TERMINAL, _("&Run in terminal\tF9"), "", wx.ITEM_NORMAL) self.tools.Append(RUN_TERMINAL_WITHOUT_ARGUMENTS, _("Run in terminal without &arguments\tShift+F9"), "", wx.ITEM_NORMAL) self.tools.Append(RUN_TERMINAL_WITHOUT_ARGUMENTS_EXIT, _("Run in terminal without &arguments && exit\tCtrl+Shift+F9"), "", wx.ITEM_NORMAL) self.tools.AppendSeparator() self.tools.Append(IMPORT, _("&Import in shell\tF10"), "", wx.ITEM_NORMAL) self.tools.AppendSeparator() self.tools.Append(BROWSE_OBJECT_WITH_PYFILLING, _("&Browse object with PyFilling...\tCtrl+Alt+F"), "", wx.ITEM_NORMAL) self.tools.Append(TEST_REGULAR_EXPRESSION_WITH_KIKI, _("Test regular expression with &Kiki...\tCtrl+K"), "", wx.ITEM_NORMAL) self.tools.Append(DESIGN_A_GUI_WITH_WXGLADE, _("Design a &gui with wxGlade...\tCtrl+Alt+G"), "", wx.ITEM_NORMAL) self.tools.Append(DESIGN_A_GUI_WITH_XRC, _("Design a gui with &XRC...\tCtrl+Alt+X"), "", wx.ITEM_NORMAL) self.tools.Append(CHECK_SOURCE_WITH_PYCHECKER, _("&Check source with PyChecker\tCtrl+Alt+C"), "", wx.ITEM_NORMAL) self.tools.AppendSeparator() self.tools.Append(BROWSE_FOLDER, _("Browse &folder\tCtrl+Shift+F"), "", wx.ITEM_NORMAL) self.tools.Append(OPEN_TERMINAL_EMULATOR, _("Open &terminal...\tCtrl+Shift+T"), "", wx.ITEM_NORMAL) self.Append(self.tools, _("&Tools")) self.blender = wx.Menu() self.blender.Append(LOAD_IN_BLENDER, _("&Load into Blender\tCtrl+B"), "", wx.ITEM_NORMAL) self.blender.Append(REFERENCE_IN_BLENDER, _("&Reference in Blender\tCtrl+Alt+B"), "", wx.ITEM_NORMAL) self.blender.AppendSeparator() self.blender.Append(REDRAW_BLENDER_WINDOW, _("Re&draw Blender window\tF5"), "", wx.ITEM_NORMAL) self.blender.AppendSeparator() self.blender.Append(BLENDER_PYTHON_MANUAL, _("Blender Python &manual..."), "", wx.ITEM_NORMAL) self.blender.Append(BLENDER_PYTHON_TUTORIAL, _("Blender Python &tutorial..."), "", wx.ITEM_NORMAL) self.blender.AppendSeparator() self.blender.Append(BLENDER_HOMEPAGE, _("Blender &homepage..."), "", wx.ITEM_NORMAL) self.blender.Append(DOWNLOAD_BLENDER, _("&Download Blender..."), "", wx.ITEM_NORMAL) self.blender.Append(FORUM_BLENDER_PYTHON, _("Forum &Blender Python..."), "", wx.ITEM_NORMAL) self.blender.Append(FORUM_ELYSIUN_PYTHON, _("Forum &Blenderartists Python..."), "", wx.ITEM_NORMAL) self.blender.AppendSeparator() self.blender.Append(ADD_SPE_TO_BLENDER, _("&Add SPE and Winpdb to Blender menu..."), "", wx.ITEM_NORMAL) self.Append(self.blender, _("&Blender")) self.links = wx.Menu() self.links.Append(SPE_HOMEPAGE, _("&Spe homepage..."), "", wx.ITEM_NORMAL) self.links.Append(FORUM_SPE, _("&Forum spe..."), "", wx.ITEM_NORMAL) self.links.AppendSeparator() self.links.Append(PYTHON_HOMEPAGE, _("&Python homepage..."), "", wx.ITEM_NORMAL) self.links.Append(PYTHON_ANNOUNCEMENTS, _("Python &announcements..."), "", wx.ITEM_NORMAL) self.links.Append(PYTHON_COOKBOOK, _("Python cook&book..."), "", wx.ITEM_NORMAL) self.links.Append(PYTHON_DAILY, _("Python &daily..."), "", wx.ITEM_NORMAL) self.links.Append(PYTHON_PACKAGE_INDEX, _("Python package &index..."), "", wx.ITEM_NORMAL) self.links.AppendSeparator() self.links.Append(AUTHORS_HOMEPAGE, _("&Authors homepage"), "", wx.ITEM_NORMAL) self.Append(self.links, _("&Links")) self.window = wx.Menu() self.window.Append(NEXT, _("&Next\tCtrl+`"), "", wx.ITEM_NORMAL) self.window.Append(PREVIOUS, _("&Previous\tCtrl+Shift+`"), "", wx.ITEM_NORMAL) self.Append(self.window, _("&Window")) self.help = wx.Menu() self.help.Append(MANUAL, _("&Manual..."), "", wx.ITEM_NORMAL) self.help.Append(KEYBOARD_SHORTCUTS, _("&Keyboard shortcuts..."), "", wx.ITEM_NORMAL) self.help.AppendSeparator() self.help.Append(PYTHON_LIBRARY, _("Python &library..."), "", wx.ITEM_NORMAL) self.help.Append(PYTHON_REFERENCE, _("Python &reference..."), "", wx.ITEM_NORMAL) self.help.Append(PYTHON_DOCUMENTATION_SERVER, _("Python documentation &server..."), "", wx.ITEM_NORMAL) self.help.AppendSeparator() self.help.Append(WXGLADE_MANUAL, _("wxGlade manual..."), "", wx.ITEM_NORMAL) self.help.Append(WXGLADE_TUTORIAL, _("wx&Glade tutorial..."), "", wx.ITEM_NORMAL) self.help.Append(WXWINDOWS_DOCUMENTATION, _("wxWindows documentation..."), "", wx.ITEM_NORMAL) self.help.AppendSeparator() self.help.Append(DONATE, _("&Donate..."), "", wx.ITEM_NORMAL) self.help.Append(ABOUT, _("&About..."), "", wx.ITEM_NORMAL) self.Append(self.help, _("&Help")) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_MENU, self.menu_new, id=wx.ID_NEW) self.Bind(wx.EVT_MENU, self.menu_open_files, id=wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.menu_save, id=wx.ID_SAVE) self.Bind(wx.EVT_MENU, self.menu_save_as, id=wx.ID_SAVEAS) self.Bind(wx.EVT_MENU, self.menu_save_copy, id=SAVE_COPY) self.Bind(wx.EVT_MENU, self.menu_open_workspace, id=OPEN_WORKSPACE) self.Bind(wx.EVT_MENU, self.menu_save_workspace, id=SAVE_WORKSPACE) self.Bind(wx.EVT_MENU, self.menu_save_workspace_as, id=SAVE_WORKSPACE_AS) self.Bind(wx.EVT_MENU, self.menu_save_uml_as, id=SAVE_UML_AS) self.Bind(wx.EVT_MENU, self.menu_print_uml_setup, id=PRINT_UML_SETUP) self.Bind(wx.EVT_MENU, self.menu_print_uml_preview, id=PRINT_UML_PREVIEW) self.Bind(wx.EVT_MENU, self.menu_print_uml, id=PRINT_UML) self.Bind(wx.EVT_MENU, self.menu_close, id=wx.ID_CLOSE) self.Bind(wx.EVT_MENU, self.menu_exit, id=wx.ID_EXIT) self.Bind(wx.EVT_MENU, self.menu_remember_open_files, id=REMEMBER_OPEN_FILES) self.Bind(wx.EVT_MENU, self.menu_undo, id=wx.ID_UNDO) self.Bind(wx.EVT_MENU, self.menu_redo, id=wx.ID_REDO) self.Bind(wx.EVT_MENU, self.menu_cut, id=CUT) self.Bind(wx.EVT_MENU, self.menu_copy, id=COPY) self.Bind(wx.EVT_MENU, self.menu_paste, id=PASTE) self.Bind(wx.EVT_MENU, self.menu_execute, id=EXECUTE) self.Bind(wx.EVT_MENU, self.menu_find__replace, id=wx.ID_REPLACE) self.Bind(wx.EVT_MENU, self.menu_find_next, id=wx.ID_FIND) self.Bind(wx.EVT_MENU, self.menu_go_to_line, id=GO_TO_LINE) self.Bind(wx.EVT_MENU, self.menu_browse_source, id=BROWSE_SOURCE) self.Bind(wx.EVT_MENU, self.menu_auto_complete, id=AUTO_COMPLETE) self.Bind(wx.EVT_MENU, self.menu_show_docstring, id=SHOW_DOCSTRING) self.Bind(wx.EVT_MENU, self.menu_indent, id=INDENT) self.Bind(wx.EVT_MENU, self.menu_dedent, id=DEDENT) self.Bind(wx.EVT_MENU, self.menu_comment, id=COMMENT) self.Bind(wx.EVT_MENU, self.menu_uncomment, id=UNCOMMENT) self.Bind(wx.EVT_MENU, self.menu_insert_separator, id=INSERT_SEPARATOR) self.Bind(wx.EVT_MENU, self.menu_insert_signature, id=INSERT_SIGNATURE) self.Bind(wx.EVT_MENU, self.menu_preferences, id=PREFERENCES) self.Bind(wx.EVT_MENU, self.menu_whitespace, id=WHITESPACE) self.Bind(wx.EVT_MENU, self.menu_indentation, id=INDENTATION_GUIDES) self.Bind(wx.EVT_MENU, self.menu_right_edge_indicator, id=RIGHT_EDGE_INDICATOR) self.Bind(wx.EVT_MENU, self.menu_end_of_line_marker, id=END_OF_LINE_MARKER) self.Bind(wx.EVT_MENU, self.menu_as_notebook, id=AS_NOTEBOOK) self.Bind(wx.EVT_MENU, self.menu_as_columns, id=AS_COLUMNS) self.Bind(wx.EVT_MENU, self.menu_as_rows, id=AS_ROWS) self.Bind(wx.EVT_MENU, self.menu_sidebar, id=SIDEBAR) self.Bind(wx.EVT_MENU, self.menu_shell, id=SHELL) self.Bind(wx.EVT_MENU, self.menu_clear_output, id=CLEAR_OUTPUT) self.Bind(wx.EVT_MENU, self.menu_refresh, id=REFRESH) self.Bind(wx.EVT_MENU, self.menu_run, id=RUN) self.Bind(wx.EVT_MENU, self.menu_run_without_arguments, id=RUN_WITHOUT_ARGUMENTS) self.Bind(wx.EVT_MENU, self.menu_run_debug, id=RUN_DEBUG) self.Bind(wx.EVT_MENU, self.menu_debug, id=DEBUG) self.Bind(wx.EVT_MENU, self.menu_run_terminal, id=RUN_TERMINAL) self.Bind(wx.EVT_MENU, self.menu_run_terminal_without_arguments, id=RUN_TERMINAL_WITHOUT_ARGUMENTS) self.Bind(wx.EVT_MENU, self.menu_run_terminal_without_arguments_exit, id=RUN_TERMINAL_WITHOUT_ARGUMENTS_EXIT) self.Bind(wx.EVT_MENU, self.menu_import, id=IMPORT) self.Bind(wx.EVT_MENU, self.menu_browse_object_with_pyfilling, id=BROWSE_OBJECT_WITH_PYFILLING) self.Bind(wx.EVT_MENU, self.menu_test_regular_expression_with_kiki, id=TEST_REGULAR_EXPRESSION_WITH_KIKI) self.Bind(wx.EVT_MENU, self.menu_design_a_gui_with_wxglade, id=DESIGN_A_GUI_WITH_WXGLADE) self.Bind(wx.EVT_MENU, self.menu_design_a_gui_with_xrc, id=DESIGN_A_GUI_WITH_XRC) self.Bind(wx.EVT_MENU, self.menu_check_source_with_pychecker, id=CHECK_SOURCE_WITH_PYCHECKER) self.Bind(wx.EVT_MENU, self.menu_browse_folder, id=BROWSE_FOLDER) self.Bind(wx.EVT_MENU, self.menu_open_terminal_emulator, id=OPEN_TERMINAL_EMULATOR) self.Bind(wx.EVT_MENU, self.menu_load_in_blender, id=LOAD_IN_BLENDER) self.Bind(wx.EVT_MENU, self.menu_reference_in_blender, id=REFERENCE_IN_BLENDER) self.Bind(wx.EVT_MENU, self.menu_blender_python_manual, id=BLENDER_PYTHON_MANUAL) self.Bind(wx.EVT_MENU, self.menu_blender_python_tutorial, id=BLENDER_PYTHON_TUTORIAL) self.Bind(wx.EVT_MENU, self.menu_blender_homepage, id=BLENDER_HOMEPAGE) self.Bind(wx.EVT_MENU, self.menu_download_blender, id=DOWNLOAD_BLENDER) self.Bind(wx.EVT_MENU, self.menu_forum_blender_python, id=FORUM_BLENDER_PYTHON) self.Bind(wx.EVT_MENU, self.menu_forum_elysiun_python, id=FORUM_ELYSIUN_PYTHON) self.Bind(wx.EVT_MENU, self.menu_add_spe_to_blender, id=ADD_SPE_TO_BLENDER) self.Bind(wx.EVT_MENU, self.menu_spe_homepage, id=SPE_HOMEPAGE) self.Bind(wx.EVT_MENU, self.menu_forum_spe, id=FORUM_SPE) self.Bind(wx.EVT_MENU, self.menu_python_announcements, id=PYTHON_ANNOUNCEMENTS) self.Bind(wx.EVT_MENU, self.menu_python_cookbook, id=PYTHON_COOKBOOK) self.Bind(wx.EVT_MENU, self.menu_python_daily, id=PYTHON_DAILY) self.Bind(wx.EVT_MENU, self.menu_python_package_index, id=PYTHON_PACKAGE_INDEX) self.Bind(wx.EVT_MENU, self.menu_authors_homepage, id=AUTHORS_HOMEPAGE) self.Bind(wx.EVT_MENU, self.menu_next, id=NEXT) self.Bind(wx.EVT_MENU, self.menu_previous, id=PREVIOUS) self.Bind(wx.EVT_MENU, self.menu_manual, id=MANUAL) self.Bind(wx.EVT_MENU, self.menu_keyboard_shortcuts, id=KEYBOARD_SHORTCUTS) self.Bind(wx.EVT_MENU, self.menu_python_library, id=PYTHON_LIBRARY) self.Bind(wx.EVT_MENU, self.menu_python_reference, id=PYTHON_REFERENCE) self.Bind(wx.EVT_MENU, self.menu_python_documentation_server, id=PYTHON_DOCUMENTATION_SERVER) self.Bind(wx.EVT_MENU, self.menu_wxglade_manual, id=WXGLADE_MANUAL) self.Bind(wx.EVT_MENU, self.menu_wxglade_tutorial, id=WXGLADE_TUTORIAL) self.Bind(wx.EVT_MENU, self.menu_wxwindows_documentation, id=WXWINDOWS_DOCUMENTATION) self.Bind(wx.EVT_MENU, self.menu_donate, id=DONATE) self.Bind(wx.EVT_MENU, self.menu_about, id=ABOUT) # end wxGlade def __set_properties(self): # begin wxGlade: Bar.__set_properties pass # end wxGlade def __do_layout(self): # begin wxGlade: Bar.__do_layout pass # end wxGlade def menu_new(self, event): # wxGlade: Bar. event.Skip() def menu_open(self, event): # wxGlade: Bar. event.Skip() def menu_save(self, event): # wxGlade: Bar. event.Skip() def menu_save_as(self, event): # wxGlade: Bar. event.Skip() def menu_open_workspace(self, event): # wxGlade: Bar. event.Skip() def menu_save_workspace_as(self, event): # wxGlade: Bar. event.Skip() def menu_save_workspace(self, event): # wxGlade: Bar. event.Skip() def menu_close(self, event): # wxGlade: Bar. event.Skip() def menu_exit(self, event): # wxGlade: Bar. event.Skip() def menu_remember_open_files(self, event): # wxGlade: Bar. event.Skip() def menu_undo(self, event): # wxGlade: Bar. event.Skip() def menu_redo(self, event): # wxGlade: Bar. event.Skip() def menu_cut(self, event): # wxGlade: Bar. event.Skip() def menu_copy(self, event): # wxGlade: Bar. event.Skip() def menu_paste(self, event): # wxGlade: Bar. event.Skip() def menu_find__replace(self, event): # wxGlade: Bar. event.Skip() def menu_go_to_line(self, event): # wxGlade: Bar. event.Skip() def menu_browse_source(self, event): # wxGlade: Bar. event.Skip() def menu_auto_complete(self, event): # wxGlade: Bar. event.Skip() def menu_indent(self, event): # wxGlade: Bar. event.Skip() def menu_dedent(self, event): # wxGlade: Bar. event.Skip() def menu_comment(self, event): # wxGlade: Bar. event.Skip() def menu_uncomment(self, event): # wxGlade: Bar. event.Skip() def menu_insert_separator(self, event): # wxGlade: Bar. event.Skip() def menu_insert_signature(self, event): # wxGlade: Bar. print "Event handler `menu_insert_signature' not implemented" event.Skip() def menu_execute(self, event): # wxGlade: Bar. print "Event handler `menu_execute' not implemented" event.Skip() def menu_execute_verbose(self, event): # wxGlade: Bar. print "Event handler `menu_execute_verbose' not implemented" event.Skip() def menu_preferences(self, event): # wxGlade: Bar. event.Skip() def menu_refresh(self, event): # wxGlade: Bar. event.Skip() def menu_whitespace(self, event): # wxGlade: Bar. event.Skip() def menu_indentation(self, event): # wxGlade: Bar. event.Skip() def menu_right_edge_indicator(self, event): # wxGlade: Bar. event.Skip() def menu_end_of_line_marker(self, event): # wxGlade: Bar. event.Skip() def menu_as_notebook(self, event): # wxGlade: Bar. print "Event handler `menu_as_notebook' not implemented" event.Skip() def menu_as_columns(self, event): # wxGlade: Bar. print "Event handler `menu_as_columns' not implemented" event.Skip() def menu_as_rows(self, event): # wxGlade: Bar. print "Event handler `menu_as_rows' not implemented" event.Skip() def menu_sidebar(self, event): # wxGlade: Bar. event.Skip() def menu_shell(self, event): # wxGlade: Bar. event.Skip() def menu_run(self, event): # wxGlade: Bar. event.Skip() def menu_run_without_arguments(self, event): # wxGlade: Bar. event.Skip() def menu_run_terminal(self, event): # wxGlade: Bar. print "Event handler `menu_run_terminal' not implemented" event.Skip() def menu_run_terminal_without_arguments(self, event): # wxGlade: Bar. print "Event handler `menu_run_terminal_without_arguments' not implemented" event.Skip() def menu_run_terminal_without_arguments_exit(self, event): # wxGlade: Bar. print "Event handler `menu_run_terminal_without_arguments_exit' not implemented" event.Skip() def menu_import(self, event): # wxGlade: Bar. event.Skip() def menu_browse_object_with_pyfilling(self, event): # wxGlade: Bar. event.Skip() def menu_test_regular_expression_with_kiki(self, event): # wxGlade: Bar. event.Skip() def menu_design_a_gui_with_wxglade(self, event): # wxGlade: Bar. event.Skip() def menu_design_a_gui_with_xrc(self, event): # wxGlade: Bar. event.Skip() def menu_check_source_with_pychecker(self, event): # wxGlade: Bar. event.Skip() def menu_browse_folder(self, event): # wxGlade: Bar. event.Skip() def menu_open_terminal_emulator(self, event): # wxGlade: Bar. event.Skip() def menu_load_in_blender(self, event): # wxGlade: Bar. event.Skip() def menu_reference_in_blender(self, event): # wxGlade: Bar. event.Skip() def menu_blender_python_manual(self, event): # wxGlade: Bar. event.Skip() def menu_blender_python_tutorial(self, event): # wxGlade: Bar. event.Skip() def menu_blender_homepage(self, event): # wxGlade: Bar. event.Skip() def menu_download_blender(self, event): # wxGlade: Bar. event.Skip() def menu_forum_blender_python(self, event): # wxGlade: Bar. event.Skip() def menu_forum_elysiun_python(self, event): # wxGlade: Bar. event.Skip() def menu_spe_homepage(self, event): # wxGlade: Bar. event.Skip() def menu_forum_spe(self, event): # wxGlade: Bar. event.Skip() def menu_authors_homepage(self, event): # wxGlade: Bar. event.Skip() def menu_contact_author(self, event): # wxGlade: Bar. event.Skip() def menu_active_python_distribution(self, event): # wxGlade: Bar. event.Skip() def menu_enthought_python_distribution(self, event): # wxGlade: Bar. event.Skip() def menu_python_announcements(self, event): # wxGlade: Bar. event.Skip() def menu_python_cookbook(self, event): # wxGlade: Bar. event.Skip() def menu_python_daily(self, event): # wxGlade: Bar. event.Skip() def menu_python_package_index(self, event): # wxGlade: Bar. event.Skip() def menu_manual(self, event): # wxGlade: Bar. event.Skip() def menu_keyboard_shortcuts(self, event): # wxGlade: Bar. event.Skip() def menu_python_library(self, event): # wxGlade: Bar. event.Skip() def menu_python_reference(self, event): # wxGlade: Bar. event.Skip() def menu_python_documentation_server(self, event): # wxGlade: Bar. event.Skip() def menu_wxglade_manual(self, event): # wxGlade: Bar. event.Skip() def menu_wxglade_tutorial(self, event): # wxGlade: Bar. event.Skip() def menu_wxwindows_documentation(self, event): # wxGlade: Bar. event.Skip() def menu_donate(self, event): # wxGlade: Bar. event.Skip() def menu_about(self, event): # wxGlade: Bar. event.Skip() def menu_find_next(self, event): # wxGlade: Bar. event.Skip() def menu_open_files(self, event): # wxGlade: Bar. event.Skip() def menu_next(self, event): # wxGlade: Bar. event.Skip() def menu_previous(self, event): # wxGlade: Bar. event.Skip() def menu_debug(self, event): # wxGlade: Bar. event.Skip() def menu_save_uml_as(self, event): # wxGlade: Bar. print "Event handler `menu_save_uml_as' not implemented" event.Skip() def menu_print_uml_setup(self, event): # wxGlade: Bar. print "Event handler `menu_print_uml_setup' not implemented" event.Skip() def menu_uml_preview(self, event): # wxGlade: Bar. print "Event handler `menu_uml_preview' not implemented" event.Skip() def menu_print_uml(self, event): # wxGlade: Bar. print "Event handler `menu_print_uml' not implemented" event.Skip() def menu_print_uml_preview(self, event): # wxGlade: Bar. print "Event handler `menu_print_uml_preview' not implemented" event.Skip() def menu_run_without_arguments(self, event): # wxGlade: Bar. print "Event handler `menu_run_without_arguments' not implemented" event.Skip() def menu_run_debug(self, event): # wxGlade: Bar. print "Event handler `menu_run_debug' not implemented" event.Skip() def menu_run_without_arguments_exit(self, event): # wxGlade: Bar. print "Event handler `menu_run_without_arguments_exit' not implemented" event.Skip() def menu_toolbar(self, event): # wxGlade: Bar. print "Event handler `menu_toolbar' not implemented" event.Skip() def menu_show_docstring(self, event): # wxGlade: Bar. print "Event handler `menu_show_docstring' not implemented" event.Skip() def menu_save_copy(self, event): # wxGlade: Bar. print "Event handler `menu_save_copy' not implemented" event.Skip() def menu_clear_output(self, event): # wxGlade: Bar. print "Event handler `menu_clear_output' not implemented" event.Skip() def menu_add_spe_to_blender(self, event): # wxGlade: Bar. print "Event handler `menu_add_spe_to_blender' not implemented" event.Skip() # end of class Bar spe-0.8.4.h/_spe/Parent.py0000644000175000017500000016447111003651355014323 0ustar stanistani####(c)www.stani.be import _spe.info as info INFO=info.copy() INFO['description']=\ """Subclassed smdi Parent frame.""" __doc__=INFO['doc']%INFO ####Importing modules----------------------------------------------------------- #---general modules import ConfigParser,os,string,sys,thread,time,types,webbrowser, pprint import _spe,sm.scriptutils,sm.wxp import dialogs.stcStyleEditor #---wxPython import wx import wx.stc from wx.lib.evtmgr import eventManager BLENDER_MESSAGE = 'Spe must be launched within Blender for this feature.' STATUS_TEXT_WORKSPACE_POS = 2 # Todo: can this be done more dynamic? import Child ####Constants------------------------------------------------------------------- DEFAULT = "" FIREFOX = '/usr/bin/firefox' NAUTILUS = '/usr/bin/nautilus --no-desktop' DOLPHIN = '/usr/bin/dolphin' KONQUEROR = '/usr/bin/konqueror' THUNAR = '/usr/bin/thunar' PCMANFM = '/usr/bin/pcmanfm' HELP_SORRY = "Sorry, '%s' was not found on your system, getting it from internet instead." HELP_WWW = 'http://www.python.org/doc/current/%s/%s.html' MAIL = 'mailto:spe.stani.be@gmail.com?subject=About spe...' PATH = info.dirname(__file__) PLATFORM = sys.platform PREFIX = sys.prefix SIZE = (600,1) SKIN = 'default' TABS = ['Shell','Locals','Session','Output','Find','Browser','Recent','Todo','Index','Notes','Donate'] TITLE = 'SPE %s' UNNAMED = 'unnamed' RECENT = 'recent.txt' FOLDERS = 'folders.txt' NOTES = 'notes.txt' REMEMBER = 'remember.txt' if info.LINUX: STYLE = wx.NB_TOP else: STYLE = wx.NB_BOTTOM BLENDER_SHORTCUT_SPE = "spe_blender.py" #a shortcut to SPE from Blender BLENDER_SHORTCUT_WINPDB = "winpdb_blender.py" #a shortcut to Winpdb from Blender ####Subclassed Parent class----------------------------------------------------- class Panel(wx.Notebook): ####Constructors def __init__(self, parent, openFiles=[], splash=None, redirect=1, path=PATH, size = SIZE,**settings): wx.Notebook.__init__(self,parent=parent,id=wx.ID_ANY,style=STYLE,size=size) self.__paths__(path) self.__settings__(openFiles,redirect,**settings) self.__findReplaceEvents__() # Todo: make this a real class instead of this lazy one self.workspace=self.emptyWorkspace() def __timer__(self): self.lock = thread.allocate_lock() #self.Bind(wx.EVT_IDLE,self.onIdle) self.Bind(wx.EVT_TIMER,self.onTimer) #self.was_idle = False self.timer = wx.Timer(self) wx.CallAfter(self.timer.Start,self.getValue('Redraw')) def __paths__(self,path,skin='default'): self.path = path self.pathDoc = os.path.join(self.path, 'doc') self.pathSkins = os.path.join(self.path, 'skins') self.pathImages = os.path.join(self.pathSkins, skin) self.pathPlugins = os.path.join(self.path, 'plugins') self.pathTabs = os.path.join(self.path, 'tabs') if self.pathPlugins not in sys.path: sys.path.insert(0,self.pathPlugins) try: os.mkdir(INFO['userPath']) except: if not os.path.exists(INFO['userPath']): print 'Warning: could not find or create user path (%s).'%INFO['userPath'] def __settings__(self,openFiles,redirect,redraw=None,Blender=None,**kwds): #arguments self._openFiles = openFiles self._redirect = redirect self._simultaneous = False self.redraw = redraw self.Blender = Blender #panel self.argumentsPrevious = [] self.beepPrevious = False self.defaultEncoding = None self.findDialog = None self.folders = [] self.kiki = None self.remember = 0 self.restartMessage = '' self.runner = None if PLATFORM == 'win32': self.LIST_STYLE = wx.LC_SMALL_ICON# todo: verify this better |wx.LC_LIST else: self.LIST_STYLE = wx.LC_LIST def __findReplaceEvents__(self): self.findStr='' self.replaceStr='' self.findFlags=1 self.stcFindFlags=0 #This can't be done with the eventManager unfortunately ;-( wx.EVT_COMMAND_FIND(self,-1,self.onFind) wx.EVT_COMMAND_FIND_NEXT(self, -1,self.onFind) wx.EVT_COMMAND_FIND_REPLACE(self, -1,self.onReplace) wx.EVT_COMMAND_FIND_REPLACE_ALL(self, -1,self.onReplaceAll) wx.EVT_COMMAND_FIND_CLOSE(self, -1,self.onFindClose) #---finish def __finish__(self): self.__icons__() self.__sash__() self.__frame__() #self.app.childActive.source.SetFocus() def __icons__(self): self.iconsList=wx.ImageList(16,16) self.icons={} self.iconsListIndex={} iconFiles=sm.osx.listdir(self.pathImages,extensions=['.png']) iconFiles.sort() for icon in iconFiles: self.icons[icon]=self.app.bitmap(icon) if self.icons[icon].GetHeight() == 16: self.iconsListIndex[icon]=self.iconsList.Add(self.icons[icon]) def __sash__(self): if self.app.DEBUG: print 'Creating tabs...' self.config = self.app.config self.AssignImageList(self.iconsList) tabs = [os.path.splitext(x)[0] for x in sm.osx.listdir(self.pathTabs,extensions=['.py']) if x[:1]!='_'] tabs.sort() tabs = TABS[:-1] + [x for x in tabs if x not in TABS] + [TABS[-1]] if not self.app.Blender: tabs.remove('Blender') self.tabPanel = {} for tab in tabs: if self.app.DEBUG: print '\t',tab __import__('_spe.tabs.'+tab) page = self.__dict__[tab.lower()] = eval('_spe.tabs.%s.Panel'%tab)(self) if info.DARWIN and tab!='Shell': text = '' else: text = tab self.AddPage(page=page,text=text,imageId=self.iconsListIndex[tab.lower()+'.png']) self.tabPanel[tab] = page self.tabs = tabs if self.get('version')!=INFO['version']: self.SetSelection(self.GetPageCount()-1) self.set('version',INFO['version']) eventManager.Register(self.onTab,wx.EVT_NOTEBOOK_PAGE_CHANGED,self) if self.getValue('Redraw') < 10: self.set('Redraw',self.getValue('Redraw')*1000) self.__timer__() def __frame__(self): #parent frame frame = self.frame frame.SetDropTarget(Child.DropOpen(self.openList)) icon = wx.Icon(os.path.join(self.pathImages,'favicon.ico'),wx.BITMAP_TYPE_ICO) frame.SetIcon(icon) if hasattr(frame,'panelFrame'): frame.panelFrame.SetIcon(icon) #constructors self.preferencesSave() self.__remember__(openFiles=self._openFiles) self.__menus__() def __menus__(self): #parentInit.importMenus menuBar = self.frame.menuBar if self.app.mdi: #d#self.frame.menuBar.parentPanel = self menuBar.check_sidebar() menuBar.check_view() if not self.app.children: menuBar.enable(0) def __remember__(self,openFiles=[]): self.__openWorkspace__() #this prepares the currentworkspace to be used try: self.get("currentworkspace") #This will fail if there is no current workspace to get except: pass # Open default workspace? self.loadWorkspace() if len(openFiles)>0: self.rememberSet(1) self.openList(openFiles) if len(self.app.children)==0: self.new(maximize = self.getValue("MaxChildren")) #---Workspace def _createNewDefaultWorkspace(self): #if not os.path.exists(self.workspace['file']): file=os.path.join(INFO['userPath'],'defaults.sws') if not os.path.isfile(file): new_cf=ConfigParser.ConfigParser() # Recent new_cf.add_section("recent") try: new_cf.set("recent","1",self.userOpen(RECENT)) except: new_cf.set("recent","1","") # Folders new_cf.add_section("folders") try: new_cf.set("folders","1",self.userOpen(FOLDERS)) except: new_cf.set("folders","1","") # Notes new_cf.add_section("notes") try: new_cf.set("notes","1",self.userOpen(NOTES)) except: new_cf.set("notes","1","") # OpenFiles new_cf.add_section("openfiles") try: new_cf.set("openfiles","1",self.userOpen(REMEMBER)) except: new_cf.set("openfiles","1","") f=open(file,"w") new_cf.write(f) f.close() return file def __openWorkspace__(self): #read the default workspace for the 'global' items file=INFO['defaultWorkspace'] if not os.path.isfile(file): self._createNewDefaultWorkspace() self.workspace['defaultconfig']=ConfigParser.ConfigParser() self.workspace['defaultconfig'].read(file) #read the specific workspace for the 'local' items #this can be blocked in two ways: # 1 self.getValue('RememberLastWorkspace') is False # 2 incorrect workspace files self.workspace['config']=ConfigParser.ConfigParser() if self.getValue('RememberLastWorkspace'): try: file = self.get("currentworkspace") if not os.path.exists(file): file = '' except: file = '' try: self.workspace['config'].read(file) self.workspace['file']=file except: file = '' else: file = '' if file is '': self.workspace['config']=self.workspace['defaultconfig'] self.workspace['file']=INFO['defaultWorkspace'] self.workspace['openfiles']=[] if self.getValue('RememberLastWorkspace'): #open the workspace files in SPE try: openFiles=eval(self.getWorkspaceValue("OpenFiles")) for i in openFiles: self.workspace['openfiles'].append(i[0]) except Exception,e: if self.app.DEBUG: self.SetStatusText("Error opening workspace file %s: %s"%(file,e)) else: self.setWorkspaceValue("openfiles",str([])) def applyWorkspaceTab(self,child): """ this function will change the child tab to indicate that it is part of the workspace """ self.name = os.path.basename(child.fileName) if not (self.frame.dead or child.frame.dead): try: child.frame.setTitle(self.name,colour=wx.WHITE) except Exception, e: print e def loadWorkspace(self): try: if self.getValue('CloseChildrenOnNewWorkspace'): #Close all open children for child in self.app.children: #this doesn't loop through all the children (leaves one left) child.frame.onFrameClose() except: pass #load the Recent Files self.recent.files=[] default=False if self.getValue('globalRecent'): default=True try: files=eval(self.getWorkspaceValue("Recent",default)) self.recent.add([file for file in files if file and os.path.exists(file)]) except: pass #load the Folders default=False if self.getValue('globalFolders'): default=True try: folders=eval(self.getWorkspaceValue("Folders",default)) self.browser.depth.SetValue(folders[0]) self.browser.add([file for file in folders[1:] if file]) except: pass #load the Notes default=False if self.getValue('globalNotes'): default=True try: notes=self.getWorkspaceValue("Notes",default) self.notes.SetValue(notes) except: pass #load the openfiles (the old 'remember.txt') fileList=[] default=False if self.getValue('globalFileList'): default=True try: files=eval(self.getWorkspaceValue("OpenFiles",default)) fileList=[file for file in files if file] except: pass if fileList: self.rememberSet(1) self.openList(fileList, message = 0, select = None, maximize = self.getValue("MaxChildren"), verbose = True) self.setWorkspaceStatusBarText(self.workspace['file']) def setWorkspaceStatusBarText(self,file): self.SetActiveStatusText(os.path.basename(file)[:-4],STATUS_TEXT_WORKSPACE_POS) def emptyWorkspace(self): return { 'config' : ConfigParser.ConfigParser() , 'file' : "" , 'openfiles' : [], 'defaultconfig' : ConfigParser.ConfigParser() } def saveWorkspace(self,filelocation=None): if filelocation is '': return if self.app.children: childActive = self.app.childActive fileList=[] if self.app.children: self.workspace['openfiles']=[] for child in self.app.children: if child.fileName != Child.NEWFILE: pos = child.source.GetCurrentPos() lineno = child.source.LineFromPosition(pos) col = child.source.GetColumn(pos) fileList.append((child.fileName,lineno,col)) self.workspace['openfiles'].append(child.fileName) self.applyWorkspaceTab(child) self.setWorkspaceValue("notes",self.notes.GetValue()) self.setWorkspaceValue("openfiles",str(fileList)) self.setWorkspaceValue("recent",str(self.recent.files[:self.getValue('RecentFileAmount')])) self.setWorkspaceValue("folders",str([self.browser.depth.GetValue()]+self.browser.getFolders()[1:])) if not filelocation: filelocation=self.workspace['file'] try: file=open(filelocation,'w') self.workspace['config'].write(file) file.close() self.workspace['file']=filelocation self.setWorkspaceStatusBarText(filelocation) except Exception, message: print 'Spe warning: could not save workspace options in',filelocation print message self.applyWorkspaceTab(childActive) def getWorkspaceValue(self,type,default=False): """ returns the value of the workspace config file key """ if default: return self.workspace['defaultconfig'].get(type.lower(),"1") else: return self.workspace['config'].get(type.lower(),"1") def setWorkspaceValue(self,type,value): """ sets the workspace config file key to a specific value """ if not self.workspace['config'].has_section(type): self.workspace['config'].add_section(type) self.workspace['config'].set(type.lower(),"1",value) ####Menu #---File def new(self,name=UNNAMED,source='',maximize=None): """Create a new empty script window.?""" app = self.app child = app.ChildFrame(self.frame, page = os.path.basename(name), extra = name, fileName = name, source = source, size = app.size, maximize = maximize) self.frame.menuBar.enable(1) return child.panel def open(self, event=None): """Open file(s) dialog.""" try: defaultDir = info.dirname(self.app.childActive.fileName) except: defaultDir = '' dlg = wx.FileDialog(self, "Choose a file - www.stani.be", defaultDir=defaultDir, defaultFile="", wildcard=info.WILDCARD, style=wx.OPEN|wx.MULTIPLE) if dlg.ShowModal() == wx.ID_OK: fileList = dlg.GetPaths() if fileList and self.app.children: child = self.app.childActive if child and child.fileName==Child.NEWFILE and not child.changed: child.frame.onFrameClose() self.openList(fileList) dlg.Destroy() def open_workspace(self): """Open file dialog.""" try: defaultDir=info.dirname(self.workspace['file']) except: defaultDir='' dlg = wx.FileDialog(self, "Choose a file - www.stani.be", defaultDir=defaultDir, defaultFile="", wildcard=info.WORKSPACE_WILDCARD, style=wx.OPEN) if dlg.ShowModal() == wx.ID_OK: file = dlg.GetPath() try: self.set("currentworkspace",file) self.__openWorkspace__() self.loadWorkspace() except Exception,e: self.message("Could not open workspace:%s\n%s"%(file,e)) dlg.Destroy() def save_workspace(self): """Save file dialog.""" try: self.saveWorkspace() except Exception,e: self.message("Could not save workspace:%s\n%s"%(file,e)) def save_workspace_as(self): """Save file dialog.""" try: defaultFile = self.workspace['file'] except: defaultFile = '' if info.WIN: defaultFile = defaultFile.replace("/","\\") dlg = wx.FileDialog(self, "Save Workspace As - www.stani.be", defaultFile = defaultFile, defaultDir = info.dirname(defaultFile), wildcard = info.WORKSPACE_WILDCARD, style = wx.SAVE|wx.OVERWRITE_PROMPT|wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: file = dlg.GetPath() try: self.set("currentworkspace",file) self.saveWorkspace(file) except Exception,e: self.message("Could not save workspace:%s\n%s"%(file,e)) dlg.Destroy() def save(self): if self.getValue('SaveWorkspaceOnFileSave'): self.saveWorkspace() #---Edit def browse_source(self, event=None): """Locate source file of word and open it.""" if self.app.children: fileName=self.app.childActive.source.getWordFileName(whole=1) if fileName and fileName[0]!='"': self.openList(fileName) else: if not fileName: fileName='' self.SetActiveStatusText('Sorry, can not locate file %s'%fileName) def find_replace(self, event=None): """Find and Replace dialog and action.""" if self.app.children: #find string findStr = self.app.childActive.source.GetSelectedText() if findStr and self.findDialog: self.findDialog.Destroy() self.findDialog = None #dialog already open, if yes give focus if self.findDialog: self.findDialog.Show(1) self.findDialog.Raise() return if not findStr: findStr = self.findStr self.numberMessages=0 #find data data = wx.FindReplaceData(self.findFlags) data.SetFindString(findStr) data.SetReplaceString(self.replaceStr) #dialog self.findDialog = wx.FindReplaceDialog(self, data, "Find & Replace", wx.FR_REPLACEDIALOG|wx.FR_NOUPDOWN) x, y = self.frame.GetPosition() self.findDialog.SetPosition((x+5,y+200)) self.findDialog.Show(1) self.findDialog.Raise() self.findDialog.data = data # save a reference to it... def execute(self): """Execute""" if self.app.children: child = self.app.childActive source = child.source code = source.GetSelectedText() if not code.strip(): if self.getValue('ExecuteWarning') and not self.messageConfirm('As there is no code selected,\nSPE will run the whole script.\n\nAre sure you want to continue?'): return if self.getValue('SaveBeforeRun') and not child.confirmSave(): return child.setStatus('As there is no code selected, SPE will run the whole script.') code = source.GetText() self.shell.Execute(code) #thread.start_new_thread(self.shell.Execute,(code,)) def preferences(self): """Show preferences dialog box.""" from dialogs import preferencesDialog prefs=preferencesDialog.Create(self,-1,'') prefs.ShowModal() #---Blender def add_spe_to_blender(self): """Adds SPE and Winpdb shortcuts to Blender menu""" from distutils.file_util import copy_file import Blender #important local variables # srcdir = info.PATH #_spe directory dstdir = Blender.Get('uscriptsdir') #preferred Blender script directory (can be '') altdir = Blender.Get('scriptsdir') #the other Blender script directory #'uscriptsdir' can be empty - in such case use 'scriptsdir': if not dstdir: dstdir, altdir = altdir, None # #2. Main operation: try to update the *.py file at dstdir, # optionally remove eventual old location from altdir: # cpyresult = rmresult = mresult = "" #helpers for message fromatting for fname in (BLENDER_SHORTCUT_SPE,BLENDER_SHORTCUT_WINPDB): src = os.path.join(srcdir,fname) result = copy_file(src, os.path.join(dstdir,fname),update=1) if result[1]: #copied! cpyresult += ", " + fname #if suceeded: add fname to the message # #if we have copied fname with success - there should not be # two fname scripts (one for every Blender scripts directory): # try to remove the unwanted one from the altdir (Blender 'scriptsdir') # if altdir and os.access(altdir,os.W_OK): try: #let's try to remove it from unused dir: os.remove(os.path.join(altdir, fname)) rmresult += ", " + fname #OK, succeed: add fname to the message except: pass #just continue - it is not a big problem # #3. Update Blender: # Blender.UpdateMenus() # #4. Final message to the user: # #([2:] is used in strings to discard leading ", "): msg = "Blender menu updated.\n\n" if cpyresult: msg+= "Copied %s to %s.\n\n" % (cpyresult[2:], dstdir) if rmresult: msg+= "Removed %s from %s. " % (rmresult[2:], altdir) self.message(msg) #self.SetStatusText(msg,1) #---View def whitespace(self,event): """Toggle visibility white space.""" for child in self.app.children: child.source.SetViewWhiteSpace(event.IsChecked()) self.set('ViewWhiteSpace',event.IsChecked()) def linenumbers(self,event): """Toggle visibility line numbers.""" for child in self.app.children: if event.IsChecked(): child.source.SetMarginWidth(1, 50) else: child.source.SetMarginWidth(1, 0) self.set('ViewLineNumbers',event.IsChecked()) def indentation_guides(self,event): """Toggle visibility indentation guides.""" for child in self.app.children: child.source.SetIndentationGuides(event.IsChecked()) self.set('IndentationGuides',event.IsChecked()) def right_edge_indicator(self,event): """Toggle visibility right edge indicator.""" for child in self.app.children: child.source.SetViewEdge(event.IsChecked()) self.set('ViewEdge',event.IsChecked()) def end_of_line_marker(self,event): """Toggle visibility end of line marker.""" for child in self.app.children: child.source.SetViewEOL(event.IsChecked()) self.set('ViewEol',event.IsChecked()) def as_notebook(self,event): if hasattr(self.frame,'Tile'): if self.app.children: self.app.childActive.frame.Maximize() else: tabs = getattr(self.frame,'tabs',None) if tabs: tabs.Tile(False) def as_columns(self,event): if hasattr(self.frame,'Tile'): self.frame.Tile(wx.VERTICAL) else: tabs = getattr(self.frame,'tabs',None) if tabs: tabs.Tile(True, wx.VERTICAL) def as_rows(self,event): if hasattr(self.frame,'Tile'): self.frame.Maximize(wx.HORIZONTAL) else: tabs = getattr(self.frame,'tabs',None) if tabs: tabs.Tile(True, wx.HORIZONTAL) def toggle_shell(self): """Show/hide shell""" frame = self.frame if hasattr(frame,'sash'): height = frame.sash.GetSize()[1] if height<10: hidden = 1 else: hidden = 0 elif hasattr(frame,'panelFrame'): hidden = not frame.panelFrame.IsShown() elif hasattr(frame,'split'): hidden = not frame.split.IsSplit() else: return False self.showShell(hidden,save=True) return hidden def showShell(self,show,save=False): if save: self.set('ShowShell',show) frame = self.frame if hasattr(frame,'sash'): if show: frame.sash.SetDefaultSize(wx.Size(1000,200)) else: frame.sash.SetDefaultSize(wx.Size(1000,1)) wx.LayoutAlgorithm().LayoutMDIFrame(frame) elif hasattr(frame,'panelFrame'): frame.panelFrame.Show(show) frame.panelFrame.Activate() elif hasattr(frame,'split'): if show: frame.split.SplitHorizontally(frame.tabs, self, -200) else: frame.split.Unsplit() ## def showToolbar(self,show,save=False): ## if save: self.set('ShowToolbar',show) ## frame = self.frame ## if hasattr(frame,'toolBar'): ## if show: ## frame.sash.SetDefaultSize(wx.Size(1000,200)) ## else: ## frame.sash.SetDefaultSize(wx.Size(1000,1)) ## wx.LayoutAlgorithm().LayoutMDIFrame(frame) #---Tools def browse_folder(self): """Browse folder""" if self.app.children: child = self.app.childActive if hasattr(child,'fileName'): path = info.dirname(child.fileName) if not os.path.exists(path): path = os.getcwd() else: path = os.getcwd() if os.path.exists(THUNAR): os.system('%s "%s" &'%(THUNAR,path)) elif os.path.exists(NAUTILUS): os.system('%s "%s" &'%(NAUTILUS,path)) elif os.path.exists(DOLPHIN): os.system('%s "%s" &'%(DOLPHIN,path)) elif os.path.exists(KONQUEROR): os.system('%s "%s" &'%(KONQUEROR,path)) elif os.path.exists(PCMANFM): os.system('%s "%s" &'%(PCMANFM,path)) else: if path[0] == '/': path = 'file://'+path webbrowser.open(path) def run(self): if self.output.IsBusy(): if self.messageConfirm('SPE will try to kill the running script.\n\nWarning:this might kill SPE as well.\nIt is highly recommended to save all scripts first.\n\nAre you sure you want to continue?'): self.output.Kill() else: self.output._check_run(False) return if self.app.children: child = self.app.childActive if not child.confirmSave(): self.output._check_run(False) return if child.isNew(): self.output._check_run(False) return from _spe.dialogs.runDialog import RunDialog runDialog = RunDialog(child.fileName, self.argumentsPrevious, self.beepPrevious, parent=self.frame, id=-1) answer = runDialog.ShowModal() arguments = runDialog.arguments.GetValue() beep = runDialog.beep.GetValue() runDialog.Destroy() if answer == wx.ID_OK: if not (arguments in self.argumentsPrevious): self.argumentsPrevious.insert(0,arguments) self.beepPrevious = beep self.run_with_arguments(arguments,beep=beep,confirm=False) else: self.output._check_run(False) def run_with_arguments(self,arguments='',beep=True,confirm=True): if self.output.IsBusy(): self.output.Kill() return if self.app.children: child = self.app.childActive if confirm and not child.confirmSave(): return if child.isNew(): return # todo: input stuff from preferences dialog box! path, fileName = os.path.split(child.fileName) params = { 'file': info.path(child.fileName), 'path': path, 'arguments': arguments, 'python': info.PYTHON_EXEC} #label = params['label'] = '"%(file)s" %(arguments)s'%params label = params['label'] = '%(file)s %(arguments)s'%params os.chdir(path) self.output.Execute("""%(python)s -u %(label)s"""%params,label=label,beep=beep) def run_debug(self): """Run file""" if not self.runner: try: from _spe.plugins.spe_winpdb import Runner except ImportError: self.messageError('You need to install\n' 'winpdb for this feature.') return self.runner = Runner(self.app) self.runner.switch() def import_(self): """Import""" if self.app.children: child = self.app.childActive if not self.getValue('SaveBeforeRun') or child.confirmSave(): if child.isNew(): return self.busyShow() name = child.fileName self.shell.write('Importing "%s" ...'%name) self.shell.waiting = 1 sm.scriptutils.importMod(name,mainDict=self.shell.locals) self.shell.waiting = 0 self.shell.prompt() if self.redraw: self.redraw() self.activateShell() self.busyHide() def debug(self): child = self.app.childActive if not child.confirmSave(): return if child.isNew(): return if not self.runner: try: from _spe.plugins.spe_winpdb import Runner except ImportError: self.messageError('You need to install\n' 'winpdb for this feature.') return self.runner = Runner(self.app) self.runner.debug() def browse_object_with_pyfilling(self): """Browse object with pyfilling""" from wx.py.filling import FillingFrame name=self.messageEntry('Enter object:') try: object=self.shell.interp.locals[name] except: self.SetActiveStatusText('%s is not defined'%name,1) return filling=FillingFrame(parent=self, id=-1, title='PyFilling', pos=wx.DefaultPosition, size=wx.Size(600,300), style=wx.DEFAULT_FRAME_STYLE, rootObject=object, rootLabel=str(object), rootIsNamespace=0, static=0) filling.Show(1) wx.FutureCall(1000,filling.Raise) def test_regular_expression_with_kiki(self): """Test regular expression with Kiki...""" try: self.kiki.Raise() except: try: from kiki import kiki except ImportError: from plugins.kiki import kiki INFO['kikiPath']=info.dirname(kiki.__file__) self.kiki=kiki.speCreate(self,info=INFO) self.SetStatusText('Kiki is succesfully started.',1) def design_a_gui_with_wxglade(self): try: import subprocess glade = subprocess.Popen(['which','wxglade'], stdout=subprocess.PIPE).stdout.read().strip() os.spawnl(os.P_NOWAIT,glade,glade) return except: pass try: from wxglade import __file__ as fileName except ImportError: from plugins.wxGlade import __file__ as fileName except: self.messageError('You need to install\n' 'wxglade (python-wxglade)\n' 'for this feature.') return path = info.dirname(fileName) glade = '%s'%os.path.join(path,'wxglade.py') if info.WIN and ' ' in glade: glade = '"%s"'%glade os.spawnl(os.P_NOWAIT,info.PYTHON_EXEC,info.PYTHON_EXEC,glade) self.SetStatusText('wxGlade is succesfully started.',1) def design_a_gui_with_xrc(self): try: from wx.tools.XRCed import xrced except ImportError: from plugins.XRCed import xrced except: self.messageError('You need to install\n' 'the wxpython tools (python-wxtools)\n' 'for this feature.') return import plugins path = os.path.dirname(plugins.__file__) xrced = '%s'%os.path.join(path,'spe_xrced.py') if info.WIN and ' ' in xrced: xrced = '"%s"'%xrced os.spawnl(os.P_NOWAIT,info.PYTHON_EXEC,info.PYTHON_EXEC,xrced) self.SetStatusText('XRC editor is succesfully started.',1) #---Links def contact_author(self): WebBrowser=self.get('WebBrowser') if WebBrowser==DEFAULT: webbrowser.open(MAIL) else: os.system("%s '%s'"%(WebBrowser,MAIL)) #---Help def keyboard_shortcuts(self): from dialogs import helpShortcutsDialog helpShortcutsDialog.create(self,path=self.path).Show(1) def python_help(self,what): pythonDocs = self.get('PythonDocs') wwwHelp = HELP_WWW%(what,what) if pythonDocs==DEFAULT: if sys.platform=='win32': helpActivePython=os.path.join(PREFIX,"Doc","ActivePython.chm") helpEntoughtPython=os.path.join(PREFIX,"Enthought","Doc","enthought_python.chm") if os.path.exists(helpActivePython): self.messageHtml(helpActivePython) elif os.path.exists(helpEntoughtPython): self.messageHtml(helpEntoughtPython) else: library=os.path.join(PREFIX,"Doc",what,"index.html") if os.path.exists(library): self.messageHtml(library) else: self.messageHtml(wwwHelp) self.SetStatusText(HELP_SORRY%library,1) else: linux1=''.join([PREFIX, "/share/doc/python", str(sys.version_info[0]), ".", str(sys.version_info[1]), "/html/%s/index.html"%what]) linux2=''.join([PREFIX, "/share/doc/python-docs-", str(sys.version_info[0]), ".", str(sys.version_info[1]), ".", str(sys.version_info[2]), "/html/%s/index.html"%what]) if os.path.exists(linux1):self.messageHtml(linux1) elif os.path.exists(linux2):self.messageHtml(linux2) else: self.messageHtml(wwwHelp) self.SetStatusText(HELP_SORRY%linux1,1) else: # TODO: pythondocs laten loopen over alle mogelijkheden, dit iets eleganter. helpActivePython=os.path.join(pythonDocs,"Doc","ActivePython.chm") if sys.platform=='win32' and os.path.exists(helpActivePython): library = helpActivePython else: library = os.path.join(pythonDocs,what,"index.html") if os.path.exists(library): self.messageHtml(library) else: self.messageHtml(wwwHelp) self.SetStatusText(HELP_SORRY%library,1) def python_documentation_server(self): from pydoc import __file__ as fileName os.spawnl(os.P_NOWAIT,info.PYTHON_EXEC,info.PYTHON_EXEC,fileName,'-g') self.messageHtml('http://localhost:7464/') def wxwindows_documentation(self): WxPythonDocs=self.get('WxPythonDocs') if WxPythonDocs==DEFAULT: WxPythonDocs = os.path.join(info.dirname(wx.__file__),'docs') WxPythonDocs2 = os.path.join(info.dirname(WxPythonDocs),'docs') WxPythonDocs3 = 'C:\\Program Files\\wxPython2.8 Docs and Demos\\docs' path = None for dir in [WxPythonDocs,WxPythonDocs2,WxPythonDocs3]: for docs in ['wx.chm','wxPythonDocs.html','wxPythonManual.html']: if not path: p = os.path.join(dir,docs) if os.path.exists(p): path = p if path: self.messageHtml(path) elif os.path.exists(os.path.join(WxPythonDocs2,"wxDocsViewer.app")): os.spawnl(os.P_NOWAIT,info.PYTHON_EXEC,info.PYTHON_EXEC, os.path.join(WxPythonDocs,"wxDocsViewer.app/Contents/Resources/viewdocs.py")) else: self.SetActiveStatusText('wxPython documentation could not be found. Check the path in the preferences dialog.') def about(self): from dialogs import helpDialog helpDialog.create(self,self.path,'about.htm', replacements=INFO) #---Backstage def openList(self,fileList,lineno=None,col=1,message=1,select='line',\ maximize=None, verbose=False): """Open a list of files.""" if type(fileList)!=types.ListType: fileList=[fileList] child = None for fileName in fileList: if type(fileName)==types.TupleType: fileName, lineno, col = fileName if not os.path.exists(fileName): continue if self.app.DEBUG: print 'Opening %s'%fileName child=self.getChildByFileName(fileName) if child: #opened already child.frame.Raise() if lineno:child.scrollTo(lineno,col,select=select) else:self.SetStatusText("'%s' is already open"%fileName,1) else: #not opened yet try: source=open(fileName).read() except: source='' # todo: make this an option child=self.new(name=fileName,source=source,maximize=maximize) #if this file is in the workspace, then change the name self.recent.add([fileName]) if lineno:child.scrollTo(lineno,col,select=select) ## if child.fileName in self.workspace['openfiles']: ## #this is a workspace file and should ## self.applyWorkspaceTab(child) lineno=None col=1 if len(self.app.children)>0:self.frame.menuBar.enable(1) return child def runFile(self,fileName,source=None,separate=0,profiling=0): """ separate: run in seperate namespace to avoid conflicts with the spe namespace """ self.shell.write("Running '%s' ..."%fileName) #self.busyShow() self.shell.waiting = 1 self.shell.interp.push('import sm.scriptutils') if separate: nameSpace = 'namespace["%s"]'%fileName self.shell.interp.push('%s={"__fileName__":"%s"}'%(nameSpace,fileName)) else: nameSpace = 'locals()' try: runCommand = 'sm.scriptutils.run(fileName=r"%s",source=%s,mainDict=%s,profiling=%s)'\ %(fileName,source,nameSpace,profiling) self.shell.interp.push(runCommand) except Exception,message: print '\n(Spe internal warning: %s!)'%message self.shell.prompt() if self.redraw:self.redraw() self.activateShell() #self.busyHide() def activateShell(self): if self.app.mdi: self.showShell(True,save=True) else: self.frame.Raise() self.SetSelection(0) ####Events #---smdi events def onActivate(self,event): """Check and update, if files are changed when parent frame is activated.""" if self.app.DEBUG: print 'Event: Parent: %s.onActivate'%self.__class__ if not self.timer.IsRunning(): #self.Bind(wx.EVT_IDLE,self.onIdle) self.Bind(wx.EVT_TIMER,self.onTimer) self.timer.Start(self.getValue('Redraw')) reloaded=[] try: for child in self.app.children: if child.checkTime(): reloaded.append(os.path.basename(child.fileName)) if reloaded: self.SetStatusText('Reloaded %s'%','.join(reloaded),1) if event: event.Skip() except Exception,m: if self.app.DEBUG: print 'Warning: Parent: %s.onActivate failed\n%s\n%s\n'%(self.__class__,Exception,m) def onDeactivate(self,event=None): if self.app.children: childActive = self.app.childActive if (not self.frame.dead) and childActive and hasattr(childActive,'source'): childActive.source.AutoCompCancel() childActive.source.CallTipCancel() self.timer.Stop() self.Unbind(wx.EVT_TIMER) ## wait = self.getValue('Redraw')/1000.0 ## while self.onTimer(None,end=True): ## time.sleep(wait) def onClose(self,event=None): """Called when the parent frame is closed.""" if self.app.DEBUG: print 'Event: Parent: %s.onClose'%self.__class__ for child in self.app.children: if not child.confirmSave(): child.Raise() child.SetStatusText('Please save this file before quitting SPE.') return False eventManager.DeregisterWindow(self) self.timer.Stop() self.frame.dead = 1 #if (not self.app.DEBUG) and self.getValue('RedirectShell'): self.redirect(0) if self.remember and self.app.children: active=self.app.childActive if self.app.mdi and active: self.set('MaxChildren',active.frame.IsMaximized()) #save the window size mainWindow=self.app.GetTopWindow() selfSize=mainWindow.GetRect() if not mainWindow.IsMaximized(): self.set("sizex",selfSize.GetSize().x) if info.DARWIN and wx.VERSION_STRING>'2.8': self.set("sizey",selfSize.GetSize().y-47) #dirty hack else: self.set("sizey",selfSize.GetSize().y) self.set("posx",selfSize.GetPosition().x) self.set("posy",selfSize.GetPosition().y) self.set("maximize","False") else: self.set("maximize","True") try: if self.getValue('SaveOnExit'): self.saveWorkspace() if self.remember: self.saveWorkspace(INFO['defaultWorkspace']) except Exception, message: self.messageEmail("""\ Spe Warning: can't save user settings (%s). Please report these details and operating system to %s."""%(message,INFO['author_email'])) if not self.getValue('RememberLastWorkspace'): self.set('currentworkspace',"") return 1 def onClosePanelFrame(self,event=None): self.showShell(show=False,save=True) self.frame.menuBar.check_view() def onTimer(self,event=None,end=False): if self.app.IsActive(): #child if self.app.children: child = self.app.childActive if not self.lock.locked(): child.idle(None,end) #redraw if self.redraw: self.redraw() else: self.onDeactivate() def onMove(self,event=None): """Called when the parent frame is moved.""" if self.app.DEBUG: print 'Event: Parent: %s.onMove'%self.__class__ if self.redraw:self.redraw() def onSize(self,event=None): """Called when the parent frame is resized.""" if self.app.DEBUG: print 'Event: Parent: %s.onSize'%self.__class__ if self.redraw:self.redraw() #---extra def onArgs(self,*args,**keyw): self.openList(*args,**keyw) self.shell.prompt() def excepthook(self, type, value, traceback) : webbrowser.open('''mailto:%s?subject=SPE %s error report&body="%s %s\n%s"'''%(INFO['author_email'],type,type,value,traceback)) def onFind(self,event,message=1): if self.app.children: source=self.app.childActive.source try: self.findStr=event.GetFindString() self.findFlags=event.GetFlags() flags=0 if wx.FR_WHOLEWORD & self.findFlags: flags|=wx.stc.STC_FIND_WHOLEWORD if wx.FR_MATCHCASE & self.findFlags: flags|=wx.stc.STC_FIND_MATCHCASE self.stcFindFlags=flags except: pass current=source.GetCurrentPos() position=source.FindText(current,len(source.GetText()),self.findStr, self.stcFindFlags) if position==-1:#wrap around self.wrapped=1 position=source.FindText(0,current+len(self.findStr),self.findStr,self.stcFindFlags) self.SetActiveStatusText("Wrapped around to find '%s'"%self.findStr,1) if position==-1 and message and self.numberMessages<1: #not found self.numberMessages=1 self.message("'%s' not found!"%self.findStr) self.numberMessages=0 else: #found line = source.LineFromPosition(position) source.EnsureVisible(line) source.GotoPos(position) source.SetSelection(position,position+len(self.findStr)) return position def onFindClose(self,event): event.GetDialog().Destroy() self.numberMessages=0 def onReplace(self,event,message=1): if self.app.children: ## Next line avoid infinite loop findStr=event.GetFindString() self.replaceStr=event.GetReplaceString() if findStr==self.replaceStr: return -1 source=self.app.childActive.source selection=source.GetSelectedText() if not(event.GetFlags() & wx.FR_WHOLEWORD): findStr=findStr.lower() selection=selection.lower() if findStr==self.replaceStr.lower(): return -1 if selection==findStr: position=source.GetSelectionStart() source.ReplaceSelection(self.replaceStr) source.SetSelection(position,position+len(self.replaceStr)) position=self.onFind(event,message=message) return position def onReplaceAll(self,event): if self.app.children: source=self.app.childActive.source count=0 self.wrapped=0 position=start=source.GetCurrentPos() while position>-1 and ((not self.wrapped) or position': if self.app.children: return self.app.childActive else: return None fileName = os.path.normcase(fileName) for child in self.app.children: if os.path.normcase(child.fileName)==fileName: return child return None def getFileNames(self): return [child.fileName for child in self.app.children] def getText(self): """Get raw text of current script window.""" if self.app.children: return self.app.childActive.source.GetText() else: return '' #---messages def message(self,message,style=wx.OK | wx.ICON_INFORMATION): """Show a message with Ok button. (style offers other options)""" dlg = wx.MessageDialog(self, message, self.app.title, style) answer = dlg.ShowModal() dlg.Destroy() return answer def messageConfirm(self,message): """Show a confirm message (yes,no)""" answer=self.message(message,style=wx.YES_NO|wx.ICON_QUESTION) return self.messageIsOk(answer) def messageIsOk(self,answer): return answer==wx.ID_OK or answer==wx.ID_YES def messageCancel(self,message): """Show a yes,no or cancel message""" if self.app.DEBUG: print 'Dialog: Parent: %s.messageCancel'%self.__class__ return self.message(message,style=wx.YES_NO|wx.ICON_QUESTION | wx.CANCEL) def messageError(self,message): """Display error message.""" self.message(message,style=wx.OK | wx.ICON_ERROR) def messageEmail(self,message): try: webbrowser.open('mailto:%s?subject=SPE error (automatic report)&body=%s'%(INFO['author_email'],message)) except: pass def messageEntry(self,message,default=''): """Show entry dialog box for user input.""" dlg = wx.TextEntryDialog(self, message,self.app.title, default) if dlg.ShowModal() == wx.ID_OK:value=dlg.GetValue() else:value=None dlg.Destroy() return value def messageScrolled(self,message): """Show multiline scrollable message box.""" from dialogs import speDialog if sys.platform!='win32':message='%s'%message speDialog.create(self, message, self.path) def messageHtml(self,fileName,doc=None): """Launch html with webbrowser.""" if doc: fileName=os.path.join(doc,'doc',fileName) if fileName[0]=='/': fileName = 'file://'+fileName WebBrowser=self.get('WebBrowser') if WebBrowser==DEFAULT: if os.path.isfile(FIREFOX): os.system("%s %s &"%(FIREFOX,fileName)) else: webbrowser.open(fileName, 1) else: os.system("%s %s &"%(WebBrowser,fileName)) #---preferences def preferencesSave(self): self.preferencesUpdate() try: defaults=open(INFO['defaultsUser'],'w') self.config.write(defaults) defaults.close() except Exception, message: print 'Spe warning: could not save user options in',INFO['defaultsUser'] print message def preferencesUpdate(self): if self.frame.dead: return self.redirect((not self.app.DEBUG) and self.getValue('RedirectShell')) self.showShell(self.getValue('ShowShell')) self.frame.menuBar.check_view() if hasattr(self.frame,'tabs'): self.frame.tabs.EnableToolTip(self.getValue('ToolTipsForFileTabs')) for child in self.app.children: child.source.update() #dialogs.stcStyleEditor.SetStyles(self.tabPanel['Shell'], self.config) #restart?! restart = '' if self.app.mdiName != self.get('Mdi'): restart += '- switch between multiple and single document interface\n (%s>%s)\n'%(self.app.mdiName,self.get('Mdi')) if self.app.shortcuts != self.get('Shortcuts'): restart += '- to use other keyboad shortcuts\n (%s>%s)\n'%(self.app.shortcuts, self.get('Shortcuts')) #encoding encoding = self.get('Encoding').split(',')[0].split(' ')[0] if encoding!=self.defaultEncoding: self.defaultEncoding = encoding if encoding=='': wx.SetDefaultPyEncoding(INFO['encoding']) else: wx.SetDefaultPyEncoding(encoding) #restart if restart!=self.restartMessage: self.restartMessage = restart if restart: self.message('Please restart SPE to apply following changes:\n%s'%restart) def set(self,name,value,save=1): self.config.set('Default',name,str(value).replace('%(','%{').replace(')s','}s')) if save: self.preferencesSave() def get(self,name): return self.config.get('Default',name).replace('%{','%(').replace('}s',')s') def getValue(self,name): return eval(self.config.get('Default',name)) spe-0.8.4.h/_spe/spe.blend0000644000175000017500000046747410772036304014331 0ustar stanistaniBLENDER_v245REND $ɉ1GLOB $ɉ 0`5 SRx`SRscreenPйH5DATAPDATAзPDATAзDATAPзDATAPDATAиPDATAиDATAPиDATAPDATAPDATAйзDATA`йPDATA`PPDATA`DATA8PDATA8иDATAȻ8зDATAȻиDATAXȻPPDATAXPDATAXиDATA0DATA0xPDATAx0DATAxPиDATAPPdDATAw333?DdCIzաDDATA 0RenderRender@>DATA0@ AnimRender>DATA@P0FormatRender>DATAP`@Render LayersRender>DATA`pPBakeRender>0DATAp`ScriptlinksScript>DATApPreviewMaterial>DATALinks and PipelineMaterial4>DATAw333?DdCC@CCC(BDC??QDATAx}@ 333?- ɉ@KM9MDATA@x 333?zCAzCA-- A@FB= A DATA zH@333?@A` ` CA A@CC #<@DATAhHy 333?1Open Text File/home/stani/sync/python/blender/server/./oje dokumenty\Blender\Python.IDE\spe_blender_server.py ',DATAHDATAH?ZP@ JLmm X0@ DATAOutputRender>DATARender LayersRender>DATARenderRender@>DATAAnimRender>DATA BakeRender>DATA FormatRender>DATA0r 333?I<>J;\\!gU>~l3IY?[?27=/h?I\\}l<>!3IY?J;iU>[?8@n.@?6?A];?J;?qbkܾgUܾhU1@i[_4=ӾAhA%>yI9X>ê~X>3 Bɪgo.8 iA0JAW@?ZP@ JLI<>J;\\!gU>~l3IY?[?27=/h?j>|wy>݄B?AC?AHx B??-:=CxЄ= ???? DATAx }`0 333?  >NPPDATA` 333?~CC~CCP?CFC= ADATAw`333?DdCD^CC(BDC??PDATA$~333?DATAz333?@ff̌A+݈+݈A6 6 B0f A@CC #<@8DATA,8OBp=AHxDATA,8SCff5DATA(v@333?zC AzC A #< #<`jFzD OBDATAh@y333?1Open Text File/home/stani/sync/python/blender/server/./ishell.py  DATA???  @}`NNDATAOutputRender>DATARenderRender@>DATAAnimRender>DATAFormatRender>DATAx} 333?-  m;@suauDATA$~333?DATA(v`333?zC AzC A #< #<`jF@F OBDATA`wX333?DdCd9D]A:BCC(BDC??DATAXx8`333?zCAzCA-- A@FB= A DATA8z`X333?@A` ` CA A@CC #<@DATAh`y8333?3Open Text File/home/stani/sync/python/spe/trunk/_spe/./oje dokumenty\Blender\Python.IDE\spe.blendr_server.py %vDATAH?k??k  @0 __ DATA OutputRender>DATA  RenderRender@>DATA   AnimRender>DATA  FormatRender>DATAx0 }  333? =>@DATA$ ~( 0 333?DATA(( v 333?zC AzC A #< #<`jF@F OBDATAwx( 333?DdCd9D]A:BCC(BDC??DATAxxX333?zCAzCA-- A@FB= A DATAXzx333?@A` ` CA A@CC #<@DATA,OBHAHxDATAhyX333?1Open Text File/home/stani/sync/python/blender/server/./oje dokumenty\Blender\Python.IDE\spe_blender_server.py ',SRxp`SRscreen.002(-5DATAXDATAXDATAXDATADATAXDATAXDATAXDATADATAXxDATAXxDATAXxDATADATA`XDATA`DATA`DATA8XDATA8XDATA8XDATADATAXDATAXDATAXDATA0XDATA0xXXDATAx0XDATAxDATAPXDATAPDATAPDATADATA(X%d DATA w333?DdCIzաDo?uub d!%DATA!x"333?zCAzCAbb A@FB= A DATA"r%!333?????????8=i>o?fffAD&@??fffAHx B? #<C DATAh%y"333?AVE TARGA/t1.blend9DATAH'- X8=H>o?{{R d@(P,DATA@(x )333?zCAzCA1||1 A@FB= A DATA )rP,@(333?????????8=H>o?fffA*@??fffAHx B? #<C DATAhP,y )333?AVE TARGA/t1.blend9DATA-H'8=>o?{{Rd.h3DATA(.v80333?B̽̌?B̽̌?RR #< #<`jFzD SQB̽̌?DATA80rh3.333?????????8=>o?fffA@??fffAHx B? #<C DATAhh3y80333?OAD FILE/9SC5pSC1Hx90:9=x::dd?????< d@_4@2??H;H;????////render///#DP HDATA9c0:{DATA0:c9+HxDATA(x:b,d'=A@DATAL:mL?B ?o: ?? #<=DATAP--DATADATA@H;h1 RenderLayerCA;CACameraL>DB=B B@?TXhh<pyTXishell.py=a888XDATA4=/home/stani/sync/python/blender/server/ishell.pyREEDATA8hIDATA88C3DATAؓmenuDATA89DATAP( DATAxHvDATAx8FDATAxpFDATA0CDATA`%ce(sDATAX+' 'DATA`=pA.argDATA`=>=>@0000DATA>?`=>@??DATA?@>?X@.ADATA@`A?A0ADATA`AB@ABCDATABC`ABPCDDATACpDBD@DCDATApDDC  DATADEpDEHEDATAEFDE0F*DATAFpGEF G!DATApGHFGG8GDATAHIpG`HHDATAIIHHII%p3DATAIKI@JJ6IDATAKXKI DATAXKPLKKK%DATAPLPMXKLL+DATAPMMPLMMDATAMOPM@NN7DATAO0PMXOO;DATA0PPOxPPDATAPQ0P0QQ&DATAQRP(RR4DATARTQ@SS4RDATAT(URXTT6DATA(UPVTpUU?DATAPVW(UVVDATAW@XPVPWWEDATA@XXYWXX: undDATAXYZ@XYYpDATAZ[XYHZZ/RRANDATA[[ZP[[pDATA[\[[P\&ograDATA\P][\ ]DATAP]x^\]^>DATAx^_P]^8_EDATA_`x^_h`@codeDATA`a_ aPa8DATAab`a8b?lf, DATAbcabXc:singDATAchdbd8dDATAhdecd eCFREEDATAefhdeXfFalliDATAfgeggA0DATAghf@hph(WDATAhigh8iDATAi0jhijp3DATA0jkixjjturnDATAkk0jPkkFREEDATAklkkplJ DATAl0nk0mmLis tDATA0nHolxnn8:>DATAHoo0nooDATAo(qHo8ppH`DATA(q(ropqq+nd',DATA(rr(qprr,DATArt(rssD0DATAt@urPttGHDATA@uxvtuvFDATAxvw@uv0wADATAwxxvw@x%DATAx wxȼ)DATA (xhȽ1DATA( 8ypDATA(H)yDATAP9DATA`.DATAx@DATAxp(DATApx :DATA@pDATA@DATA@`$DATAX)DATAP+DATAPDATA@DATAx #DATAx0DATA0xx DATA0@DATA@DATA@DATA@` DATAL# Save this file as (ipython) ishell.py and run it externally of Blender.DATAD8# Press Alt-A in the Blender 3D View to run the SPE Blender server.DATADATA<8# SPE - Stani's Python Editor - http://pythonide.stani.beDATA$P# Copyright (C)2008 www.stani.beDATA#rvDATAH# This program is free software: you can redistribute it and/or modifyDATAH# it under the terms of the GNU General Public License as published byDATAD0# the Free Software Foundation, either version 3 of the License, orDATA(`# (at your option) any later version. DATAX# DATAD# This program is distributed in the hope that it will be useful, pDATAD=# but WITHOUT ANY WARRANTY; without even the implied warranty ofREEDATA@># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theDATA0?# GNU General Public License for more details.DATAA# EDATADA# You should have received a copy of the GNU General Public LicenseDATAHB# along with this program. If not, see http://www.gnu.org/licenses/DATAD|DATA import sysDATAEimport shell as _shellDATA,Efrom IPython.iplib import InteractiveShellDATA$Ffrom IPython.Shell import IPShellDATAG|DATA `Hclass Completer(_shell.Client):DATA(HI def complete(self,instance,text):DATA8@J return self.get('rl_complete',text,default=[])DATA DATA(K def __call__(self,instance,text):DATA,L return self.complete(instance,text)DATAMDATA8@Nclass Interpreter(_shell.Interpreter,InteractiveShell):DATA<XO """Interpreter based on code.InteractiveInterpreter."""DATAxP DATA(0Q def __init__(self, *args, **keyw):DATA8(R """Create an interactive interpreter object.3DATA8@S Locals can be only defined in the server."""DATA8XT InteractiveShell.__init__(self, *args, **keyw)DATA@pU _shell.Interpreter.__init__(self,showInterpIntro=False)DATA V |DATAHPW def runsource(self, source, filename='', symbol='single'):)2DATA<X """Compile and run some source in the interpreter.EDATAY diDATA0HZ Arguments are as for compile_command().DATAP[ reDATA([ One several things can happen:DATA\DATA@] 1) The input is incorrect; compile_command() raised an(DATAH^ exception (SyntaxError or OverflowError). A syntax tracebackDATAD_ will be printed by calling the showsyntaxerror() method.|DATA ay dDATA@a 2) The input is incomplete, and more input is required;DATA<b compile_command() returned None. Nothing happens.pDATAdDATADd 3) The input is complete; compile_command() returned a codeDATAHe object. The code is executed by calling self.runcode() (whichDATADg also handles run-time exceptions, except for SystemExit).coDATA@heptDATA h The return value is:DATAiothDATAxj - True in case 2EDATAPkhe DATALk - False in the other cases, unless an exception is raised, whereEDATAP0m None is returned instead. This can be used by external callers to'>DATA<xn know whether to continue feeding input or not.REEDATAo>DATAL8p The return value can be used to decide whether to use sys.ps1 orREEDATA,pq sys.ps2 to prompt the next line."""DATApr'] DATAHs # if the source code has leading blanks, add 'if 1:\n' to itDATAHPt # this allows execution of indented pasted code. It is temptingDATAHu # to add '\n' at the end of source to run commands like ' a=1'DATADv # directly, but this fails for more complicated scenariosDATA(w if source[:1] in [' ', '\t']:DATA,x source = 'if 1:\n%s' % sourceDATA4h _shell.Interpreter.runsource(self,source)DATA 8y REEDATA, def post_config_initialization(self):DATA< InteractiveShell.post_config_initialization(self)DATA0 self.set_custom_completer(Completer())DATA  DATA, def _ofind(self,oname,*args,**keyw):DATA< return self.get('ipython_ofind',oname,{'found':0})DATA  DATAclass Shell(IPShell):DATA(` def __init__(self,*args,**keyw):DATA,X keyw['shell_class'] = InterpreterDATA,P IPShell.__init__(self,*args,**keyw)DATAPuDATAdef start(user_ns = None):DATA$ return Shell(user_ns = user_ns)DATA DATA xdef main():DATA start().mainloop()DATA DATAif __name__ == '__main__':DATA ` main()TXhpyh<TXshell.pyzx xx@DATA0z/home/stani/sync/python/blender/server/shell.pyDATAx8x>DATA8xXCextDATAp8hDATAp 93DATApp  riptDATApDATAPp`FDATAPFDATAP@CXpCDATAX%DATAX(DATAXADATAX8@DATA`?DATAx.DATA PDATA8CDATApDDATA0`DATA81DATA0DATA(DATA(pDATA(H0)DATAp@DATAp8DATA8pDATA8(pDATApADATA(pDATAH%DATApDATAX %DATA ` DATAH\DATAH DATAHX=DATA0!DATAxHDATAxPTDATAPxDATAP`DATA8 xDATA hXDATA`:GDATAXf DATA8 DATA`DATA`(DATA(`pDATA(`DATAP DATAP0DATAP`(DATA 0 p -DATA   P DATA  0&DATA (X^?DATApЕ !?DATApZ?DATAp`%?DATAXZ?DATAH?DATAȚؙPIZ?DATAȚ`?DATAȚH"Z?DATA0"?DATAxȝ &^?DATAxp%/DATApxx,2DATAxpp'C4DATAphx*P6DATAh p8DATA hh:DATA0 @H<DATA0 x %?DATAЦ0h8D@DATAЦاx.BDATAاЦ h2EDATAاH$GDATA8*3IDATAhت JDATAh(I9LDATAȭhX=ODATAȭЮp,RDATAЮدȭx/VDATAدЮ h0dDATAhد0nDATAh@t~DATA@hȲ DATA@P DATA88DATA8DATA8HDATA0p DATA@DATAh DATAh4DATAxh *DATAxxDATA x8  DATA   X DATA p   ( DATAp 8    DATA8  p   {yDATA 8 H  5DATA `yDATA0xDATAH{yDATAp DATApH{yDATAHpDATAHXDATA02DATA8x{yDATAh8DATAh@DATA@(h DATA(@pDATA(HDATA0&DATA(x"DATAh$DATA`$DATA`0{yDATA`h-DATAhx ` 3DATAx !h (!7DATA!"x !8"/{yDATA"#!"0#"DATA#H$"#$ {yDATAH$P%#$$,DATAP%(&H$%%DATA(&('P%p&&+DATA('((&p''DATA((('H(( DATA()()h)({yDATA)*(*X*"DATA*+)*@+!DATA+,*+0,&DATA,@-+,-DATA@-H.,--,DATAH.p/@-./?DATAp/(0H.//{yDATA(0@1p/p007DATA@1 2(011{yDATA 2(3@1h220DATA(304 2p33,{yDATA044(3x44 DATA4504@55yDATA5646`6DATA675687{yDATA7P8678DATAP89788{yDATA99P8P99DATA9:9(:p:DATA:;9;X;%DATA;<:;x<ODATA<=;@==DATA=><>P>?DATA>`?=>?B?DATA`?(@>?? ?DATA(@@`?p@@ ?DATA@A(@(AA+?DATAAB@(BpB?DATABCACXC)F?DATACDBChD>?DATADEC EXEF?DATAEFDE@F8?DATAFGEFPG,B?DATAGHFGhH??DATAHIG IhIB?DATAIJHI@J?DATAJ`KIJKB?DATA`KHLJKK?DATAHLM`KLLB?DATAMMHLHMM?DATAMOM NNIB?DATAO(PMXOO4?DATA(P`QOpPPDB?DATA`Q@R(PQQ DATA@RXS`QRR7DATAXS@T@RSS"DATA@TxUXSTUDDATAxUPV@TUVDATAPVWxUVV \DATAWXPVPWW+ DATAXXWPXX DATAXYXYxY,oDATAYZX ZxZ*DATAZ[Y[`[DATA[\Z[X\,DATA\][]p]>DATA]^\(^p^DATA^_]_`_/DATA_`^`X`  DATA`a_`Pa.DATAaxb`a8b -DATAxbPcabc DATAPc0dxbcc DATA0dzPcxdhzMDATAz{0dz8{ #DATA{8|z{|DATA8|@}{||,DATA@}H~8|}}2DATAH~@}~~~DATAH~H"p3DATA05DATAHxDATAp0pDATAp@DATA@8p)DATA80@؄$DATA008xЅ+p3DATA00x DATA0@*DATA8hDATA8$DATA؉HADATAP#ADATAH$p3DATAX hDATAX@p3DATA@XX:DATAX@؏DATAHXXАDduGDATAHpAp3DATApH(?DATApP@DATAxBDATAЖ0!DATAЖxHDATAxЖ(8p3DATAxؘ0$4DATAPЙDATAPCDATAxPț &DATAx /DATAHxȝHDATAH ؞DATA  Hh+DATA  h#DATA( X7DATA(0pТ.p3DATA08(xأ2DATA8@01DATA@h8Ap3DATAh@(DDATAph(hDATApDATAp`ؒDATA@ DATAȫh-DATAȫXDATAxȫ0DATAx@ DATA@xЮp3DATA@`p3DATA(XDATAHа DATAH رDATA HhDATA P p3DATAPDATAp(DATApX"DATAXpض DATAXXDATA05DATAعHDATAع XDATAhعغ DATAh  DATA hhDATA@# Save this file as shell.py and run it externally of Blender.DATAD# Press Alt-A in the Blender 3D View to run the SPE Blender server.DATAhDATA<# SPE - Stani's Python Editor - http://pythonide.stani.beDATA$# Copyright (C)2008 www.stani.beDATA#DATAH`# This program is free software: you can redistribute it and/or modifyDATAH# it under the terms of the GNU General Public License as published byDATAD# the Free Software Foundation, either version 3 of the License, orDATA(# (at your option) any later version.DATA#DATAD# This program is distributed in the hope that it will be useful,EEDATAD# but WITHOUT ANY WARRANTY; without even the implied warranty ofDATA@# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theDATA0# GNU General Public License for more details.DATA # DATAD# You should have received a copy of the GNU General Public LicenseDATAH# along with this program. If not, see http://www.gnu.org/licenses/DATA0DATA4import cPickle, pprint, socket,sys,time,tracebackDATA from threading import ThreadDATADATApHOST = '127.0.0.1'DATAHPORT = 2020DATADATASLEEP = 0.001DATADATA(def write(x,sys=sys):DATAD "Replacement for print which will be deprecated in python3k."DATA( sys.stdout.write(x)DATA sys.stdout.flush()DATAp DATAXdef echo(x):DATA  return xDATADATAclass Proxy:DATAX def __str__(self):DATA$0 return self.__proxy_str__DATADATAdef ipython_object(x):DATA obj = eval(x)DATA` #subsitute proxiesDATA$8 for key in ['obj','parent']:DATA  o = obj[key]DATA< if type(o) == dict and o.has_key('__proxy_str__'):DATA p = Proxy()DATA$ p.__dict__.update(o) DATA obj[key] = pDATA return objDATApDATAPROMPT = ('>>>', '...')DATADATACOMMANDS = {DATA` 'str' : echo,DATA0  'eval' : eval,DATA  'pickle': cPickle.loads,DATA(0 'ipython_object' : ipython_object,?DATA(}>DATA$Еfor p in PROMPT: COMMANDS[p]=echof?DATA^?DATA(`WEBSITE = 'http://pythonide.stani.be'Z?DATAX^?DATAclass Client(object):^?DATALؙ def __init__(self,host=HOST,port=PORT,commands=COMMANDS,bufsize=8192,U?DATA  max_idle_count=20):DATA$ self.host = host?DATA$ self.port = port?DATA(ȝ self.commands = commands?DATA( self.bufsize = bufsizeDATA0 self.max_idle_count = max_idle_count2DATA( self.prompt = PROMPT[0]DATA, self.connection_succesfull = TrueDATA 9DATAh def _connect(self):DATAL@ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)=DATA  try:DATA< self._socket.connect((self.host, self.port))ADATA0 self.connection_succesfull = TrueDATA  return TrueDATA  except socket.error:GDATA, if self.connection_succesfull:DATAت write(DATAL 'Unable to connect to the SPE Blender Python Server.\n'+\DATA@ 'Make sure the server is running on %s:%s\n'\DATA0 %(self.host, self.port))TDATA0 self.connection_succesfull = FalseDATA  return FalsefDATA  tDATA def _disconnect(self):DATA try:DATA$P self._socket.close()DATA8 except:DATA passDATA H self._socket = NoneDATA0 DATA def _send(self,source):DATA while source:DATA8 self._socket.send(source[:self.bufsize])yDATA, source = source[self.bufsize:]DATAxDATA8  def _receive(self):DATA  data = ''DATA  count = 0DATA  while 1:DATA  try:uDATA8H  tmp = self._socket.recv(self.bufsize)DATA` except:DATA0 tmp = ''DATA if tmp:DATA data += tmpDATA count = 0DATA else:DATAX count += 1DATA40 if count == self.max_idle_count: breakDATA8 return dataDATADATA def _split(self,data):DATA$ index = data.find(' ')DATAp if index == -1:DATA H return data, NoneDATA(0 #split in command and argumentDATA$( command = data[:index]DATA( instructions= data[index+1:]yDATA( return command, instructionsDATAyDATA0 def _eval(self,data,traceback=traceback):DATA4 command, instructions = self._split(data)DATA8  #just echo if no space is present -> no commandDATA0! if instructions is None: return commandDATA$" #retrieve command functionDATA# try:DATA0$ execute = self.commands[command]DATA% except KeyError:DATA,p& return 'Error: Unknown Command'DATAp' #execute commandDATAH( try:DATA,) return execute(instructions)DATA$* except Exception, message:DATA$* traceback.print_exc()DATA(+ return 'Error: %s'%messageDATA , DATA0- def get(self,command,source,default=[]):yDATA@. return self.thread(self._get,command,source,default=[])DATA/ DATA8p0 def _get(self,command,source,default=[],result={}):DATA1 if self._connect():DATA4h2 self._send('%s %s'%(command,source))DATA0p3 r = self._eval(self._receive())DATAx4 else:DATA@5 r = defaultDATA6 self._disconnect()DATA6 result['get'] = rDATA7 return rDATA8 yDATAP9 #---Blender hackDATA(: def is_game(self):DATA(; if not hasattr(self,'_game'):DATAP; self._game = self.thread_without_game(self._get,'is_game','',False)DATA@= return self._gameDATA> B?DATA> def shake(self):?DATA? pass?DATA p@ ?DATA,(A def thread(self,target,*args,**kwargs):DATA(B if self.is_game():?DATA,C return target(*args,**kwargs)E?DATA@C return self.thread_without_game(target,*args,**kwargs)?DATA E E?DATA<E def thread_without_game(self,target,*args,**kwargs):E?DATA0F kwargs['result'] = result = {}B?DATA@G thread = Thread(target=target,args=args,kwargs=kwargs)DATA I thread.start()?DATAI self.shake()B?DATAJ thread.join()?DATA K return result['get']?DATA L =?DATAHMclass Interpreter(Client):?DATAL N def __init__(self,host=HOST,port=PORT,commands=COMMANDS,bufsize=8192,E?DATA8XO max_idle_count=20,showInterpIntro=True):F?DATAHpP super(Interpreter,self).__init__(host,port,commands,bufsize,DATAQ max_idle_count)DATA8R self.introText = 'Python %s\n'%sys.versionDATA$S if showInterpIntro: write(DATAHT 'SPE (%s) Blender Shell (%s:%s)\n'%(WEBSITE,host,port)+\DATAU self.introTextDATA V )CDATA,PW self.connection_succesfull = FalseDATAPX 5DATA0Y def runsource(self,source,*args,**keyw):DATA, Z self.connection_succesfull = TrueDATA[ if self._connect():DATA0[ self._send('run_source '+source)-DATA@] self.prompt, data = self._split(self._receive())DATA(^ if data:oDATA0_ if data[-1] != '\n': data+='\n'DATA$` self.write(data)DATA0` more = self.prompt == PROMPT[1]DATAa else:DATAb data = NoneDATAc more = FalseDATAxd self._disconnect()DATAz return moreDATA{ DATA0| def get_auto_complete_list(self,source):|DATA4} return self.get('auto_complete',source,[])DATA~ DATA$H def get_call_tip(self,source):DATA80 return self.get('call_tip',source,('','',''))DATAHDATA def run(self):DATA while True:DATA, source = self._read_source()DATA( if source is None: breakDATA,x self.more = self.push(source)DATAx DATA,@class InteractiveInterpreter(Interpreter):DATA8DATA( def __init__(self,*args,**keyw):DATAD؉ super(InteractiveInterpreter,self).__init__(*args,**keyw)DATA$ self.more = 0DATA( self.commandBuffer = []DATA  REEDATA  def push(self, command):DATA< """Send command to the interpreter to be executed.EDATA  DATAHX Because this may be called recursively, we append a new listDATAD onto the commandBuffer list and then append commands intoDATA@ that. If the passed in command is part of a multi-lineDATAD command we keep appending the pieces to the last list inDATAD commandBuffer until we have a complete command. If not, weDATA$0 delete that last list."""DATADATA< # In case the command is unicode try encoding itDATA(ؘ if type(command) == unicode:DATAЙ try:REEDATAD command = command.encode(wx.GetDefaultPyEncoding())DATA(ț except UnicodeEncodeError:DATA0 pass # otherwise leave it aloneDATAȝ DATA if not self.more:EEDATA,h try: del self.commandBuffer[-1]DATA$h except IndexError: passDATA8X if not self.more: self.commandBuffer.append([])DATA0p self.commandBuffer[-1].append(command)DATA4x source = '\n'.join(self.commandBuffer[-1])DATA4 more = self.more = self.runsource(source)EEDATAD## dispatcher.send(signal='Interpreter.push', sender=self,DATAH## command=command, more=more, source=source)DATA return moreDATADATA` def _read_source(self):DATA@ try:?DATA0 return raw_input(self.prompt+' ')DATA except EOFError:REEDATA return NoneDATA DATA def write(self,x):DATA` write(x)DATA(DATA аdef main():DATA if len(sys.argv) > 1:DATA h host = sys.argv[1]DATA P else:DATA host = HOSTDATA if len(sys.argv)>2:DATA$ port = int(sys.argv[2])EDATA  else:DATAX port = PORTDATA80 interpreter = InteractiveInterpreter(host,port)DATAH interpreter.run()DATA  3DATAغif __name__ == '__main__':DATA  main()DATAhTXh-pyTXSPE editor #p"p"X)DATAT C:\Documents and Settings\witold.jaworski\Moje dokumenty\Blender\Python.IDE\Spe.txtDATA $ DATA0 h$0DATA0 x $`DATAx  0 $&FREEDATA !x 8%3FREEDATA!P! %XTFREEDATAP!!! &GFREEDATA!!P!&X)FREEDATA!("!&.FREEDATA("p"!P'SFREEDATAp""("'FREEDATA"#p"(u FREEDATA#H#"8(ȩ# 2DATAH###( %FREEDATA##H#(NFREEDATA##)xFREEDATA $#Press ALT-P to launch SPE0DATAh$ut0DATA$#You can also copy files:sDATA($# spe_blender.py and winpdb_blender.py\DATA48%#from your Python Lib\site-packages\_spe directory DATAX%#into your Blender .blender\scripts directory or into user Blender script directory.REEDATAH &#This will add two commands to Scripts menu on the Script Window Panel:DATA,&# Scripts-->System-->Stani Python EditorDATA0&# Scripts-->System-->Attach Winpdb debugger EDATATP'#For more info visit http://pythonide.stani.be (or http://blenderartists.org/forum)DATA'pacDATA (import sysuDATA$8(if sys.modules.has_key('_spe.SPE'):DATA(( reload(sys.modules.get('_spe.SPE'))EEDATA(else: DATA) import _spe.SPElsTXh- TXspe_blender_server.py .o...XDATA@ ./home/stani/sync/python/blender/server/spe_blender_server.pyDATA..ȕaB0000DATA. /.8xDATA /h/.hpDATAh// /Jg DATA//h/ h,DATA/@0/87nch DATA@00/Ȧ9 NEWDATA00@0P0eeeDATA010`9DATA1`10x DATA`1118ȧU5DATA11`1hFDATA1821pFDATA8221XC8DATA2282Ț`%8DATA232 DATA3X32PA####DATAX333X@####DATA33X30Ȫ?@=DATA30438.DATA04x43sDATAx44040ȫCsDATA45x4@DDATA5P54kDATAP555HA<DATA55P5X'DATA5(65/DATA(6p65pDATAp66(6@DATA67p6DATA7H76(ȮDATAH777he eDATA77H78DATA7 87####DATA 8h87(er vDATAh88 8p#DATA88h8<DATA8@98h<DATA@998@)kDATA99@9####DATA9:9آP BDATA:`:9( forDATA`:::x,DATA::`:أP+P#DATA:8;:0://wDATA8;;:h####DATA;;8;8<DATA;<;P#DATA<X<;0ȳ qqqDATAX<<<x`DATA<<X<XFREEDATA<0=<DATA0=x=<P+ DATAx==0=PDATA=>x=FREEDATA>P>=(еllllDATAP>>>p<DATA>>P>H FREEDATA>(?>DATA(?p?>0ض,DATAp??(?8DATA?@p?ب2qqqqDATA@H@?8 DATAH@@@x 4IDATA@@H@(ectsDATA@ A@8DATA AhA@p)DATAhAA AȪpFREEDATAAAhAKDATAA@BA8(ADATA@BBA8%impoDATABB@BDATABCB ȺnderDATAC`CBh DATA`CCCP pa5DATACC`C<DATAC8DCȻ'<DATA8DDCp ;DATADD8Dح DATADEDм  DATAEXEDP- DATAXEEEpADATAEEXE DATAE0FE` DATA0FxFEh%DATAxFF0FDATAFGxF@DATAGPGF@DATAPGGGp&DATAGGPGȿDATAG(HG@DATA(HpHGH DATApHH(HDATAHIpHDATAIHIH@DATAHIIIXDATAIIHIز DATAI JIDATA JhJIP(DATAhJJ J`6DATAJJhJDATAJ@KJ(DATA@KKJpHoADDATAKK@K DATAKLK DATAL`LK(DATA`LLLpX& DATALL`LDATAL8MLDATA8MML8 10)DATAMM8M;& DATAMNMkDATANXNMP@llllDATAXNNNDATANNXNȷ._diDATAN0ON ?DATA0OxONH@+ DATAxOO0O ADATAOPxO(DATAPPPO88exc(DATAPPPP selDATAPPPPȹ3QDATAP(QP(0FREEDATA(QpQPhx& DATApQQ(QZ?DATAQRpQ FREEDATARHRQHX DATAHRRRx*?DATARRHRлf,soDATAR SR 0<DATA ShSRXh5pa5DATAhSS S<?DATASShS0@2<DATAS@TS?DATA@TTSȽDATATT@T CkDATATUTDATAU`UTȾ8Z?DATA`UUU0H,pt sDATAUU`UEZ?DATAU8VU 2)<DATA8VVUh0DATAVV8VtionDATAVWVMDATAWXWV FREEDATAXWWW/ DATAWWXW 8DATAW0XWp.DATA0XxXW!= seDATAxXX0X 8XDATAXYxXh)DATAYPYX&if tDATAPYYY0 DATAYYPY`pa5DATAY(ZY0DATA(ZpZY0DATApZZ(ZXx'pa5DATAZ[pZ4FREEDATA[H[Z84Z?DATAH[[[$DATA[[H[ DATA[ \[8DATA \h\[` DATAh\\ \XDATA\\h\;<DATA\@]\Px:Z?DATA@]]\<DATA]]@](P'Z?DATA]^]DATA^`^]> DATA`^^^(P#?DATA^^`^x####DATA^8_^ urn DATA8__^(-pa5DATA__8_X DATA_`_= seDATA`X`_Z?DATAX```(X?DATA``X`pkDATA`0a`+DATA0axa`@?DATAxaa0aP<DATAabxaDATAbPba<qqqqDATAPbbbH<DATAbbPb^?DATAb(cb%PDATA(cpcb(hDATApcc(cp$DATAcdpcHDATAdHdcP#PDATAHddd` DATAddHd(?DATAd ed@BZ?DATA ehedhEDATAhee e(, DATAeehe@?DATAe@fex#####DATA@ffeFDATAff@f@B?DATAfgf#= seDATAg`gfX P!DATA`ggg@3DATAgg`gADATAg8hg@pa5DATA8hhg0 r>DATAhh8hpter(DATAhih leteDATAiXih`>?DATAXiiip$elf.DATAiiXi(":?DATAi0jix es(tDATA0jxjiXDATAxjj0j DATAjkxj@/?DATAkPkj@DATAPkkkterDATAkkPk0 ct=iDATAk(lkp DATA(lplkP%DATApll(lFDATAlmpl DATAmHml`DATAHmmm-N?DATAmmHmpDATAm nm`kDATA nhnmDATAhnn n@<DATAnnhn(qqqqDATAn@on`K('seDATA@oon@bbq?DATAoo@oppa5DATAopoP$N?DATAp`poP#DATA`ppp@esulDATApp`p-1DATAp8qpx9qqqqDATA8qqpH/?DATAqq8q@1exceDATAqrq0 DATArXrqh4DATAXrrrP5DATArrXrpDATAr0srbbbbDATA0sxsr`AR?DATAxss0sh<DATAstxsDATAtPts`?DATAPttt0DATAttPtxP0<DATAt(ut`,R?DATA(uputX"<DATApuu(u"N?DATAuvpu`&?DATAvHvuP%j(obDATAHvvv%DATAvvHvh%R?DATAv wvX,pa5DATA whwv P#DATAhww whDATAwwhw8+P#DATAw@xwG DATA@xxwxJDATAxx@x-__clDATAxyxPKDATAy`yxX0DATA`yyy0OR?DATAyy`y8)9XDATAy8zybbbbDATA8zzy@(FREEDATAzz8z 2FREEDATAz{z&<DATA{X{zPDATAX{{{  <DATA{{X{`! DATA{0|{(FREEDATA0|x|{h%<DATAx||0|H!DATA|}x|1FREEDATA}P}|p FREEDATAP}}}8#out,DATA}}P}!pa5DATA}(~}X \DATA(~p~} DATAp~~(~h`DATA~p~0rn sDATAH~h-^DATAHH autoDATAHC?DATA +<DATA hP<DATAh Ps:?DATAhDATA@X&DATA@@!ttr(DATAЁ@ DATAЁHphDATA`Ё(&<DATA` DATA`8V?DATA8pDATA8H&HDATAȃ8bb qDATAȃH == DATAXȃ @oDATAXhV?DATAXDATA0XrDATA0x09kDATAx0def DATAx@DATAP(qqqqDATAPpV?DATAP DATA(`DATA(pXhon_DATAp(<DATAp02HDATAHo?DATAHo DATA؈H0pV?DATA؈ Pxp FREEDATA h؈p<DATAh q<DATAh8`q&DATA@q"PDATA@r$V?DATAЊ@8`r$<DATAЊrFREEDATA`ЊrC<DATA`0`sDATA`s3exceDATA8t7DATA8Ht/9DATAȌ8t"kDATAȌ0u DATAXȌ8pu,V?DATAXu?DATAXv/<DATA0@xvFREEDATA0xv P#DATAx0w(<DATAx Xw"pa5DATAPpw!(selDATAPw*hasaDATAPPx?DATA(PxqqqqDATA(pxP#DATAp( y8pa5DATApHy+ DATAHyDATAHzDATAؑH`zP#DATAؑ Xz%DATA hؑ{)FREEDATAh `{ bb DATAhX{P#DATA@{FREEDATA@(|Lpa5DATAГ@P|FREEDATAГ|" DATA`Г0} DATA` x}LDATA`} DATA8(~<DATA8p~PDATA8X~{yDATADȕ# Press Alt-A in the 3D view above to start the SPE blender server#DATA8RDATAh# Usage hints:DATAL# - Save wxshell.py (or ipython ishell.py or shell.py) in an external fileDATA0 # - Launch the shell with: python wxshell.pybDATA8# - Move it so that it overlaps with the Blender windowDATA<# (For iPython ishell.py or shell.py turn on animation)DATAPetDATA<# SPE - Stani's Python Editor - http://pythonide.stani.beDATA$# Copyright (C)2008 www.stani.bea5DATA8###DATAHh# This program is free software: you can redistribute it and/or modifyDATAH# it under the terms of the GNU General Public License as published byDATADX# the Free Software Foundation, either version 3 of the License, orDATA(Ț# (at your option) any later version.DATA #DATADP# This program is distributed in the hope that it will be useful,EEDATAD# but WITHOUT ANY WARRANTY; without even the implied warranty ofa5DATA@0# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theDATA0# GNU General Public License for more details.DATA# DATAD0# You should have received a copy of the GNU General Public LicenseDATAH# along with this program. If not, see http://www.gnu.org/licenses/DATADATADHimport __builtin__,cPickle,inspect, socket, sys, traceback, typesDATA(from code import InteractiveInterpreterDATA0from rlcompleter import Completer as _CompleterDATApDATAHOST = '127.0.0.1'DATAPORT = 2020DATA(METHOD = strDATAhSDATA NO_CALLTIP = 'eval ("","","")'DATAREEDATA,LOCALS = {'__import__': __import__}###DATA$pLOCALS.update(__builtin__.__dict__)DATAtry:DATA import GameLogicfulDATA,@ scene = GameLogic.getCurrentScene()buDATA LOCALS.update({DATA$آ 'GameLogic' : GameLogic,###DATA ( 'scene' : scene,###DATA0x 'objects' : scene.getObjectList(),DATA,أ 'lights' : scene.getLightList(),DATA0 })DATAh Permanent = GameLogicDATA GAME = 1DATAexcept ImportError:DATA0 import Blender, bpyDATAx LOCALS.update({DATA  'Blender' : Blender,DATA 'bpy' : bpy,DATA,P 'objects' : Blender.Object.Get(),DATA })DATA Permanent = BlenderDATA( GAME = 0LDATApaDATA#---completerllDATA class Completer(_Completer):DATA00 def complete_command(self,text,str=str):DATA if "." in text:DATA4ب self.matches = self.attr_matches(text)DATA8 else:DATA8x self.matches = self.global_matches(text)DATA, return 'eval '+str(self.matches)lllDATA8 DATA,pcompleter = Completer(namespace=LOCALS) DATAȪqqqDATA#---interpreterDATA,8def formatargspec(func,inspect=inspect):REEDATA( """Get argument specifications"""qDATA  try:DATA  func=func.im_funcllDATA h except:DATA passGetDATA  try:DATA( result = inspect.formatargspec(DATA<p *inspect.getargspec(func)).replace('self, ','')DATA ح except:DATA try:DATA0P result = inspect.formatargvalues(DATAD *inspect.getargvalues(func)).replace('self, ','')DATA  except:DATA` result = ''DATA( if result == '(*args, **kwargs)':DATA return ''DATA@ return resultDATADATA(def proxy_attr(obj,eval=eval,str=str):DATA  try:DATA@ sobj = str(obj)DATA  except:DATA return ''DATA  try:DATA @ if obj == eval(sobj):DATA return objDATA ز except:DATA return sobjDATAP DATA8def proxy_attrNOTWORKING(obj,cPickle=cPickle,str=str):DATA  try:DATA( cPickle.dumps(obj)DATAp return objDATA  except:DATA try:DATA( return str(obj)DATAp except:DATA  return ''DATA DATA48def proxy_obj(obj, proxy_attr=proxy_attr,dir=dir,^?DATA< setattr=setattr,getattr=getattr,type=type,str=str):DATA  if proxy_attr(obj) == obj:DATAP return objDATA  try:DATAȷ sobj = str(obj)qDATA  except:DATA,H sobj = '<%s>'%type(obj).__name__DATA$ p = {'__proxy_str__':sobj}<DATA for attr in dir(obj):DATA 8 if attr != '__class__':DATA try: DATA4ȹ pa = proxy_attr(getattr(obj,attr))DATA( except:DATA(h pa = ''qDATA p[attr]=paDATA return pqqqDATAH0DATA,xclass Interpreter(InteractiveInterpreter):EDATA л prompt = ('>>>', '...')DATA  #DATA8X def __init__(self,locals={},extra_attributes=[]):DATA@ InteractiveInterpreter.__init__(self, locals=locals)DATA40 self.extra_attributes = extra_attributesDATA etuDATAȽ def run_source(self,x, DATAD InteractiveInterpreter=InteractiveInterpreter,sys=sys):DATA self.output = ''DATA<Ⱦ _stdout, _stderr = sys.stdout, sys.stderr0DATA00 sys.stdout, sys.stderr = self, self?DATAH more = InteractiveInterpreter.runsource(self,x)DATA4 sys.stdout, sys.stderr = _stdout, _stderrEDATA4h return self.prompt[more]+' '+self.output DATA DATAP def get_auto_complete_list(self,command,dir=dir,str=str,getattr=getattr):DATA try:?DATA0 obj = self._get_object(command)DATA  l = dir(obj) DATA0p for attr in self.extra_attributes:DATA$ if attr not in l: DATA  try:0DATA,h getattr(obj,attr) DATA( l.append(attr)DATA except:DATA ` passDATA4 l = [(x.lower(),x) for x in l]DATA l.sort()DATA(X l = [x[1] for x in l]DATA8 public = [x for x in l if x[:1] != '_']<DATA8 private = [x for x in l if x[:1] == '_']?DATA( l = public+privateDATA except:DATA l = []DATA ` return 'eval '+str(l)DATA ###DATA< def _get_object(self,command,namespace=None,eval=eval):DATA<P if namespace == None: namespace = self.localsDATA@ if command[-1:] in ['.','(']: command = command[:-1]DATA(( return eval(command, namespace)DATA DATA@ def ipython_ofind(self,oname,str=str,proxy_obj=proxy_obj):DATA$( oname = oname.strip()DATAx #objectDATA try: DATA0 obj = self._get_object(oname)DATAX found = 1DATA except:DATA obj = None?DATA( found = 0DATAp #parentDATA, osplit = oname.split('.')[:-1]DATA parent = NoneiDATAP while osplit:DATA try:DATA@ parent = self._get_object('.'.join(osplit))DATAH breakDATA except:DATA( osplit = osplit[:-1]?DATA( #proxy objectutDATA(p proxy = proxy_obj(obj)<DATA if obj == proxy:DATA$ ospace = 'Interactive'DATA` else:DATA, ospace = 'Blender internal'REEDATAD result = {'found':found, 'obj':proxy, 'namespace':ospace,DATAHh 'ismagic':0, 'isalias':0, 'parent':proxy_obj(parent)}^?DATA0 return 'ipython_object '+str(result)Z?DATA @ , tDATA$x def get_call_tip(self,command, DATAH hasattr=hasattr,TypeError=TypeError,type=type,types=types,DATAD@ eval=eval,dir=dir,str=str,formatargspec=formatargspec,EDATA$ NO_CALLTIP=NO_CALLTIP):DATA try:REEDATA4@ obj = self._get_object(command)DATA except:DATA  return NO_CALLTIPDATA0 #name>DATA p name = commandqqDATA #argspec0DATA@ if type(obj) in [types.ClassType,types.TypeType] and \DATA(p hasattr(obj,'__init__'):qqqDATA$ init = obj.__init__DATA else: DATAX init = obj?DATA try:DATA0 argspec = formatargspec(init)[1:-1]DATA@ except TypeError:EEDATA argspec = ''DATA #tipqqqDATA try:?DATA(P tip = obj.__doc__DATAH if obj!=init and init.__doc__: tip += '\n\n'+init.__doc__DATA  except:DATA ` tip = ''DATA0 calltip = str((name,argspec,tip))N?DATA  return 'eval '+calltip'DATA` DATA def write(self,x):DATA self.output += xREEDATA ( *DATAL`interpreter = Interpreter(locals=LOCALS,extra_attributes=['name','parent'])DATA,DATAdef is_game(x,GAME=GAME):DATA(P return ['str ','str True'][GAME]?DATA-DATACOMMANDS = {DATA0 'run_source' : interpreter.run_source,DATA<x 'auto_complete' : interpreter.get_auto_complete_list,DATA0 'call_tip' : interpreter.get_call_tip,DATA4@ 'rl_complete' : completer.complete_command,DATA4 'ipython_ofind' : interpreter.ipython_ofind,^?DATA  'is_game' : is_game,sDATAP}EEDATADATAdef write(x,sys=sys):DATAD "Replacement for print which will be deprecated in python3k."EEDATAh sys.stdout.write(x)DATA sys.stdout.flush()DATA le.DATA0class SpeBlenderServer(): DATATx def __init__(self,host=HOST,port=PORT,commands=COMMANDS,backlog=1,timeout=0,REEDATA0 bufsize=8192,max_idle_count=20):DATA$X self.host = host DATA$ self.port = portEDATA( self.commands = commandsDATA(P self.backlog = backlogqqDATA( self.timeout = timeoutDATA( self.bufsize = bufsizeDATA0X self.max_idle_count = max_idle_count DATA self.start()DATA  <DATA,8 def _create_socket(self,socket=socket):DATAH self.log('\tCreating socket with %d sec timeout.'%self.timeout)DATAL self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)DATA0 self._socket.settimeout(self.timeout)EEDATAL self.log('\tBinding to host "%s" on port %d'%(self.host,self.port))DATA4X self._socket.bind((self.host,self.port)) DATAP self.log('\tListen for maximum %d of queued connections.'%self.backlog)DATA,8 self._socket.listen(self.backlog)DATA  PDATA, def start(self,traceback=traceback):DATA4  self.log('Starting SPE Blender Server...')DATA( self._socket = NoneDATA self._disconnect()EDATA  try:DATA$` self._create_socket()DATA except:DATA( self.log('\t... FAILED!')DATA$H traceback.print_exc()EEDATA4 if self._socket: self._socket.close()qqDATA llDATA$8 def is_running(self,bool=bool):DATA$ return bool(self._socket)DATA DATA$ def log(self,x,write=write):<DATAh write(x+'\n')qqDATA  _DATA0 def _connect(self,socket=socket,str=str):5DATAH try:DATAD self._connection, self._address = self._socket.accept()DATA, self._connection.setblocking(0)DATA@P #self.log("Connected to %s."%str(self._address)) DATA return 1bb DATA  except socket.timeout:DATA(X self._connection = None DATA$ self.log('Timed out')qqDATA return 0DATA H except socket.error:DATA( self._connection = NoneDATA return 0#DATA 8 t()DATAp def _disconnect(self): DATA( self._connection = NoneDATA  REEDATAH def _receive(self):DATA data = ''DATA count = 0DATA while 1:REEDATAX try:etuDATA< tmp = self._connection.recv(self.bufsize)^?DATA except:DATA@ tmp = '' DATA if tmp:DATA  self.log(tmp)qqDATA data += tmpDATA` count = 0 DATA else:EEDATA count += 1EDATA40 if count == self.max_idle_count: breakEDATA return dataDATA seDATA def _split(self,data):DATA$P index = data.find(' ')DATA if index == -1:DATA  return data, NoneDATA(8 #split in command and argument?DATA$ command = data[:index]DATA( instructions= data[index+1:]a5DATA(8 return command, instructions DATA DATAD def _execute(self,data,traceback=traceback,Exception=Exception,DATA 0 KeyError=KeyError):DATA4 command, instructions = self._split(data)DATA8 #just echo if no space is present -> no commandDATA0H if instructions is None: return commandDATA$ #retrieve command functionEDATA try:<DATA08 execute = self.commands[command]DATA except KeyError:endDATA0 return 'str Error: Unknown Command'DATA@ #execute commandM?DATA try:lllDATA, return execute(instructions)0DATA$  except Exception, message: DATA$p traceback.print_exc()qqDATA, return 'str Error: %s'%messageDATA  DATAP def _send(self,output):DATA while output:DATA< self._connection.send(output[:self.bufsize])DATA,H output = output[self.bufsize:]DATAREEDATA def tick(self):DATA if self._connect():DATA(X data = self._receive()DATA, output = self._execute(data)DATA  self._send(output)DATAX self._disconnect()DATA DATAP# create a server, to keep around always as a global in the GameLogic moduleDATAPtry:DATA$ server = Permanent.SPE_serverEDATAexcept AttributeError:DATAP  Permanent.SPE_server = server = SpeBlenderServer(HOST,PORT,COMMANDS)DATA DATAif server.is_running():DATA server.tick() DATAX TXh -TXwxshell.pyX uDATA4X /home/stani/sync/python/blender/server/wxshell.pyDATA`PO@DATA`Pp7ti}DATA `PHP.py%DATA 8hе9menuDATA8  ж FREEDATA ȷ8hDATAȷ؆ `FDATA؆ȷ F?DATA@؆XȈCB?DATA@8%B?DATA8@?DATA8(AB?DATA0P@?DATA0Xx?F?DATAX`0.?DATA`X؏B?DATA8`PC?DATA8pD?DATAp8?DATAp`?DATA(p>DATAp8 ?DATAph$>DATAhp?DATA8hXȗ>?DATA8X;?DATAX8ؙ?DATAXX0?DATA@`ЛB?DATA@0؜#?DATA0H@x4?DATAH`04?DATA`H;>DATA`Ƞ06>DATA@,?DATAȣX?>DATAȣФp/?DATAФȣP?DATA`ФХ?DATA`h,>DATAh``%?DATA`Hh>DATAH `ة?DATA Hh>DATAЫ @?DATAЫ`?DATA`Ы(?DATA`X'B?DATAX`B?DATA8XȯB?DATA8 а ?DATA H8hر=B?DATAHp A?DATApxH-F?DATAxp(7p3DATAXxصݘDATAXp9DATAp8X DATA8pȸ`DATA@8`йBDATA@0  E@DDATA0 X@x  @DATAXH0 # DATAH0XDATA0(Hx%p3DATA(0pDATA(X%DATAPDATA8xDATAx@DATAx`"DATA`x?p3DATA`@CDATA`/DATAp9p3DATA ;%DATA0@D$DATA0hxGDATAh0 BDATA h0 %-DATA p!  !DATAp!h" !"'DATAh"P#p!"#!DATAP#H$h"##'p3DATAH$0%P#$$!$DATA0%&H$x%%DATA&&0%P&& DATA&'&'P'DATA'(&'0(DATA(()'((H(DATA()P*(p))=DATAP*x+()*+@9DATAx+0,P*++p3DATA0,h-x+x,,EDATAh-.0,- .A!DATA./h-.8/-p3DATA/0./H07DATA01/0h1<DATA130 22ADATA331H33DATA3p434@4DATAp4534 54 DATA56p4506.DATA6H7567X6DATAH78678Fp3DATA8x9H78 9)DATAx9 :899DATA :;x9h::#DATA;X< :X;;LpyriDATAX<=;<==pDATA=>X<=0>;am iDATA>?=>@?)`DATA?@>?8@+FREEDATA@A?@0A :DATAAB@AHBMDATABCACCCdef DATACDB@DpD intDATADECD8E":DATAEFDE(F$ DATAF(GEFFme)DATA(GGFpGGDATAG(I(G8HHE DATA(IPJGpIIB()DATAPJxK(IJK<DATAxKLPJK8LDstdiDATALMxKLPM)p3DATAMPNLM NDATAPNOMNOJe chDATAOPPNO8P5DATAPHQOPQ:DATAHQ0RPQQ DATA0R SHQxRR#DATA SXT0RhSSG selDATAXTU STUK DATAUPVXTUV DATAPV8WUVVdoutDATA8W0XPVWW& DATA0XY8WxXX"DATAY Z0X`YY1tionDATA ZX[YhZZGt, sDATAX[\ Z[\<_autDATA\]X[\H]N:DATA]^\^x^;calsDATA^_]0_x_def DATA_`^`x`?:DATA`0b_0aaNDATA0b8c`xbb2FREEDATA8c`d0bccB DATA`de8cde? DATAef`de@f=:DATAfgef`g4FREEDATAghfhh>DATAhig8iiDATAijhjXj' + DATAjHkijk latDATAHk ljkk<DATA llHkhll 'DATAlm l@mm!DATAmnl(nxn 'DATAnomo`o MessDATAopno@paDATApPqopqDATAPqrpqqDATArrPqPrr DATArsrsXsapp DATAshtrs(tFREEDATAht usttDATA uuhthuuDATAu u@vxv DATAD# Save this file as wxshell.py and run it externally of Blender.py%DATA8# Let the Shell window overlap with the Blender Window.DATAHLDATA<h# SPE - Stani's Python Editor - http://pythonide.stani.beDATA$# Copyright (C)2008 www.stani.be DATAh#DATAH# This program is free software: you can redistribute it and/or modifyDATAH # it under the terms of the GNU General Public License as published by?DATADX# the Free Software Foundation, either version 3 of the License, orDATA(# (at your option) any later version.?DATA#E?DATAD(# This program is distributed in the hope that it will be useful,E?DATADP# but WITHOUT ANY WARRANTY; without even the implied warranty ofE?DATA@x# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theDATA0# GNU General Public License for more details.?DATA# ?DATADP# You should have received a copy of the GNU General Public LicenseDATAH# along with this program. If not, see http://www.gnu.org/licenses/B?DATA>DATA`import sys, time?DATA(import shell as _shell?DATA import wx>DATA(from wx.py import interpreter, shell?DATA>DATA@Xclass Interpreter(_shell.Interpreter,interpreter.Interpreter):>DATA< """Interpreter based on code.InteractiveInterpreter."""DATA ?DATA4X def __init__(self, locals=None, rawin=None, ?DATAD` stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,?DATA$ showInterpIntro=False):DATA8x """Create an interactive interpreter object.?DATA8 Locals can be only defined in the server.""">DATA< interpreter.Interpreter.__init__(self,rawin=rawin, DATA8Ƞ stdin=stdin, stdout=stdout, stderr=stderr,?DATA0 showInterpIntro=showInterpIntro)?DATA@ _shell.Interpreter.__init__(self,showInterpIntro=False)DATA0 #wx.CallAfter(self.thread,self.is_game)DATA  ?DATAХ def shake(self):?DATA0 frame = wx.GetApp().GetTopWindow()>DATA( x, y = frame.GetPosition()>DATA  frame.Move((x+1,y+1))>DATA frame.Update()?DATAh time.sleep(0.01)?DATA@ frame.Move((x,y))E?DATA frame.Update()?DATA  >DATA( def _runsource(self,source,result):DATAD result['get'] = _shell.Interpreter.runsource(self, source)?DATA ȯ =?DATA$ def runsource(self, source):E?DATA@h """Compile and run source code in the interpreter."""B?DATAD stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr=?DATA0 sys.stdin, sys.stdout, sys.stderr = \B?DATA8 self.stdin, self.stdout, self.stderrDATAص if source:DATA< more = self.thread(self._runsource,source)DATA else:DATA more = FalseDATAD` # If sys.std* is still what we set it to, then restore it.DATAH # But, if the executed source changed sys.std*, assume it waspBDATADx  # meant to be changed and leave it. Power to the people.DATA$ if sys.stdin == self.stdin:DATA  sys.stdin = stdinDATA(x if sys.stdout == self.stdout:DATA p sys.stdout = stdoutDATA(X if sys.stderr == self.stderr:DATA P sys.stderr = stderrDATA8 return moreDATA  DATA$## def runsource(self, source):DATA@## """Compile and run source code in the interpreter."""DATAD## stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderrDATA0## sys.stdin, sys.stdout, sys.stderr = \DATA<## self.stdin, self.stdout, self.stderrDATA< ## more = _shell.Interpreter.runsource(self, source)DATAH@## # If sys.std* is still what we set it to, then restore it.DATAHx## # But, if the executed source changed sys.std*, assume it wasDATAD## # meant to be changed and leave it. Power to the people.DATA(## if sys.stdin == self.stdin:DATA ## sys.stdin = stdinDATA(!## if sys.stdout == self.stdout:DATA$"## sys.stdout = stdoutDATA(### if sys.stderr == self.stderr:DATA$$## sys.stderr = stderrDATAx%## return moreDATA P&## DATA' def write(self,x):DATA ' self.stdout.write(x)DATA(|DATA@p) def getAutoCompleteList(self, command='', *args, **kwds):DATAD* """Return list of auto-completion options for a command.`DATA + DATAHx, The list of options will be based on the locals namespace."""DATAD- stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderrDATA0. sys.stdin, sys.stdout, sys.stderr = \DATA8/ self.stdin, self.stdout, self.stderrDATA@0 l = self.get_auto_complete_list(command.split()[-1])DATAD 2 sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderrEEDATAH3 return lREEDATA4REEDATA84 def getCallTip(self, command='', *args, **kwds):DATA05 """Return call tip text for a command.DATA 6 REEDATAH7 Call tip information will be based on the locals namespace."""DATA,8 return self.get_call_tip(command)DATA9rDATA$h:class ShellFrame(shell.ShellFrame):DATAPX; def __init__(self, parent=None, id=-1, title='Spe Blender Python Shell',s pDATA@< pos=wx.DefaultPosition, size=wx.DefaultSize,DATA<= style=wx.DEFAULT_FRAME_STYLE, locals=None,DATA,> InterpClass=Interpreter,DATA,? config=None, dataDir=None,DATA$@ *args, **kwds):REEDATAPA shell.frame.Frame.__init__(self, parent, id, title, pos, size, style)DATADC shell.frame.ShellFrameMixin.__init__(self, config, dataDir)DATA@DREEDATA$D if size == wx.DefaultSize:DATA(E self.SetSize((750, 525))DATAF DATApG intro = ''DATAH8H self.shell = shell.Shell(parent=self, id=-1, introText=intro,3DATADpI locals=locals, InterpClass=InterpClass,nDATA@J startupScript=self.startupScript,DATAHK execStartupScript=self.execStartupScript,DATA,L *args, **kwds)DATAMat DATALN # Override the shell so that status messages go to the status bar. DATA8O self.shell.setStatusText = self.SetStatusTextDATAPREEDATA Q self.shell.SetFocus()ceDATA$xR self.LoadSettings() DATAHhS self.SetStatusText("SPE (Stani's Python Editor) - %s - %s:%s"%\DATALT (_shell.WEBSITE,self.shell.interp.host,self.shell.interp.port))DATA U |DATA V def OnAbout(self, event):r DATA(W """Display an About window."""DATA$xX title = 'About this shell'ADATA4`Y text = 'SPE Blender Python Shell\n\n' + \DATAHhZ 'A remote interactive python shell for Blender.\n\n' + \DATA@[ 'Licensed under the GPL-v3 or later.\n\n' + \s.sDATAP\ "This shell makes part of SPE (Stani's Python Editor).\n\n" + \ DATA<^ '(c) 2008 Stani (%s)\n\n'%_shell.WEBSITE + \DATA0_ '' + \DATA@` 'Shell Revision: %s\n' % self.shell.revision + \DATAP0a 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \,DATA4xb 'Platform: %s\n' % sys.platform + \DATADc 'Python Version: %s\n' % sys.version.split()[0] + \eDATA@d 'wxPython Version: %s\n' % wx.VERSION_STRING + \DATA@e ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:])) ssDATA8f dialog = wx.MessageDialog(self, text, title,:DATA@h wx.OK | wx.ICON_INFORMATION)rDATA8i dialog.ShowModal()DATAj dialog.Destroy()intDATAj|DATAkclass ShellApp(wx.App):DATAhl def OnInit(self):DATA$@m wx.InitAllImageHandlers()DATA (n frame = ShellFrame():DATA$o self.SetTopWindow(frame) DATAo frame.Show(True) DATAp return 1|DATAq SetDATA Prdef main():DATAs app = ShellApp(0)p.DATAs app.MainLoop()DATAt DATAhuif __name__ == '__main__':DATA @v main()OB Hx[{OBCamera ;??????w?w????????(?OBd8?)d??>)d?????OB {[HxOBCube~?????????????DOBd8? #=?>=??@???@@0ME~2MECube.001Px  8 3???DATA,PDATAP8??II?I?I???III??II?I??IIDATA, xDATAx5 ############DATA,8DATAx4DNA1H SDNANAMEF*next*prev*first*lastxyzwxminxmaxyminymax*pointergroupvalpadname[32]typesubtypeflagsaveddatalentotallen*newid*libname[24]usicon_id*propertiesid*idblock*filedataname[240]filename[240]tot*parentcurvecurblocktypeshowkeyposcurvaladrcodetotelem*data*weightsvgroup[32]sliderminslidermax*refkeyelemstr[32]elemsizeblock*ipo*fromtotkeyslurph**scripts*flagactscripttotscript*line*formatblen*nameflagsnlineslines*curl*sellcurcselc*undo_bufundo_posundo_len*compiledsizeseekpassepartalphaangleclipstaclipendlensortho_scaledrawsizeshiftxshiftyYF_dofdistYF_apertureYF_bkhtypeYF_bkhbiasYF_bkhrotscriptlinkh*rectframenrframesoffsetsfrafie_imacyclokmulti_indexlayerpassmenunribufs*anim*rrsourcepad1lastframetpageflagtotbindxrepyreptwstatwendbindcode*repbind*packedfile*previewlastupdatelastusedanimspeedgen_xgen_ygen_type*vnodetexcomaptomaptonegblendtype*object*texuvname[32]projxprojyprojzmappingofs[3]size[3]texflagcolormodelrgbkdef_varcolfacnorfacvarfacdispfacwarpfacname[160]*handle*pname*stnamesstypesvars*varstr*result*cfradata[32](*doit)()(*instance_init)()(*callback)()versionaipotype*ima*cube[6]imat[4][4]obimat[3][3]stypeviewscalenotlaycuberesdepthrecalclastsizenoisesizeturbulbrightcontrastrfacgfacbfacfiltersizemg_Hmg_lacunaritymg_octavesmg_offsetmg_gaindist_amountns_outscalevn_w1vn_w2vn_w3vn_w4vn_mexpvn_distmvn_coltypenoisedepthnoisetypenoisebasisnoisebasis2imaflagcropxmincropymincropxmaxcropymaxxrepeatyrepeatextendcheckerdistnablaiuser*plugin*coba*envloc[3]rot[3]mat[4][4]min[3]max[3]*obmodetotexenergydistspotsizespotblendhaintatt1att2shadspotsizebiassoftbufsizesampbuffersfiltertypebufflagbuftyperay_sampray_sampyray_sampzray_samp_typearea_shapearea_sizearea_sizeyarea_sizeztexactshadhalostepYF_numphotonsYF_numsearchYF_phdepthYF_useqmcYF_bufsizeYF_padYF_causticblurYF_ltradiusYF_glowintYF_glowofsYF_glowtypeYF_pad2*mtex[10]specrspecgspecbmirrmirgmirbambrambbambgambemitangspectraray_mirroralpharefspeczoffsaddtranslucencyfresnel_mirfresnel_mir_ifresnel_trafresnel_tra_ifiltertx_limittx_falloffray_depthray_depth_traharseed1seed2mode_lflarecstarclinecringchasizeflaresizesubsizeflarebooststrand_stastrand_endstrand_easesbiasshad_alphapadfrgbselpr_typeuse_nodespr_backpr_lampseptexml_flagdiff_shaderspec_shaderroughnessrefracparam[4]rmsdarkness*ramp_col*ramp_specrampin_colrampin_specrampblend_colrampblend_specramp_showpad3rampfac_colrampfac_spec*nodetree*groupfrictionfhreflectfhdistxyfrictdynamodepad2sss_radius[3]sss_col[3]sss_errorsss_scalesss_iorsss_colfacsss_texfacsss_frontsss_backsss_flagsss_presetYF_arYF_agYF_abYF_dscaleYF_dpwrYF_dsmpYF_presetYF_djitname[256]scale*bbi1j1k1i2j2k2selcol1selcol2quat[4]expxexpyexpzradrad2s*mat*imatelemsdisp**mattotcolwiresizerendersizethreshvec[3][3]alfaweightradiush1h2f1f2f3hidevec[4]mat_nrpntsupntsvresoluresolvorderuordervflaguflagv*knotsu*knotsv*bp*beztcharidxkernnurb*bevobj*taperobj*textoncurve*path*keybevpathlenbevresolwidthext1ext2resolu_renresolv_renspacemodespacinglinedistshearfsizewordspaceulposulheightxofyoflinewidth*strfamily[24]*vfont*vfontb*vfonti*vfontbisepchartotboxactbox*tbselstartselend*strinfocurinfoname[128]maxrcttotrctvartypetotvertipoextraprtbitmaskslide_minslide_max*drivereffect*mface*mtface*tface*mvert*medge*dvert*mcol*msticky*texcomesh*mselect*oc*sumohandlevdataedatafdatatotedgetotfacetotselectcubemapsizesmoothreshsubdivsubdivrsubsurftype*mr*pv*tpageuv[4][2]col[4]transptileunwrapv1v2v3v4edcodecreasedef_nr*dwtotweightco[3]no[3]co[2]indexv[4]midchildrenstartpad[2]v[2]*verts*faces*colfaces*edges*vert_edge_map*vert_face_map*map_memlevelslevel_countcurrentnewlvledgelvlpinlvlrenderlvluse_col*edge_flags*edge_creases*vert_map*edge_map*old_faces*old_edges*errormodifiersubdivTyperenderLevels*emCache*mCachedefaxispad[6]startlengthrandomizeseed*start_cap*end_cap*curve_ob*offset_oboffset[3]scale[3]merge_distfit_typeoffset_typecountaxistolerancesplit_angle*texturestrengthdirectiondefgrp_name[32]midleveltexmapping*map_objectuvlayer_name[32]uvlayer_tmp*projectors[10]*imagenum_projectorsaspectxaspectypercentfaceCountfacrepeat*objectcenterstartxstartyheightnarrowspeeddamptimeoffslifetimedeformflagparentinv[4][4]cent[3]falloff*indexartotindexforceoperationpntswopntsuopntsvopntswtypeutypevtypewfufvfwdudvdw*defvec[8][3]dvec[3]max**obpartypepar1par2par3parsubstr[32]*track*proxy*proxy_group*proxy_from*action*poseconstraintChannelsnetworkdefbasemodifiersdloc[3]orig[3]dsize[3]drot[3]dquat[4]obmat[4][4]laycolbitstransflagipoflagtrackflagupflagnlaflagprotectflagipowinscaflagscavisflagboundtypedupondupoffdupstadupendsfctimemassdampinginertiaformfactorrdampingsizefacdtdtxactcolempty_drawtypepad1[7]empty_drawsizepropsensorscontrollersactuatorsbbsize[3]actdefgameflaggameflag2softflaganisotropicFriction[3]constraintsnlastripshooks*pd*soft*dup_groupfluidsimFlagrestrictflagshapenrshapeflagrecalcopad4*fluidsimSettings*derivedDeform*derivedFinallastDataMaskcurindexactivedeflectforcefieldpdef_damppdef_rdamppdef_permf_strengthf_powermaxdistpdef_sbdamppdef_sbiftpdef_sbofttotpointtotspring*bpoint*bspringnodemassgravmediafrictrklimitphysics_speedgoalspringgoalfrictmingoalmaxgoaldefgoalvertgroupfuzzynessinspringinfrictefraintervallocalsolverflags**keystotpointkeysecondspringcolballballdampballstiffsbc_modeaeroedgeminloopsmaxloopschokepad5*scratchshow_advancedoptionsresolutionxyzpreviewresxyzrealsizeguiDisplayModerenderDisplayModeviscosityValueviscosityModeviscosityExponentgravxgravygravzanimStartanimEndgstarmaxRefineiniVelxiniVelyiniVelz*orgMesh*meshSurface*meshBBsurfdataPath[240]bbStart[3]bbSize[3]typeFlagsdomainNovecgenvolumeInitTypepartSlipValuegenerateTracersgenerateParticlessurfaceSmoothingsurfaceSubdivsunusedDNADummyparticleInfSizeparticleInfAlphafarFieldSize*meshSurfNormalsmistypehorrhorghorbhorkzenrzengzenbzenkambkfastcolexposureexprangelinfaclogfacgravityactivityBoxRadiusskytypephysicsEnginemisimiststamistdistmisthistarrstargstarbstarkstarsizestarmindiststardiststarcolnoisedofstadofenddofmindofmaxaodistaodistfacaoenergyaobiasaomodeaosampaomixaocolor*aosphere*aotableshemiresmaxiterdrawtypesubshootpsubshootenodelimmaxsublamppamapamielmaelmimaxnodeconvergenceradfacgammaselcolsxsy*lpFormat*lpParmscbFormatcbParmsfccTypefccHandlerdwKeyFrameEverydwQualitydwBytesPerSeconddwFlagsdwInterleaveEveryavicodecname[128]*cdParms*padcdSizeqtcodecname[128]codecaudio_codecvideo_bitrateaudio_bitrategop_sizerc_min_raterc_max_raterc_buffer_sizemux_packet_sizemux_ratemixratemainpad[3]*mat_override*light_overridelayflagpassflagpass_xor*avicodecdata*qtcodecdataffcodecdatacfrapsfrapefraimagesframaptothreadsframelenblurfacedgeRedgeGedgeBfullscreenxplayyplayfreqplayattribrt1rt2stereomodedimensionspresetmaximsizexschyschxaspyaspxpartsypartswinposplanesimtypesubimtypequalityscemoderendererocresrpad[2]alphamodeosafrs_secedgeintsafetyborderdisprectlayersactlaygausspostmulpostgammaposthuepostsatdither_intensitybake_osabake_filterbake_modebake_flagGIqualityGIcacheGImethodGIphotonsGIdirectYF_AAYFexportxmlYF_nobumpYF_clamprgbyfpad1GIdepthGIcausdepthGIpixelspersampleGIphotoncountGImixphotonsGIphotonradiusYF_numprocsYF_raydepthYF_AApassesYF_AAsamplesGIshadowqualityGIrefinementGIpowerGIindirpowerYF_gammaYF_exposureYF_raybiasYF_AApixelsizeYF_AAthresholdbackbuf[160]pic[160]ftype[160]col[3]framename[64]*brushtoolcornertypeeditbutflagjointrilimitdegrstepturnextr_offsdoublimitsegmentsringsverticesunwrapperuvcalc_radiusuvcalc_cubesizeuvcalc_mapdiruvcalc_mapalignuvcalc_flagimapaintselect_threshclean_threshretopo_moderetopo_paint_toolline_divellipse_divretopo_hotspotmultires_subdiv_typepad4[2]dirairbrushview*sessiondrawbrushsmoothbrushpinchbrushinflatebrushgrabbrushlayerbrushflattenbrushbrush_typetexnrtexrepttexfadetexsepaveragingdraw_flagtablet_sizetablet_strengthsymm*camera*world*setbase*basactcursor[3]twcent[3]twmin[3]twmax[3]editbutsizeselectmodeproportionalprop_mode*ed*radioframing*toolsettingsaudiomarkersjumpframe*theDagdagisvaliddagflagssculptdatazoomblendximyimspacetypeblockscale*areablockhandler[8]viewmat[4][4]viewinv[4][4]persmat[4][4]persinv[4][4]winmat1[4][4]viewmat1[4][4]viewquat[4]zfacpad0persp*ob_centre*bgpic*localvd*ri*retopo_view_data*depthsob_centre_bone[32]localviewlayactscenelockaroundcamzoompivot_lastgridgridviewpixsizenearfarcamdxcamdygridlinesviewbutgridflagmodeselecttwtypetwmodetwflagtwdrawflagtwmat[4][4]clip[4][4]*clipbbafterdrawzbufxrayflag2gridsubdivsnap_target*properties_storageverthormaskmin[2]max[2]minzoommaxzoomscrollkeeptotkeepaspectkeepzoomoldwinxoldwinyrowbutv2d*editipoipokeyactname[32]constname[32]totipopinbutofschannellockmedian[3]cursenscuractaligntabomainbmainbo*lockpointexfromshowgroupmodeltypescriptblockre_alignoldkeypresstab[7]chanshown*filelisttotfiletitle[24]dir[160]file[80]ofssortmaxnamelencollums*libfiledataretvalmenuact(*returnfunc)()(*returnfunc_event)()(*returnfunc_args)()*arg1*arg2*menup*pupmenuoopsvisiflagtree*treestoresearch_string[32]search_tsesearch_flagsdo_outlinevisstoreflagdeps_flags*cumapimanrcurtileimtypenrshowsparecentxcenty*info_str*info_spare*spare*texttopviewlinesfont_idlheightleftshowlinenrstabnumbercurrtab_setshowsyntaxunused_paddpix_per_linetxtscrolltxtbar*script*but_refsredraws*idaspect*curfont*edittreetreetypetitle[28]fasesubfasemouse_move_redrawimafasemxmydirslidirsli_linesdirsli_sxdirsli_eydirsli_exdirsli_himaslifileselmenuitemimasli_sximasli_eyimasli_eximasli_hdssxdssydsexdseydesxdesydeexdeeyfssxfssyfsexfseydsdhfsdhfesxfesyfeexfeeyinfsxinfsyinfexinfeydnsxdnsydnwdnhfnsxfnsyfnwfnhfole[128]dor[128]file[128]dir[128]*firstdir*firstfiletopdirtotaldirshilitetopfiletotalfilesimage_sliderslider_heightslider_spacetopimatotalimacurimaxcurimay*first_sel_ima*hilite_imatotal_selectedima_redraw*cmapoutline[4]neutral[4]action[4]setting[4]setting1[4]setting2[4]num[4]textfield[4]textfield_hi[4]popup[4]text[4]text_hi[4]menu_back[4]menu_item[4]menu_hilite[4]menu_text[4]menu_text_hi[4]but_drawtypeiconfile[80]back[4]header[4]panel[4]shade1[4]shade2[4]hilite[4]grid[4]wire[4]select[4]lamp[4]active[4]group[4]group_active[4]transform[4]vertex[4]vertex_select[4]edge[4]edge_select[4]edge_seam[4]edge_sharp[4]edge_facesel[4]face[4]face_select[4]face_dot[4]normal[4]bone_solid[4]bone_pose[4]strip[4]strip_select[4]vertex_sizefacedot_sizebpad[2]syntaxl[4]syntaxn[4]syntaxb[4]syntaxv[4]syntaxc[4]movie[4]image[4]scene[4]audio[4]effect[4]plugin[4]transition[4]meta[4]bpad1[4]tuitbutstv3dtfiletipotinfotsndtacttnlatseqtimatimaseltexttoopsttimetnodebpad[4]spec[4]dupflagsavetimetempdir[160]fontdir[160]renderdir[160]textudir[160]plugtexdir[160]plugseqdir[160]pythondir[160]sounddir[160]yfexportdir[160]versionsvrmlflaggameflagswheellinescrolluiflaglanguageuserprefviewzoomconsole_bufferconsole_outmixbufsizefontsizeencodingtransoptsmenuthreshold1menuthreshold2fontname[256]themesundostepscurssizetb_leftmousetb_rightmouselight[3]tw_hotspottw_flagtw_handlesizetw_sizetextimeouttexcollectratememcachelimitframeserverportpad_rot_angleobcenter_diarvisizervibrightversemaster[160]verseuser[160]recent_filessmooth_viewtxvertbaseedgebaseareabase*sceneendxendysizexsizeyscenenrscreennrfullmainwinwinakthandler[8]*newvvec*v1*v2panelname[64]tabname[64]drawname[64]ofsxofsycontrolsnapold_ofsxold_ofsysortcounter*paneltab*v3*v4*fullwinmat[4][4]headrctwinrctheadwinwinheadertypebutspacetypewinxwinyhead_swaphead_equalwin_swapwin_equalheadbutlenheadbutofscursorspacedatauiblockspanelssubvstr[4]subversionpadsminversionminsubversiondisplaymode*curscreen*curscenefileflagsglobalfname[80]*ibuf*se1*se2*se3nrdone*stripdataorxory*instance_private_data**current_private_data*newseqstartofsendofsstartstillendstillmachinestartdispenddispmulhandsize*strip*curelemfacf0facf1*seq1*seq2*seq3seqbase*sound*hdaudiolevelpancurposstrobe*effectdataanim_preseek*oldbasep*parseq*seqbasepmetastackedgeWidthforwardwipetypefMinifClampfBoostdDistdQualitybNoCompScalexIniScaleyIniScalexFinScaleyFinxInixFinyIniyFinrotInirotFin*frameMapglobalSpeedbuttypeuserjitstaendtotpartnormfacobfacrandfactexfacrandlifeforce[3]vectsizemaxlendefvec[3]mult[4]life[4]child[4]mat[4]texmapcurmultstaticstepomattimetexspeedtexflag2negvertgroup_vvgroupname[32]vgroupname_v[32]*keysminfacusedusedelemdxdylinkotypeold*poin*oldpoinresetdistlastval*makeyqualqual2targetName[32]toggleName[32]value[32]maxvalue[32]materialName[32]damptimerdelaypropname[32]matname[32]axisflag*fromObjectsubject[32]body[32]pulsefreqtotlinks**linksinvertfreq2axisfbuttonbuttonfhathatfprecisionstr[128]*mynewinputstotslinks**slinksvalotime*actblendinprioritystrideaxisstridelengthsndnrpad1[2]makecopycopymadepad2[1]trackvolume*melinVelocity[3]localflagforceloc[3]forcerot[3]linearvelocity[3]angularvelocity[3]butstabutendminvisifacslowminloc[3]maxloc[3]minrot[3]maxrot[3]distributionint_arg_1int_arg_2float_arg_1float_arg_2toPropName[32]*toObjectbodyTypefilename[64]loadaniname[64]goaccellerationmaxspeedmaxrotspeedmaxtiltspeedrotdamptiltdampspeeddamp*sample*stream*newpackedfile*snd_soundpanningattenuationpitchmin_gainmax_gaindistancestreamlenchannelshighpriopad[10]gaindopplerfactordopplervelocitynumsoundsblendernumsoundsgameengine*lamprengobjectchildbaserollhead[3]tail[3]bone_mat[3][3]arm_head[3]arm_tail[3]arm_mat[4][4]xwidthzwidthease1ease2rad_headrad_tailbonebasechainbasepathflaglayer_protectedghostepghostsizeghosttypepathsizeghostsfghostefpathsfpathefconstflagikflagselectflag*bone*childiktree*b_bone_matschan_mat[4][4]pose_mat[4][4]pose_head[3]pose_tail[3]limitmin[3]limitmax[3]stiffness[3]ikstretch*customchanbaseproxy_layerstride_offset[3]cyclic_offset[3]reserved1autosnapactnractwidthtimeslidename[30]enforce*tariterationsrootbonesubtarget[32]orientweightgrabtarget[3]reserved2minmaxflagstickystuckcache[3]lockflagfollowflagzminzmaxvolmodeplaneorglengthbulgepivXpivYpivZaxXaxYaxZminLimit[6]maxLimit[6]extraFzchannel[32]no_rot_axisstride_axiscurmodactstartactendactoffsstridelenblendoutstridechannel[32]offs_bone[32]hasinputhasoutputdatatypesockettypenslimitstack_indexinternstack_index_extlocxlocyown_indexto_index*tosock*link*new_nodelastyoutputs*storageminiwidthcustom1custom2need_execexectotrbutrprvr*typeinfo*fromnode*tonode*fromsocknodeslinks**stackinitstacksizecur_indexalltypes*owntype(*timecursor)()(*stats_draw)()(*test_break)()cyclicmoviesamplesminspeedbokehhuesatt1t2t3fstrengthfalphakey[4]colname[32]bktyperotationpreviewgamcono_zbuffstopmaxblurbthreshshortymintablemaxtableext_in[2]ext_out[2]*curve*table*premultablecurrcliprcm[4]black[3]white[3]bwmul[3]offset[2]innerradiusratergb[3]cloneactive_rndpad[4]*layerstotlayermaxlayertotsizeTYPEcharucharshortushortintlongulongfloatdoublevoidLinkListBasevec2svec2ivec2fvec2dvec3ivec3fvec3dvec4ivec4fvec4drctirctfIDPropertyDataIDPropertyIDLibraryFileDataIpoKeyBlockKeyScriptLinkTextLineTextPackedFileCameraPreviewImageImageUserImageanimRenderResultMTexObjectTexPluginTexCBDataColorBandEnvMapImBufTexMappingLampWaveMaterialbNodeTreeGroupVFontVFontDataMetaElemBoundBoxMetaBallBezTripleBPointNurbCharInfoTextBoxCurvePathIpoDriverIpoCurveMeshMFaceMTFaceTFaceMVertMEdgeMDeformVertMColMStickyMSelectOcInfoCustomDataMultiresPartialVisibilityMDeformWeightMultiresColMultiresColFaceMultiresFaceMultiresEdgeMultiresLevelMultiresMapNodeModifierDataSubsurfModifierDataLatticeModifierDataCurveModifierDataBuildModifierDataArrayModifierDataMirrorModifierDataEdgeSplitModifierDataDisplaceModifierDataUVProjectModifierDataDecimateModifierDataSmoothModifierDataCastModifierDataWaveModifierDataArmatureModifierDataHookModifierDataSoftbodyModifierDataBooleanModifierDataLatticebDeformGroupLBufbActionbPosePartDeflectSoftBodyFluidsimSettingsDerivedMeshObHookSBVertexBodyPointBodySpringSBScratchWorldRadioBaseAviCodecDataQuicktimeCodecDataFFMpegCodecDataAudioDataSceneRenderLayerRenderDataGameFramingTimeMarkerImagePaintSettingsBrushToolSettingsBrushDataSculptDataSculptSessionSceneDagForestBGpicView3DSpaceLinkScrAreaRenderInfoRetopoViewDataViewDepthsView2DSpaceInfoSpaceIpoSpaceButsSpaceSeqSpaceFiledirentryBlendHandleSpaceOopsTreeStoreTreeStoreElemSpaceImageCurveMappingSpaceNlaSpaceTextSpaceScriptScriptSpaceTimeSpaceNodeSpaceImaSelImaDirOneSelectableImaThemeUIThemeSpacebThemeSolidLightUserDefbScreenScrVertScrEdgePanelFileGlobalStripElemStripPluginSeqSequencebSoundhdaudioMetaStackEditingWipeVarsGlowVarsTransformVarsSolidColorVarsSpeedControlVarsEffectBuildEffPartEffParticleWaveEffOopsbPropertybNearSensorbMouseSensorbTouchSensorbKeyboardSensorbPropertySensorbCollisionSensorbRadarSensorbRandomSensorbRaySensorbMessageSensorbSensorbControllerbJoystickSensorbExpressionContbPythonContbActuatorbAddObjectActuatorbActionActuatorbSoundActuatorbCDActuatorbEditObjectActuatorbSceneActuatorbPropertyActuatorbObjectActuatorbIpoActuatorbCameraActuatorbConstraintActuatorbGroupActuatorbRandomActuatorbMessageActuatorbGameActuatorbVisibilityActuatorFreeCamerabSamplebSoundListenerSpaceSoundGroupObjectBonebArmaturebPoseChannelbActionChannelSpaceActionbConstraintChannelbConstraintbKinematicConstraintbTrackToConstraintbRotateLikeConstraintbLocateLikeConstraintbMinMaxConstraintbSizeLikeConstraintbActionConstraintbLockTrackConstraintbFollowPathConstraintbDistanceLimitConstraintbRotationConstraintbStretchToConstraintbLocLimitConstraintbRotLimitConstraintbSizeLimitConstraintbRigidBodyJointConstraintbClampToConstraintbActionModifierbActionStripbNodeStackbNodeSocketbNodeLinkbNodebNodePreviewbNodeTypeNodeImageAnimNodeBlurDataNodeHueSatNodeImageFileNodeChromaNodeGeometryNodeVertexColNodeDefocusCurveMapPointCurveMapBrushCloneCustomDataLayerTLEN  L4(Thxh tx T8pDDlh8$88\,< @ @ 44DX`Dt<<<\h`4@t( <(,((0@XP Lt<$x$(h x$ 8x h (88,@0,HhH,(lDLP@< <@Lh48<8l(DlP<,4D4,,D,@,<4` <$t (@  ,<STRC                 !"#$ %&'( )*+, -./01 234* 56789 :;<=!!!>?@" ABC D!E!FGHIJK L#MNB -$OPQRSTUVWXYZ[\6 ]%^_& `abcdefghij'! k(l)mfnopqrstuvwx#y%z{|}~ *+,-   .)&/#&.0+'1QRfp,4dabc&6'-/02+34QR   * 6 ]465p  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI/J/KLMNOPQRS* 6T67UVWXYZ[\]^_`abcdefghijklmno ]8pq9-#y:::;rstuvwxyz{|}~<;r  65= >???>=@\A^B9;r  +++6C5 \D)8888A@@D+'+EEE>='+  *DF);r 65GHIJKLMNFOP QQQ\RS I GKTLTJMNOH'UVUWX Y YYJ W V X   ZR QQSGK[[[\[ !"B # $][ +^[ +%&_[ '()*` [ +++,+-+./0(123B4a[ 56b[ 7Bc [ ,89:;<=+>?@d [ +A'BBCDE?@e[ FGf[ H;Ig[ +HM;h[ +J;,8+>KLMNOP=@?QRi[ So\+;j [ +TUVWXYk[ l[ +Zm[\]^\_`abcdefg>h6Lnnn;iPjo#k+l+gmnopq+$+r+s+t+u6C;rpvqw - x  y  z {5|}~{T ]        rs7tuu vvv+$TUVWXYr ws(xycw8Qzt(FFF6     J{9 !"#$%&'()*+,-./0123456789:;<=6*  ]|>?@ABCDEFGHIJKL}}}MNO+~ P QRSTUVWXYZ[ \ ]^\_ `abcdBefghijkl 5m7nopqe~rstucvwxyz{|}~M \o\QQ\M9* %+{' }     >6T |  ] o\Q '&MD !"#$%&'()*+++,-./01@234567oS89:;<=>?@ABjCDEFGH;I JKLMNO\ P#&QRSTUVWXYZ[\]   ^\_ ` a67bcdefg('jhi#. jklm_njeo pqrstuvw _nx\ yz{|}~      _ e p  _'B&jh\1  jh_ "Bj Bjo __7j 6T6Q\1       l0   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ@R4STUVWXYZ[\]^_`abcdefghijklmn opqrstuvwxyz{|}~&   KL  ]      1f | p     ) 'c6(l      P B(c-R8*   P  M7UKLMNOPQR, - !" # $% & '()o\5*+,-./0123P\P5*456o7+89:$;<=o\ ->+?@ 5ABCDEFG"HI=$J\Q ->KLM+ pNOPQR STUVWSXY M+FZ[\+0+ ]^|_` o&ab+MckH5dPefghi l&ab7U*jklmn5o+p9qo\:rs H$t -+ uvwxyz{| }#y#~ 6YB_Sh\+ 7 h$ (h  @Sh \$  {+q 6 xp  _pveh6 - ++B++ +bo\+ +'ckpN++b+o\/   +   M   o   o++o\+ +6pN+';IO {ck -   o      j I   z           6       ac voHL\p`c !"#$ %&'()*+,q- ./01234 &56789:;'B; M<=>* ?b@A -QBCDEENDBspe-0.8.4.h/_spe/info.py0000644000175000017500000001437211003655422014016 0ustar stanistaniimport os,sys PLATFORM = sys.platform WIN = PLATFORM.startswith('win') DARWIN = PLATFORM.startswith('darwin') LINUX = not (WIN or DARWIN) if WIN: windowsVer = sys.getwindowsversion() if (windowsVer[3] == 1 ): WIN98 = True else: WIN98 = False else: WIN98 = False PYTHON_EXEC = sys.executable if WIN: if PYTHON_EXEC.endswith('w.exe'): PYTHON_EXEC = PYTHON_EXEC[:-5] + '.exe' try: import win32api PYTHON_EXEC = win32api.GetShortPathName(PYTHON_EXEC) PYTHON_COM = True except ImportError: PYTHON_EXEC = (r'%s'%PYTHON_EXEC).replace('Program Files','progra~1') PYTHON_COM = False if ' ' in PYTHON_EXEC: PYTHON_EXEC = '"%s"'%PYTHON_EXEC elif DARWIN: pythonw = PYTHON_EXEC.replace('ython','ythonw') if os.path.exists(pythonw): PYTHON_EXEC = pythonw PYTHON_COM = False else: PYTHON_COM = False PATH = os.path.dirname(__file__) _PATH = os.path.dirname(PATH) def path(p): if (WIN or LINUX) and ' ' in p: return '"%s"'%p else: return p #---Append sm if PATH not in sys.path: sys.path.insert(0,PATH) if _PATH not in sys.path: sys.path.insert(0,_PATH) import sm.osx INFO={ 'author' : "www.stani.be", 'author_email' : 'spe.stani.be@gmail.com', 'blenderVersion' : "2.35", 'date' : "27-10-2005", 'donate' : "If you enjoy SPE, consider a (small) donation.", 'doc' : "%(titleFull)s\n\n%(description)s\n\n%(links)s\n\n%(requirements)s\n\n%(copyright)s", 'forums' : '', 'license' : 'GPL', 'location' : PATH, 'pyVersion' : "2.3", 'pyVersionC' : sys.version.split(' ')[0], 'scripts' : ['spe','spe_wininst.py'], 'skinLocation' : os.path.join(PATH,'skins','default'), 'smLocation' : os.path.join(PATH,'sm'), 'title' : "SPE", 'url' : 'http://pythonide.stani.be', 'userPath' : sm.osx.userPath('.spe'), 'version' : "0.8.4.h", 'wxVersion' : "2.6.1.0.", } INFO['defaults'] = os.path.join(INFO['location'],'defaults.cfg') INFO['defaultsUser'] = os.path.join(INFO['userPath'],'defaults.cfg') INFO['defaultWorkspace'] = os.path.join(INFO['userPath'],'defaults.sws') INFO['titleFull'] = "%(title)s %(version)s"%INFO if DARWIN: INFO['python'] = 'pythonw' else: INFO['python'] = 'python' INFO['links'] =\ """Homepage : %s Donwloads: http://www.stani.be/python/spe/page_blender Forum : http://www.stani.be/python/spe/page_forum Lists : http://www.stani.be/python/spe/page_mailman"""%INFO['url'] INFO['description'] =\ """Stani's Python Editor Spe is a python IDE with auto-indentation, auto completion, call tips, syntax coloring, syntax highlighting, class explorer, source index, auto todo list, sticky notes, integrated pycrust shell, python file browser, recent file browser, drag&drop, context help, ... Special is its blender support with a blender 3d object browser and its ability to run interactively inside blender. Spe is extensible with boa. Wanted: wxpython programmers to extend spe's features, feel free to do a proposal. For more information, see spe/doc/manual.html"""%INFO INFO['requirements'] =\ """Python v%(pyVersion)s required wxPython v%(wxVersion)s required Blender v%(blenderVersion)s optional"""%INFO INFO['copyright'] =\ """Copyright (C)%(author)s (%(date)s) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """%INFO INFO['contribute'] = """There are different ways to contribute: - %s (or convince your boss) - Let your company sponsor SPE (see manual) - SPE needs documentation writers and screenshot takers for manual - Contribute code (eg wxPython panels) & patches - Promote SPE in newsgroups, press, blogs, ... - Subscribe to mailing lists - Translate manual - Report bugs in the bug tracker"""%INFO['donate'] WILDCARD = "Python (*.py;*.pyw;*.tpy)|*.py;*.pyw;*.tpy|Backup files (*.bak)|*.bak|All files (*)|*" WORKSPACE_WILDCARD = "SPE Workspace (*.sws)|*.sws|All files (*)|*" WILDCARD_EXTENDED = WILDCARD+'|Python All(*.py;*.pyw;*.tpy;*.pyc;*.pyd;*.pyo)|*.py;*.pyw;*.tpy;*.pyc;*.pyd;*.pyo|Text (*.txt;*.rtf;*.htm;*.html;*.pdf;*.cfg)|*.txt;*.rtf;*.htm;*.html;*.pdf;*.cfg|Bitmap (*.jpg;*.jpeg;*.bmp;*.tif;*.tiff;*.png;*.pic)|*.jpg;*.jpeg;*.bmp;*.tif;*.tiff;*.png;*.pic|Vector (*.dxf;*.dwg;*.svg;*.swf;*.vrml;*.wrl)|*.dxf;*.dwg;*.svg;*.swf;*.vrml;*.wrl' __doc__=INFO['doc']%INFO def copy(): return INFO.copy() def dirname(fileName): fileName = os.path.dirname(fileName) if PYTHON_COM: return win32api.GetShortPathName(fileName) else: return fileName def imageFile(fileName): return os.path.join(INFO['skinLocation'],fileName) #---wx try: import wx INFO['wxVersionC'] = wx.VERSION_STRING ## if INFO['wxVersionC']!=INFO['wxVersion']: ## print '\nSpe Warning: Spe was developped on wxPython v%s, but v%s was found.'%(INFO['wxVersion'],INFO['wxVersionC']) ## print 'If you experience any problems please install wxPython v%s\n'%INFO['wxVersion'] INFO['encoding'] = wx.GetDefaultPyEncoding() WX_ERROR = False except ImportError, message: print "Spe Error: Please install the right version of wxPython: %s"%INFO['wxVersion'] print message WX_ERROR = True spe-0.8.4.h/_spe/Child.wxg0000644000175000017500000001006210331016126014246 0ustar stanistani wxHORIZONTAL wxEXPAND 0 wxSPLIT_VERTICAL main notebook Explore Browser Todo Index Notes Check $parent $id $parent $id $parent $id Source Uml $parent $id $parent $id spe-0.8.4.h/_spe/Blender_signature.py0000644000175000017500000000104210707132351016506 0ustar stanistani#!BPY #""" #Name: '%(Command)s' #Blender: %(Blender version)d #Group: 'Misc' #Tooltip: 'A script written by %(User)s' #""" __author__ = "%(User)s" __url__ = ("http://www.blender.org") __version__ = "1.00" __bpydoc__ = """\ Here you can put a detailed description of the script for the user - about its features and usage. Blender users will see it at the window opened by 'Help'-->'Scripts Help browser' command. P.S. notice that you have two ways of forcing a line break in this docstring:
- an empty line
- a tag:
""" spe-0.8.4.h/_spe/Menu.wxg0000644000175000017500000010576410772170467014167 0ustar stanistani wx.ID_NEW menu_new wx.ID_OPEN menu_open_files wx.ID_SAVE menu_save wx.ID_SAVEAS menu_save_as SAVE_COPY menu_save_copy --- --- OPEN_WORKSPACE menu_open_workspace SAVE_WORKSPACE menu_save_workspace SAVE_WORKSPACE_AS menu_save_workspace_as --- --- SAVE_UML_AS menu_save_uml_as PRINT_UML_SETUP menu_print_uml_setup PRINT_UML_PREVIEW menu_print_uml_preview PRINT_UML menu_print_uml --- --- wx.ID_CLOSE menu_close wx.ID_EXIT menu_exit --- --- REMEMBER_OPEN_FILES 1 menu_remember_open_files wx.ID_UNDO menu_undo wx.ID_REDO menu_redo --- --- CUT menu_cut COPY menu_copy PASTE menu_paste --- --- EXECUTE menu_execute --- --- wx.ID_REPLACE menu_find__replace wx.ID_FIND menu_find_next GO_TO_LINE menu_go_to_line BROWSE_SOURCE menu_browse_source AUTO_COMPLETE menu_auto_complete SHOW_DOCSTRING menu_show_docstring --- --- INDENT menu_indent DEDENT menu_dedent COMMENT menu_comment UNCOMMENT menu_uncomment --- --- INSERT_SEPARATOR menu_insert_separator INSERT_SIGNATURE menu_insert_signature --- --- PREFERENCES menu_preferences WHITESPACE 1 menu_whitespace INDENTATION_GUIDES 1 menu_indentation RIGHT_EDGE_INDICATOR 1 menu_right_edge_indicator END_OF_LINE_MARKER 1 menu_end_of_line_marker --- --- AS_NOTEBOOK menu_as_notebook AS_COLUMNS menu_as_columns AS_ROWS menu_as_rows --- --- SIDEBAR 1 menu_sidebar SHELL 1 menu_shell --- --- CLEAR_OUTPUT menu_clear_output REFRESH menu_refresh RUN menu_run RUN_WITHOUT_ARGUMENTS menu_run_without_arguments --- --- RUN_DEBUG menu_run_debug DEBUG menu_debug --- --- RUN_TERMINAL menu_run_terminal RUN_TERMINAL_WITHOUT_ARGUMENTS menu_run_terminal_without_arguments RUN_TERMINAL_WITHOUT_ARGUMENTS_EXIT menu_run_terminal_without_arguments_exit --- --- IMPORT menu_import --- --- BROWSE_OBJECT_WITH_PYFILLING menu_browse_object_with_pyfilling TEST_REGULAR_EXPRESSION_WITH_KIKI menu_test_regular_expression_with_kiki DESIGN_A_GUI_WITH_WXGLADE menu_design_a_gui_with_wxglade DESIGN_A_GUI_WITH_XRC menu_design_a_gui_with_xrc CHECK_SOURCE_WITH_PYCHECKER menu_check_source_with_pychecker --- --- BROWSE_FOLDER menu_browse_folder OPEN_TERMINAL_EMULATOR menu_open_terminal_emulator LOAD_IN_BLENDER menu_load_in_blender REFERENCE_IN_BLENDER menu_reference_in_blender --- --- REDRAW_BLENDER_WINDOW --- --- BLENDER_PYTHON_MANUAL menu_blender_python_manual BLENDER_PYTHON_TUTORIAL menu_blender_python_tutorial --- --- BLENDER_HOMEPAGE menu_blender_homepage DOWNLOAD_BLENDER menu_download_blender FORUM_BLENDER_PYTHON menu_forum_blender_python FORUM_ELYSIUN_PYTHON menu_forum_elysiun_python --- --- ADD_SPE_TO_BLENDER menu_add_spe_to_blender SPE_HOMEPAGE menu_spe_homepage FORUM_SPE menu_forum_spe --- --- PYTHON_HOMEPAGE PYTHON_ANNOUNCEMENTS menu_python_announcements PYTHON_COOKBOOK menu_python_cookbook PYTHON_DAILY menu_python_daily PYTHON_PACKAGE_INDEX menu_python_package_index --- --- AUTHORS_HOMEPAGE menu_authors_homepage NEXT menu_next PREVIOUS menu_previous MANUAL menu_manual KEYBOARD_SHORTCUTS menu_keyboard_shortcuts --- --- PYTHON_LIBRARY menu_python_library PYTHON_REFERENCE menu_python_reference PYTHON_DOCUMENTATION_SERVER menu_python_documentation_server --- --- WXGLADE_MANUAL menu_wxglade_manual WXGLADE_TUTORIAL menu_wxglade_tutorial WXWINDOWS_DOCUMENTATION menu_wxwindows_documentation --- --- DONATE menu_donate ABOUT menu_about #FFFFFF wxVERTICAL 0 1 skins/default/blenpy.png wxEXPAND 0 0 1 2 0 0 Previous window | Ctrl+Shift+` #ffffff skins/default/tab_left.png evt_previous 0 Next window | Ctrl+` #ffffff skins/default/tab_right.png evt_next 0 Find & replace... | Ctrl+F #ffffff skins/default/viewmag.png evt_find 0 Go to line... | Ctrl+G #ffffff skins/default/goto.png evt_goto 0 Browse source | Ctrl+Enter #ffffff skins/default/thumbnail.png evt_browse_source 0 Check source with pychecker | Ctrl+Alt+C #ffffff skins/default/pychecker.png evt_check 0 Dedent | Shift+Tab #FFFFFF skins/default/dedent.png evt_dedent 0 Indent | Tab #FFFFFF skins/default/indent.png evt_indent 0 Comment | Alt+3 #FFFFFF skins/default/comment.png evt_comment 0 Uncomment | Alt+4 #FFFFFF skins/default/uncomment.png evt_uncomment 0 Run | F9 #FFFFFF skins/default/run.png evt_run 0 Import | F10 #FFFFFF skins\default\import.png evt_import 0 Show/hide sidebar | F11 #ffffff skins/default/view_left_right.png evt_sidebar 0 Run verbose | Ctrl+Alt+R #ffffff skins/default/debug.png evt_run_verbose 0 Show/hide shell | F12 #ffffff skins/default/view_top_bottom.png evt_shell 0 Please donate, if you enjoy SPE. #ffffff skins/default/donate.png evt_donate spe-0.8.4.h/_spe/Parent_notes.txt0000644000175000017500000000070510366063006015710 0ustar stanistani+wxGlade manual entry in help menu +open terminal emulator fix +browse folder +lege seperators voorkomen +find dialog +internet explorer activex wxhtmlwindow +improved retrieval of wxwindows documentation windows menu for mac & hide tabs configurable keyboard shortcuts beter systeem voor children, met remove, nu probleem child kan al dood zijn scrollbar py2exe BUGS right click menu unicode savingspe-0.8.4.h/_spe/MenuEditor.wxg0000644000175000017500000001103410272471120015301 0ustar stanistani 771, 274 wxVERTICAL wxEXPAND 0 10 773, 235 Label Shortcut Icon Action 0 wxGrid.wxGridSelectRows 1 1 1 1 0 1 wxALL|wxEXPAND 4 4 1 4 7 4 0 0 0 0 0 20 20 0 0 spe-0.8.4.h/_spe/__init__.py0000644000175000017500000000030610341631472014615 0ustar stanistani##import info ##INFO=info.copy() ##INFO['description']=\ ##"""This is the main spe application.""" ##__doc__=INFO['doc']%INFO def main(): import SPE if __name__ == '__main__': main() spe-0.8.4.h/_spe/wxgChild.py0000644000175000017500000000372610754716453014653 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4cvs on Fri Jul 22 01:44:22 2005 import wx class Panel(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: Panel.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.split = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_BORDER) self.main = wx.Notebook(self.split, -1, style=0) self.notebook = wx.Notebook(self.split, -1, style=0) self.explore = Tree(self.notebook, -1) self.browser = Browser(self.notebook, -1) self.todo = wx.ListCtrl(self.notebook, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.index = wx.ListCtrl(self.notebook, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.notes = wx.TextCtrl(self.notebook, -1, "") self.pychecker = Pycheck.Panel(self.notebook, -1) self.sash = PythonSTC(self.main, -1) self.uml = sm.uml.Canvas(self.main, -1) self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: Panel.__set_properties pass # end wxGlade def __do_layout(self): # begin wxGlade: Panel.__do_layout splitSizer = wx.BoxSizer(wx.HORIZONTAL) self.notebook.AddPage(self.explore, _("Explore")) self.notebook.AddPage(self.browser, _("Browser")) self.notebook.AddPage(self.todo, _("Todo")) self.notebook.AddPage(self.index, _("Index")) self.notebook.AddPage(self.notes, _("Notes")) self.notebook.AddPage(self.pychecker, _("Check")) self.main.AddPage(self.sash, _("Source")) self.main.AddPage(self.uml, _("Uml")) self.split.SplitVertically(self.notebook, self.main) splitSizer.Add(self.split, 1, wx.EXPAND, 0) self.SetAutoLayout(True) self.SetSizer(splitSizer) splitSizer.Fit(self) splitSizer.SetSizeHints(self) # end wxGlade # end of class Panel spe-0.8.4.h/_spe/help.py0000644000175000017500000000471310272471120014007 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Content for context menu.""" __doc__=INFO['doc']%INFO MENU=\ """To add your own menu, see Help>Add menu. See framework/menus/menu_User.py for an example. """ SHELL=\ """Press 'Ctrl-SPACE' in the shell to jump to file and line number after error. Press ESC to clear up the shell. In the next tab 'Locals' you can browse the namespace of this shell. Drag and drop here any files to run.""" LOCALS=\ """Explore objects in the namespace tab. Double click any item to browse in a seperate PyFilling window.""" SESSION=\ """The session tab records the commands of the Shell.""" FIND=\ """Tool to search recursively through text.""" BROWSER=\ """This shows all file of a folder and subfolders. Set depth to the level of nested subfolders. Left click a file to open it. Right click to run it. Drag and drop here any directory to add.""" RECENT=\ """Left click a recent file to open it. Right click to run it. Drag and drop here any files to add.""" TODO=\ """Overview of the todo tasks of all open files. Click to jump to the source location. To add a todo task anywhere in the source code, start a line with '# TODO:' and let it follow by a description of the task. Press F5 or save to refresh.""" INDEX=\ """Alphabetical listing of the defined methods and classes in all open files. Click to jump to the source location. Press F5 or save to refresh.""" NOTES=\ """These notes will always be saved and opened in Spe.""" BLENDER=\ """Blender browser. Choose an item to browse... It is required that you launch spe from Blender and that you have blenpy installed to access this feature.""" CHILD_EXPLORE=\ """Explore the class and method tree of the source code. Right or double click to jump to source code. See Help>Seperators about inserting separators. Press F5 or save to refresh.""" CHILD_TODO=\ """Every comment starting with '# TODO:' will appear here. By adding '!' you can give priority. Click to jump to the source code. Press F5 or save to refresh.""" CHILD_INDEX=\ """Alphabetical listing of the defined methods and classes. Click to jump to the source location. Press F5 or save to refresh.""" CHILD_NOTES=\ """These notes will be saved as 'fileName.txt'. If it is empty, this file will be deleted.""" CHILD_SOURCE=\ """See Help>Shortcuts about keyboard shortcuts. See Help>Seperators about inserting separators.""" spe-0.8.4.h/_spe/spe0000755000175000017500000000005011002645341013210 0ustar stanistani#!/usr/bin/env python import _spe.SPE spe-0.8.4.h/_spe/SPE.pyw0000755000175000017500000000014711002645341013675 0ustar stanistani#!/usr/bin/env python """Shortcut to launch spe in Windows.""" if __name__=='__main__': import SPE spe-0.8.4.h/_spe/defaults.cfg0000644000175000017500000001176510775432035015014 0ustar stanistani[Default] #GENERAL Backup = 1 CheckFileOnSave = 1 Encoding = Mdi = RedirectShell = 1 RecentFileAmount = 100 Redraw = 1 Shortcuts = ShowShell = 1 ShowToolbar = 1 SingleInstanceApp = 0 ToolTipsForFileTabs = 1 version = 0 #EDITOR #general AutoComplete = 1 AutoCompleteIgnore = ['gtk'] AutoReloadChangedFile = 0 CheckSourceRealtime = compiler ExecuteWarning = 1 SaveBeforeRun = 1 AutoUpdateSidebar = 1 CallTips = whole documentation Font = Courier,default MaxChildren = 1 UpdateSidebar = realtime WordChars = _.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 StcStyle = SPE #workspaces globalRecent = 1 globalFolders = 1 globalNotes = 1 globalFileList = 0 SaveOnExit = 1 SaveWorkspaceOnFileSave = 1 CloseChildrenOnNewWorkspace = 1 RememberLastWorkspace = 1 currentworkspace = #tabs & white spaces ConvertTabsToSpaces = 1 UseTabs = 0 StripTrailingSpaces = 0 TabWidth = 4 ViewWhiteSpace = 0 ViewLineNumbers = 1 #guides EdgeColumn = 79 IndentationGuides = 1 ViewEdge = 1 #PATHS #General Signature = #Terminal emulator Terminal = TerminalRun = TerminalRunExit = #Html WebBrowser = PythonDocs = WxPythonDocs = [stc.style.Boa] setting.-2=fore:#000000 setting.-1=fore:#000000,back:#88C4FF style.000=fore:#808080 style.001=fore:#007F00,back:#E8FFE8,italic style.002=fore:#007F7F style.003=fore:#7F007F style.004=fore:#7F007F style.005=fore:#00007F,bold style.006=fore:#7F0000 style.007=fore:#000033,back:#FFFFE8 style.008=fore:#0000FF,bold style.009=fore:#007F7F,bold style.010=bold style.012=fore:#7F7F7F,italic style.013=fore:#000000,back:#E0C0E0,eolfilled style.032=back:%(backcol)s,face:%(mono)s,size:%(size)d style.033=size:%(lnsize)d,face:%(helv)s,back:#A0A0A0 style.034=fore:#0000FF,back:#FFFF88,bold style.035=fore:#FF0000,back:#FFFF88,bold [stc.style.SPE] setting.-2=fore:#000000 setting.-1=fore:#000000,back:#88C4FF style.000=face:%(mono)s,size:%(size)d style.001=fore:#007F00,back:#E8FFE8,italic,size:%(size)d style.002=fore:#007F7F,size:%(size)d style.003=fore:#7F007F,size:%(size)d style.004=fore:#7F007F,size:%(size)d style.005=fore:#00007F,bold,size:%(size)d style.006=fore:#7F0000,size:%(size)d style.007=fore:#7F0000,size:%(size)d style.008=fore:#0000FF,bold,underline,size:%(size)d style.009=fore:#007F7F,bold,size:%(size)d style.010=bold,size:%(size)d style.012=fore:#990000,back:#C0C0C0,italic,size:%(size)d style.013=fore:#000000,back:#E0C0E0,eol,size:%(size)d style.032=face:%(mono)s,size:%(size)d style.033=back:#C0C0C0 style.034=fore:#FFFFFF,back:#0000FF,bold style.035=fore:#000000,back:#FF0000,bold [stc.style.Idle] setting.-2=fore:#000000 setting.-1=fore:#FFFFFF,back:#0000A0 style.001=fore:#DD0000 style.003=fore:#00AA00 style.004=fore:#00AA00 style.005=fore:#FF7700 style.006=fore:#00AA00 style.007=fore:#00AA00 style.008=fore:#0000FF style.009=fore:#0000FF style.012=fore:#DD0000 style.032=face:%(mono)s,size:%(size)d style.033=size:%(lnsize)d,face:%(helv)s,back:#A0A0A0 style.034=fore:#0000FF,bold style.035=fore:#DD0000,bold [stc.style.Twilight] setting.-2=fore:#FFFFFF setting.-1=fore:#000000,back:#888888 style.000=fore:#808080 style.001=fore:#A0A0A0,italic style.002=fore:#FF00FF style.003=fore:#FFFF00 style.004=fore:#FFFF00 style.005=fore:#80FFFF,bold style.006=fore:#00C1C1 style.007=fore:#00C1C1 style.008=fore:#FFFF00,bold style.009=fore:#FFFFFF,bold style.010=bold,fore:#80FFFF style.012=fore:#A0A0A0,italic style.013=fore:#000000,back:#959500,eolfilled style.032=back:#000000,face:%(mono)s,size:%(size)d,fore:#FFFFFF style.033=size:%(lnsize)d,face:%(helv)s,back:#A0A0A0,fore:#000000 style.034=fore:#0000FF,back:#80FFFF,bold style.035=fore:#FF0000,back:#80FFFF,bold [stc.style.Classic] setting.-2=fore:#FFFFFF setting.-1=fore:#000000,back:#888888 style.000=fore:#808080 style.001=fore:#00FF00,italic style.002=fore:#00FFFF style.003=fore:#FF00FF style.004=fore:#FF00FF style.005=fore:#FFFFFF,bold style.006=fore:#FFB7B7 style.007=fore:#D1D1D1 style.008=fore:#79BCFF,bold style.009=fore:#FFFFB9,bold style.010=bold,fore:#FFFFFF style.012=fore:#949494,italic style.013=fore:#000000,back:#CA8BE4,eolfilled style.032=back:#000080,face:%(mono)s,size:%(size)d,fore:#FFFF00 style.033=size:%(lnsize)d,face:%(helv)s,back:#A0A0A0,fore:#000000 style.034=fore:#0000FF,back:#FFFF88,bold style.035=fore:#FF0000,back:#FFFF88,bold spe-0.8.4.h/_spe/spe_blender.py0000644000175000017500000000360110725624770015352 0ustar stanistani#!BPY #""" #Name: 'Stani Python Editor' #Blender:243 #Group: 'System' #Tooltip: 'Python IDE for Blender' #""" __author__ = "Stani (www.stani.be)" __url__ = ("http://pythonide.stani.be/") __email__ = ("witold-jaworski@poczta.neostrada.pl") __version__ = "0.8.4.b" __bpydoc__ = """ This small script, written by Witold Jaworski, opens the SPE (Stani's Python Editor). Spe is a python IDE with auto-indentation, auto completion, call tips, syntax coloring, syntax highlighting, class explorer, source index, auto todo list, sticky notes, integrated pycrust shell, python file browser, recent file browser, drag&drop, context help, ... Special is its blender support with a blender 3d object browser and its ability to run interactively inside blender. Spe ships with wxGlade (gui designer), PyChecker (source code doctor) and Kiki (regular expression console). Spe is extensible with wxGlade. Spe can be used in Blender as an "side-kick" editor: once used, it opens quickly during session. As long it is open, Blender redraws its window, but all its commands are not availabe. In fact, you can control it by issuing a Blender API calls from Spe's shell console.
Typical patter of usage:
When you have finished to modify a script in SPE:
- transfer it into Blender's Text Editor (using Spe 'Load into Blender' menu command),
- close the SPE,
- select the script in Text Editor,
- run it to test (you can use to track it in the WinPdb debugger).
Then, when you will have to make another non-trivial modification to script,
- open the Spe again.
It will open with the same file, at the same position, where you have closed it.
Make the change, transfer to Blender, and test again. """ #copy this script to the .blender/scripts directory or user script directory import sys if sys.modules.has_key('_spe.SPE'): reload(sys.modules.get('_spe.SPE')) else: import _spe.SPE spe-0.8.4.h/_spe/SPE_DEBUG.py0000755000175000017500000000027011002645341014411 0ustar stanistani#!/usr/bin/env python """Shortcut to launch spe in Windows.""" if __name__=='__main__': import sys if not '--debug' in sys.argv: sys.argv.append('--debug') import _spe.SPE spe-0.8.4.h/_spe/Menu.py0000644000175000017500000007713510754716453014013 0ustar stanistani# generated by wxGlade 0.3.2 on Sat Apr 10 23:50:35 2004 ####(c)www.stani.be try: import _spe.info as info except: print "SPE path error: the folder of SPE.py should be called '_spe'!" print "(Maybe you renamed it to 'spe', please rename it back to '_spe'.)" print "SPE will exit now." import sys sys.exit() INFO=info.copy() INFO['description']=\ """Subclassed smdi frame.""" __doc__=INFO['doc']%INFO ####Modules & constants import os, wx import wxgMenu import sm.wxp.smdi as smdi STATUS = "(c) www.stani.be - The name of the current workspace is displayed at the right." ArtIDs = [ wx.ART_FILE_OPEN, wx.ART_PRINT, wx.ART_ADD_BOOKMARK, wx.ART_REPORT_VIEW, wx.ART_LIST_VIEW, wx.ART_HELP, ] BLENDER = 4 WINDOW = 5 TOOLS=[ TOOL_NEW,TOOL_OPEN_FILES, TOOL_SAVE, TOOL_SAVE_AS, TOOL_SAVE_WORKSPACE, TOOL_REMEMBER_OPEN_FILES, TOOL_UNDO, TOOL_REDO, TOOL_FIND__REPLACE, TOOL_GO_TO_LINE, TOOL_BROWSE_SOURCE, TOOL_INDENT, TOOL_DEDENT, TOOL_COMMENT, TOOL_UNCOMMENT, TOOL_SIDEBAR, TOOL_SHELL, TOOL_RUN, TOOL_RUN_DEBUG, TOOL_DEBUG, TOOL_IMPORT, TOOL_CHECK_SOURCE_WITH_PYCHECKER, TOOL_LOAD_IN_BLENDER, TOOL_REFERENCE_IN_BLENDER, TOOL_DONATE ] = \ [wx.NewId() for x in range(25)] CHILD_TOOLS=[ TOOL_SAVE, TOOL_SAVE_AS, TOOL_SAVE_WORKSPACE, TOOL_REMEMBER_OPEN_FILES, TOOL_UNDO, TOOL_REDO, TOOL_FIND__REPLACE, TOOL_GO_TO_LINE, TOOL_BROWSE_SOURCE, TOOL_INDENT, TOOL_DEDENT, TOOL_COMMENT, TOOL_UNCOMMENT, TOOL_SIDEBAR, TOOL_RUN, TOOL_RUN_DEBUG, TOOL_DEBUG, TOOL_IMPORT,TOOL_CHECK_SOURCE_WITH_PYCHECKER, ] BLENDER_TOOLS = [TOOL_LOAD_IN_BLENDER, TOOL_REFERENCE_IN_BLENDER] def _(x): if '|' in x and info.DARWIN: return x.replace('Ctrl','Cmd').replace('Alt+F4','Cmd+Q') else: return x class Tool(wx.ToolBar): def __init__(self,parent=None,app=None,id=-1,menu=None,**kwds): self.app = app wx.Bitmap = app.bitmap wx.ToolBar.__init__(self,parent=parent,id=id,**kwds) self.SetToolBitmapSize((16,16)) parent.SetToolBar(self) self.AddLabelTool(TOOL_NEW, "", wx.Bitmap("skins/default/filenew.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("New | Ctrl+N"), "") self.AddLabelTool(TOOL_OPEN_FILES, "", wx.Bitmap("skins/default/fileopen.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Open files... | Ctrl+O"), "") self.AddLabelTool(TOOL_SAVE, "", wx.Bitmap("skins/default/filesave.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Save | Ctrl+S"), "") self.AddLabelTool(TOOL_SAVE_AS, "", wx.Bitmap("skins/default/filesaveas.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Save as... | Shift+Ctrl+S"), "") self.AddLabelTool(TOOL_SAVE_WORKSPACE, "", wx.Bitmap("skins/default/workspace_save.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Save workspace"), "") self.AddLabelTool(TOOL_REMEMBER_OPEN_FILES, "", wx.Bitmap("skins/default/remember.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_CHECK, _("Remember open files"), "") self.AddSeparator() self.AddLabelTool(TOOL_UNDO, "", wx.Bitmap("skins/default/undo.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Undo | Ctrl+Z"), "") self.AddLabelTool(TOOL_REDO, "", wx.Bitmap("skins/default/redo.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Redo | Ctrl+Y"), "") self.AddSeparator() self.AddLabelTool(TOOL_FIND__REPLACE, "", wx.Bitmap("skins/default/viewmag.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Find & replace... | Ctrl+F"), "") self.AddLabelTool(TOOL_GO_TO_LINE, "", wx.Bitmap("skins/default/goto.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Go to line... | Ctrl+G"), "") self.AddLabelTool(TOOL_BROWSE_SOURCE, "", wx.Bitmap("skins/default/thumbnail.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Browse source | Ctrl+Enter"), "") self.AddSeparator() self.AddLabelTool(TOOL_INDENT, "", wx.Bitmap("skins/default/indent.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Indent | Tab"), "") self.AddLabelTool(TOOL_DEDENT, "", wx.Bitmap("skins/default/dedent.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Dedent | Shift+Tab"), "") self.AddLabelTool(TOOL_COMMENT, "", wx.Bitmap("skins/default/comment.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Comment | Alt+3"), "") self.AddLabelTool(TOOL_UNCOMMENT, "", wx.Bitmap("skins/default/uncomment.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Uncomment | Alt+4"), "") self.AddSeparator() self.AddLabelTool(TOOL_SIDEBAR, "", wx.Bitmap("skins/default/view_left_right.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_CHECK, _("View sidebar | F11"), "") self.AddLabelTool(TOOL_SHELL, "", wx.Bitmap("skins/default/view_top_bottom.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_CHECK, _("Show/hide shell | F12"), "") self.AddSeparator() self.AddLabelTool(TOOL_RUN, "", wx.Bitmap("skins/default/run.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_CHECK, _("Run.../Stop | F9"), "") self.AddLabelTool(TOOL_RUN_DEBUG, "", wx.Bitmap("skins/default/run_debug.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_CHECK, _("Run/Stop with WinPdb | F9"), "") self.AddLabelTool(TOOL_DEBUG, "", wx.Bitmap("skins/default/debug.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Debug with WinPdb... | Ctrl+Shift+D"), "") self.AddLabelTool(TOOL_IMPORT, "", wx.Bitmap("skins/default/import.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Import | F10"), "") self.AddLabelTool(TOOL_CHECK_SOURCE_WITH_PYCHECKER, "", wx.Bitmap("skins/default/pychecker.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Check source with pychecker | Ctrl+Alt+C"), "") self.AddSeparator() if app.Blender: self.AddLabelTool(TOOL_LOAD_IN_BLENDER, "", wx.Bitmap("skins/default/blender.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Load into Blender | Ctrl+B"), "") self.AddLabelTool(TOOL_REFERENCE_IN_BLENDER, "", wx.Bitmap("skins/default/blenderRef.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Reference in Blender | Ctrl+Alt+B"), "") self.AddSeparator() self.AddLabelTool(TOOL_DONATE, "", wx.Bitmap("skins/default/donate.png", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, _("Please donate, if you enjoy SPE."), "") self.Realize() def __events__(self): wx.EVT_TOOL(self,TOOL_NEW, self.menuBar.menu_new) wx.EVT_TOOL(self,TOOL_OPEN_FILES, self.menuBar.menu_open_files) wx.EVT_TOOL(self,TOOL_SAVE, self.menuBar.menu_save) wx.EVT_TOOL(self,TOOL_SAVE_AS, self.menuBar.menu_save_as) wx.EVT_TOOL(self,TOOL_SAVE_WORKSPACE, self.menuBar.menu_save_workspace) wx.EVT_TOOL(self,TOOL_REMEMBER_OPEN_FILES, self.menuBar.menu_remember_open_files) # wx.EVT_TOOL(self,TOOL_UNDO, self.menuBar.menu_undo) wx.EVT_TOOL(self,TOOL_REDO, self.menuBar.menu_redo) # wx.EVT_TOOL(self,TOOL_FIND__REPLACE, self.menuBar.menu_find__replace) wx.EVT_TOOL(self,TOOL_GO_TO_LINE, self.menuBar.menu_go_to_line) wx.EVT_TOOL(self,TOOL_BROWSE_SOURCE, self.menuBar.menu_browse_source) # wx.EVT_TOOL(self,TOOL_INDENT, self.menuBar.menu_indent) wx.EVT_TOOL(self,TOOL_DEDENT, self.menuBar.menu_dedent) wx.EVT_TOOL(self,TOOL_COMMENT, self.menuBar.menu_comment) wx.EVT_TOOL(self,TOOL_UNCOMMENT, self.menuBar.menu_uncomment) # wx.EVT_TOOL(self,TOOL_SIDEBAR, self.menuBar.menu_sidebar) wx.EVT_TOOL(self,TOOL_SHELL, self.menuBar.menu_shell) # wx.EVT_TOOL(self,TOOL_RUN, self.menuBar.menu_run) wx.EVT_TOOL(self,TOOL_RUN_DEBUG, self.menuBar.menu_run_debug) wx.EVT_TOOL(self,TOOL_DEBUG, self.menuBar.menu_debug) wx.EVT_TOOL(self,TOOL_IMPORT, self.menuBar.menu_import) wx.EVT_TOOL(self,TOOL_CHECK_SOURCE_WITH_PYCHECKER, self.menuBar.menu_check_source_with_pychecker) # if self.app.Blender: wx.EVT_TOOL(self,TOOL_LOAD_IN_BLENDER, self.menuBar.menu_load_in_blender) wx.EVT_TOOL(self,TOOL_REFERENCE_IN_BLENDER, self.menuBar.menu_reference_in_blender) # wx.EVT_TOOL(self,TOOL_DONATE, self.menuBar.menu_donate) wx.EVT_TOOL_ENTER(self,-1,self.onToolEnter) def onToolEnter(self,event): if event.GetSelection == -1: wx.CallAfter(self.skip,self) ## def ToggleTool(*arg,**keyw): ## print arg,keyw ## wx.ToolBar.ToggleTool(*arg,**keyw) ## def skip(self): if self.app.children: child = self.app.childActive child.statusBar.throbber.Play() # end of class Tool class Bar(wxgMenu.Bar): #---wxGlade def __init__(self, app, frame, *args, **kwds): self.app = app self.frame = frame wxgMenu.Bar.__init__(self, *args, **kwds) self.CHILD_MENUS = wxgMenu.CHILD_MENUS[:] self.CHILD_TOOLS = CHILD_TOOLS # Mac tweaks if wx.Platform == "__WXMAC__": app.SetMacAboutMenuItemId(wxgMenu.ABOUT) app.SetMacPreferencesMenuItemId(wxgMenu.PREFERENCES) app.SetMacExitMenuItemId(wx.ID_EXIT) #Disable highlight self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL,self.skip) #---parentPanel def enable(self,status): if self.toolBar: for tool in self.CHILD_TOOLS: self.toolBar.EnableTool(tool,status) for menu in self.CHILD_MENUS: self.Enable(menu,status) if not self.app.mdi and self.toolBar: self.toolBar.EnableTool(TOOL_SHELL,0) parentFrame = self.parentFrame if hasattr(parentFrame,'palette'): parentFrame.palette.enable(status) def Bind(self,*arg,**keyw): self.frame.Bind(*arg,**keyw) def skip(self,event): if self.app.children: child = self.app.childActive if child!= None: child.statusBar.throbber.Play() def link(self,x,doc=None): self.parentPanel.messageHtml(x,doc=doc) def check_view(self,event=None): self.Check(wxgMenu.WHITESPACE, self.parentPanel.getValue('ViewWhiteSpace')) self.Check(wxgMenu.INDENTATION_GUIDES, self.parentPanel.getValue('IndentationGuides')) self.Check(wxgMenu.RIGHT_EDGE_INDICATOR, self.parentPanel.getValue('ViewEdge')) self.Check(wxgMenu.SHELL, self.parentPanel.getValue('ShowShell')) #self.Check(wxgMenu.TOOLBAR, self.parentPanel.getValue('ShowToolbar')) if self.app.mdi and self.toolBar: self.toolBar.ToggleTool(TOOL_SHELL,self.parentPanel.getValue('ShowShell')) # TODO: Implement view line numbers and view folding #self.Check(LINE_NUMBERS, 1) #self.Check(FOLDING, 1) def check_sidebar(self,show=True): if self.app.childActive: self.Check(wxgMenu.SIDEBAR,show) if self.toolBar: self.toolBar.ToggleTool(TOOL_SIDEBAR,show) def check_remember(self,bool): self.file.Check(wxgMenu.REMEMBER_OPEN_FILES,bool) if self.toolBar: self.toolBar.ToggleTool(TOOL_REMEMBER_OPEN_FILES,bool) def check_run(self,bool): if self.toolBar: self.toolBar.ToggleTool(TOOL_RUN,bool) def check_run_debug(self,bool): if self.toolBar: self.toolBar.ToggleTool(TOOL_RUN_DEBUG,bool) def check_toolbar(self,show=True): if self.toolBar: self.parentPanel.set('ShowShell',show) self.Check(wxgMenu.TOOLBAR,show) if show: self.frame.SetToolBar(self.toolBar) self.toolBar.Show() else: self.frame.SetToolBar(None) self.toolBar.Destroy() self.toolBar = None #self.toolBar.Hide() if hasattr(self.frame,'sash'): wx.LayoutAlgorithm().LayoutMDIFrame(frame) else: self.frame.Layout() #---events def __events__(self): app = self.app #Blender if app.Blender: self.CHILD_MENUS += wxgMenu.BLENDER_MENUS self.CHILD_TOOLS += BLENDER_TOOLS else: #maybe weird to remove it afterwards but keeps wxGlade intact self.Remove(BLENDER) if app.mdi not in [smdi.SDI]:#[smdi.MDI_SPLIT,smdi.SDI]: if app.Blender: self.Remove(WINDOW+1) #When Blender menu was not removed, the first Window menu has higher number! else: self.Remove(WINDOW) self.CHILD_MENUS.remove(wxgMenu.NEXT) self.CHILD_MENUS.remove(wxgMenu.PREVIOUS) #mdi if not app.mdi: self.Enable(wxgMenu.SHELL,0) if self.toolBar: self.toolBar.EnableTool(TOOL_SHELL,0) def menu_new(self, event=None): """File > New""" self.parentPanel.new() def menu_open_files(self, event=None): """File > Open file(s)...""" self.parentPanel.open(event) def menu_save(self, event=None): """File > Save""" if self.app.children: self.app.childActive.save() self.app.parentPanel.save() def menu_save_as(self, event=None): """File > Save As...""" if self.app.children: self.app.childActive.saveAs() def menu_save_uml_as(self, event=None): if self.app.children: self.app.childActive.saveUmlAs() def menu_save_copy(self, event=None): """File > Save a Copy...""" if self.app.children: self.app.childActive.saveCopy() def menu_print_uml(self, event=None): if self.app.children: self.app.childActive.printUml() def menu_print_uml_preview(self, event=None): if self.app.children: self.app.childActive.printUmlPreview() def menu_print_uml_setup(self, event=None): if self.app.children: self.app.childActive.printUmlSetup() def menu_close(self, event=None): """File > Close""" active = self.app.childActive if active: active.frame.onFrameClose() def menu_exit(self, event=None): """File > Exit""" self.parentFrame.onFrameClose() def menu_remember_open_files(self, event=None): """File > Remember open file(s)""" self.parentPanel.rememberSet(not self.parentPanel.remember) self.Check(wxgMenu.REMEMBER_OPEN_FILES,self.parentPanel.remember) if self.toolBar: self.toolBar.ToggleTool(TOOL_REMEMBER_OPEN_FILES,self.parentPanel.remember) def menu_undo(self, event=None): """Edit > Undo""" if self.app.children: self.app.childActive.source.Undo() def menu_redo(self, event=None): """Edit > Redo""" if self.app.children: self.app.childActive.source.Redo() def menu_cut(self, event=None): """Edit > Cut""" if self.app.children: self.app.childActive.source.Cut() def menu_copy(self, event=None): """Edit > Copy""" if self.app.children: self.app.childActive.source.Copy() def menu_paste(self, event=None): """Edit > Paste""" if self.app.children: self.app.childActive.source.Paste() def menu_find__replace(self, event=None): """Edit > Find & replace...""" self.parentPanel.find_replace(event) def menu_find_next(self, event=None): """Edit > Find next""" self.parentPanel.onFind(event) def menu_go_to_line(self, event=None): """Edit > Go to line...""" if self.app.children: self.app.childActive.go_to_line() def menu_browse_source(self, event=None): """Edit > Browse source""" self.parentPanel.browse_source() def menu_auto_complete(self, event=None): """Edit > Auto complete""" if self.app.children: self.app.childActive.source.autoComplete() def menu_show_docstring(self, event=None): if self.app.children: self.app.childActive.source.showCallTip() def menu_indent(self, event=None): """Edit > Indent""" if self.app.children: self.app.childActive.source.CmdKeyExecute(wx.stc.STC_CMD_TAB) def menu_dedent(self, event=None): """Edit > Dedent""" if self.app.children: self.app.childActive.source.CmdKeyExecute(wx.stc.STC_CMD_BACKTAB) def menu_comment(self, event=None): """Edit > Comment""" if self.app.children: self.app.childActive.comment() def menu_uncomment(self, event=None): """Edit > UnComment""" if self.app.children: self.app.childActive.uncomment() def menu_insert_separator(self, event=None): """Edit > Insert seperator...""" if self.app.children: self.app.childActive.insert_separator() def menu_insert_signature(self, event=None): """Edit > Insert seperator...""" if self.app.children: self.app.childActive.insert_signature() def menu_execute(self, event): # wxGlade: Bar. """Edit > Execute""" self.parentPanel.execute() def menu_execute_verbose(self, event): # wxGlade: Bar. """Edit > Execute verbose""" self.parentPanel.execute_verbose() def menu_preferences(self, event=None): """Edit > Preferences...""" self.parentPanel.preferences() def menu_whitespace(self, event=None): """View > Whitespace""" self.parentPanel.whitespace(event) def menu_linenumbers(self, event=None): """View > Linenumbers""" self.parentPanel.linenumbers(event) def menu_indentation(self, event=None): """View > Indentation guides""" self.parentPanel.indentation_guides(event) def menu_right_edge_indicator(self, event=None): """View > Right edge indicator""" self.parentPanel.right_edge_indicator(event) def menu_end_of_line_marker(self, event=None): """View > End-of-line marker""" self.parentPanel.end_of_line_marker(event) def menu_as_notebook(self, event): self.parentPanel.as_notebook(event) def menu_as_columns(self, event): self.parentPanel.as_columns(event) def menu_as_rows(self, event): self.parentPanel.as_rows(event) def menu_sidebar(self, event=None): """View > Sidebar""" if self.app.children: self.app.childActive.toggle_sidebar(event) def menu_shell(self, event=None): """View > Shell""" hidden = self.parentPanel.toggle_shell() self.Check(wxgMenu.SHELL,hidden) if self.toolBar: self.toolBar.ToggleTool(TOOL_SHELL,hidden) def menu_clear_output(self, event=None): """View > Refresh""" self.parentPanel.output.Clear() def menu_refresh(self, event=None): """View > Refresh""" if self.app.children: self.app.childActive.refresh() def menu_toolbar(self, event): show = not self.parentPanel.getValue('ShowToolbar') self.check_toolbar(show) def menu_browse_folder(self, event=None): """Tools > Browse folder""" if self.app.children: self.parentPanel.browse_folder() def menu_run(self, event): # wxGlade: Bar. if self.app.children: self.app.parentPanel.run() def menu_run_without_arguments(self, event): # wxGlade: Bar. if self.app.children: self.app.parentPanel.run_with_arguments() def menu_run_terminal(self, event=None): """Tools > Run""" if self.app.children: self.app.childActive.run() def menu_run_terminal_without_arguments(self, event): if self.app.children: self.app.childActive.run_with_arguments(exit=False) def menu_run_terminal_without_arguments_exit(self,event): if self.app.children: self.app.childActive.run_with_arguments(exit=True) def menu_run_debug(self, event): # wxGlade: Bar. self.parentPanel.run_debug() def menu_import(self, event=None): """Tools > Import""" self.parentPanel.import_() def menu_debug(self, event=None): """Tools > Import""" self.parentPanel.debug() def menu_browse_object_with_pyfilling(self, event=None): """Tools > Browse object with PyFilling...""" self.parentPanel.browse_object_with_pyfilling() def menu_test_regular_expression_with_kiki(self, event=None): """Tools > Test regular expression with Kiki...""" self.parentPanel.test_regular_expression_with_kiki() def menu_design_a_gui_with_wxglade(self, event=None): """Tools > Design a gui with wxGlade...""" self.parentPanel.design_a_gui_with_wxglade() def menu_design_a_gui_with_xrc(self, event=None): """Tools > Design a gui with XRC...""" self.parentPanel.design_a_gui_with_xrc() def menu_check_source_with_pychecker(self, event=None): """Tools > Check source with PyChecker""" if self.app.children: self.app.childActive.check_source_with_pychecker() def menu_open_terminal_emulator(self, event=None): """Tools > Open terminal emulator...""" if self.app.children: self.app.childActive.open_terminal_emulator() def menu_run_in_terminal_emulator(self, event=None): """Tools > Run in terminal emulator...""" if self.app.children: self.app.childActive.run_in_terminal_emulator() def menu_run_in_terminal_emulator__exit(self, event=None): """Tools > Run in terminal emulator & exit...""" if self.app.children: self.app.childActive.run_in_terminal_emulator_exit() def menu_load_in_blender(self, event=None): """Blender > Load in blender""" if self.app.children: self.app.childActive.load_in_blender() def menu_reference_in_blender(self, event=None): """Blender > Reference in Blender""" if self.app.children: self.app.childActive.reference_in_blender() def menu_redraw_blender_window(self, event=None): """Blender > Redraw blender window""" if self.app.children: self.app.childActive.refresh() def menu_blender_python_manual(self, event=None): """Blender > Blender python manual...""" self.link("http://www.blender.org/documentation/245PythonDoc/index.html") def menu_blender_python_tutorial(self, event=None): """Blender > Blender python tutorial...""" self.link('http://jmsoler.free.fr/didacticiel/blender/tutor/english/index_prog_python.htm') def menu_blender_homepage(self, event=None): """Blender > Blender homepage...""" self.link('http://www.blender.org') def menu_download_blender(self, event=None): """Blender > Download blender...""" self.link('http://www.blender.org/download/get-blender') def menu_forum_blender_python(self, event=None): """Blender > Forum blender python...""" self.link('http://www.blender.org/forum/viewforum&f=9') def menu_forum_elysiun_python(self, event=None): """Blender > Forum Blenderatists Python...""" self.link('http://blenderartists.org/forum/forumdisplay.php?f=11') def menu_add_spe_to_blender(self, event=None): """Blender > Add SPE And Winpdb to Blender menu...""" self.parentPanel.add_spe_to_blender() def menu_spe_homepage(self, event=None): """Links > Spe homepage...""" self.link('http://pythonide.stani.be') def menu_forum_spe(self, event=None): """Links > Forum spe...""" self.link('http://www.stani.be/python/spe/page_forum') def menu_authors_homepage(self, event=None): """Links > Authors homepage""" self.link('http://www.stani.be') def menu_contact_author(self, event=None): """Links > Contact author...""" self.parentPanel.contact_author() def menu_python_homepage(self, event=None): """Links > Python homepage...""" self.link('http://www.python.org') def menu_active_python_distribution(self, event=None): """Links > Active python distribution...""" self.link('http://www.activestate.com') def menu_enthought_python_distribution(self, event=None): """Links > Enthought python distribution...""" self.link('http://www.enthought.com/python/') def menu_python_announcements(self, event=None): """Links > Python announcements...""" self.link('http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&group=comp.lang.python.announce') def menu_python_cookbook(self, event=None): """Links > Python cookbook...""" self.link('http://www.activestate.com/ASPN/Cookbook/Python') def menu_python_daily(self, event=None): """Links > Python daily...""" self.link('http://www.pythonware.com/daily/') def menu_python_for_artists(self, event=None): """Links > Python for artists...""" self.link('http://spe.pycs.net/stories/6.html') def menu_python_package_index(self, event=None): """Links > Python package index...""" self.link('http://www.python.org/pypi') def menu_next(self, event=None): """Window > Next""" if self.app.mdi: self.parentFrame.ActivateNext() else: event.Skip() def menu_previous(self, event=None): """Window > Previous""" if self.app.mdi: self.parentFrame.ActivatePrevious() else: event.Skip() def menu_manual(self, event=None): """Help > Manual...""" self.link('http://stani.tradebit.com/files.php/7007') def menu_keyboard_shortcuts(self, event=None): """Help > Keyboard shortcuts...""" self.link('http://pythonide.stani.be/manual/html/manual12.html') def menu_python_library(self, event=None): """Help > Python library...""" self.parentPanel.python_help('lib') def menu_python_reference(self, event=None): """Help > Python reference...""" self.parentPanel.python_help('ref') def menu_python_documentation_server(self, event=None): """Help > Python documentation server...""" self.parentPanel.python_documentation_server() def menu_wxglade_manual(self, event=None): """Help > wxGlade manual...""" self.link("http://spe.stani.be/manual/wxGlade/index.html") def menu_wxglade_tutorial(self, event=None): """Help > wxGlade tutorial...""" self.link("http://spe.stani.be/manual/wxGlade/tutorial.html") def menu_wxwindows_documentation(self, event=None): """Help > wxWindows documentation...""" self.parentPanel.wxwindows_documentation() def menu_donate(self, event=None): """Help > Donate...""" self.link('http://stani.tradebit.com/files.php/7007') #self.parentPanel.messageHtml('donate.html',doc=self.parentPanel.path) def menu_about(self, event=None): """Help > About...""" if wx.Platform == "__WXMAC__": wx.MessageBox("Stani's Python Editor: A Python IDE built on the wxPython toolkit.\n(c)www.stani.be") else: self.parentPanel.about() def menu_open_workspace(self, event): self.parentPanel.open_workspace() event.Skip() def menu_save_workspace(self, event): self.parentPanel.save_workspace() event.Skip() def menu_save_workspace_as(self, event): self.parentPanel.save_workspace_as() event.Skip() class PalettePanel(wxgMenu.Palette): def evt_indent(self, event): self.menuBar.menu_indent() if self.app.children: self.app.childActive.source.SetFocus() def evt_dedent(self, event): self.menuBar.menu_dedent() if self.app.children: self.app.childActive.source.SetFocus() def evt_comment(self, event): self.menuBar.menu_comment() if self.app.children: self.app.childActive.source.SetFocus() def evt_uncomment(self, event): self.menuBar.menu_uncomment() if self.app.children: self.app.childActive.source.SetFocus() def evt_run(self, event): self.menuBar.menu_run() def evt_import(self, event): self.menuBar.menu_import() def evt_find(self, event): self.menuBar.menu_find__replace() if self.app.children: self.app.childActive.source.SetFocus() def evt_goto(self, event): self.menuBar.menu_go_to_line() if self.app.children: self.app.childActive.source.SetFocus() def evt_browse_source(self, event): self.menuBar.menu_browse_source() if self.app.children: self.app.childActive.source.SetFocus() def evt_shell(self, event): self.menuBar.menu_shell() def evt_check(self, event): self.menuBar.menu_check_source_with_pychecker() if self.app.children: self.app.childActive.source.SetFocus() def evt_donate(self, event): self.menuBar.menu_donate() if self.app.children: self.app.childActive.source.SetFocus() def evt_next(self, event): self.menuBar.menu_next() if self.app.children: self.app.childActive.source.SetFocus() def evt_previous(self, event): self.menuBar.menu_previous() if self.app.children: self.app.childActive.source.SetFocus() def evt_sidebar(self, event): self.menuBar.menu_sidebar() if self.app.children: self.app.childActive.source.SetFocus() def evt_run_verbose(self, event): self.menuBar.menu_run_verbose() class Palette(wx.MiniFrame): def __init__(self,parent,*args,**keyw): wx.MiniFrame.__init__(self,parent,style=wx.CAPTION|wx.FRAME_FLOAT_ON_PARENT,*args,**keyw) sizer_main = wx.BoxSizer(wx.VERTICAL) self.panel = PalettePanel(parent=self,id=wx.ID_ANY) sizer_main.Add(self.panel, 0, wx.ADJUST_MINSIZE, 0) self.SetAutoLayout(True) self.SetSizer(sizer_main) sizer_main.Fit(self) sizer_main.SetSizeHints(self) def enable(self,status): for child in self.panel.GetChildren()[:-2]: child.Enable(status) from wx.animate import GIFAnimationCtrl class Status(wx.StatusBar): def __init__(self,parent=None,id=-1): wx.StatusBar.__init__(self,parent=parent,id=id) self.SetFieldsCount(5) self.SetStatusWidths([20, -1, 90, 90, 100]) self.throbber = Throbber(self,'throbber_still.gif') self.throbber.Play() self.SetStatusText(STATUS,1) class Throbber(GIFAnimationCtrl): def __init__(self,statusBar,fileName,position=0): GIFAnimationCtrl.__init__(self,statusBar,-1,info.imageFile(fileName)) self._statusBar = statusBar self._fileName = fileName self._position = position self._running = False #backgroundcolour player = self.GetPlayer() player.UseBackgroundColour(True) #position rect = statusBar.GetFieldRect(0) self.SetPosition((rect.x+(rect.width-16)/2, rect.y+(rect.height-16)/2)) def LoadFile(self,fileName): if (hasattr(self,'_fileName') and fileName != self._fileName) and not self._running: GIFAnimationCtrl.LoadFile(self,info.imageFile(fileName)) self._fileName = fileName return True return False def run(self): self.playFile('throbber.gif') self._running = True def stop(self): self._running = False self.playFile('throbber_still.gif') #wx.FutureCall(1000,self.Stop) def playFile(self,fileName): self.LoadFile(fileName) self.Play() spe-0.8.4.h/_spe/SPE.py0000755000175000017500000001567411002642334013520 0ustar stanistani#!/usr/bin/env python import sys if sys.platform.startswith('win') and sys.executable.lower().endswith('pythonw.exe'): from cStringIO import StringIO sys.stdout = StringIO() MIN_WX_VERSION = '2.5.4.1' GET_WXPYTHON = 'Get it from http://www.wxpython.org!' try: import wxversion if sys.modules.has_key('wx') or sys.modules.has_key('wxPython'): pass#probably not the first call to this module: wxPython already loaded else: #wxversion.select('2.6') wxversion.ensureMinimal(MIN_WX_VERSION) except ImportError: #the old fashioned way as not everyone seems to have wxversion installed try: import wx if wx.VERSION_STRING < MIN_WX_VERSION: print 'You need to upgrade wxPython to v%s (or higher) to run SPE.'%MIN_WX_VERSION print GET_WXPYTHON sys.exit() except ImportError: print "Error: SPE requires wxPython, which doesn't seem to be installed." print GET_WXPYTHON sys.exit() print 'Warning: the package python-wxversion was not found, please install it!' print 'SPE will continue anyway, but not all features (such as wxGlade) might work.' import info INFO = info.copy() INFO['description']=\ """This is the main SPE application created with SPE and wxGlade.""" __doc__ = INFO['doc']%INFO print """ SPE v%(version)s (c)2003-2008 www.stani.be If spe fails to start: - type "%(python)s SPE.py --debug > debug.txt 2>&1" at the command prompt (or if you use tcsh: "%(python)s SPE.py --debug >& debug.txt") - send debug.txt with some info to spe.stani.be[at]gmail.com """%INFO ####Import Modules #---General import ConfigParser, sys, os, wx import sm.wxp.smdi as smdi import Menu,Parent,Child from optparse import OptionParser #---Blender print "Blender support", try: import Blender redraw = Blender.Redraw print 'enabled.' except ImportError: Blender = None redraw = None print 'disabled (run SPE inside Blender to enable).' #---Crypto try: from Crypto.Cipher import DES fCrypto = True print "Encrypted debugging enabled.\n" except ImportError: fCrypto = False print """\nEncrypted debugging disabled. If you prefer encrypted debugging, install the "Python Cryptography Toolkit" from http://www.amk.ca/python/code/crypto\n""" ####Constants MDI = 0 DEBUG = 0 IMAGE_PATH = info.INFO['skinLocation']#os.path.join(info.path,'skins','default') ####Command line arguments openFiles = [] if DEBUG: __debug = DEBUG else: __debug = DEBUG openFiles = [] __workspace = None parser = OptionParser(usage="%prog [--debug] [ -w | --workspace=] [file1.py file2.py ... ]",version="SPE v%s (c)2003-2007 www.stani.be"%INFO['version']) parser.add_option("-w","--workspace",help="open a workspace file") parser.add_option("-d","--debug",action="store_true",help="turn on debug output") opts, args = parser.parse_args() if not __debug: __debug = (opts.debug) if opts.workspace: __workspace=opts.workspace else: openFiles=args ####Preferences config=ConfigParser.ConfigParser() config.readfp(open(INFO['defaults'])) try: config.read(INFO['defaultsUser']) except: print 'Spe warning: could not load user options' # If there is a preference in the user's defaults that is not in # the regular defaults file, add it baseConfig=ConfigParser.ConfigParser() baseConfig.read(os.path.join(info.PATH,"defaults.cfg")) for section in baseConfig.sections(): for option in baseConfig.options(section): if not config.has_option(section,option): config.set(section,option,baseConfig.get(section,option)) #---Workspace if __workspace is not None: config.set("Default","currentworkspace",__workspace) fp = open(INFO['defaultsUser'],"w") config.write(fp) fp.close() #---Maximize style = smdi.STYLE_PARENTFRAME try: maximize=eval(config.get("Default","maximize")) except: maximize=True if maximize: style |= wx.MAXIMIZE #---Size try: sizeX = int(config.get("Default","sizex")) sizeY = int(config.get("Default","sizey")) posX = max(0,int(config.get("Default","posx"))) posY = max(0,int(config.get("Default","posy"))) except: sizeX = 800 sizeY = 600 posX = 0 posY = 0 #---MDI mdi = config.get('Default','Mdi') if not smdi.DI.has_key(mdi): mdi = smdi.Default config.set('Default','Mdi',mdi) #---Single Instance Application try: singleInstance = eval(config.get('Default','SingleInstanceApp')) except: singleInstance = False ####Shortcuts class Translate: def __init__(self,keys): self.keys = keys def __call__(self,entry): entry = entry.split('\t') if len(entry)==2: label, shortcut = entry else: label = entry[0] shortcut = '' l = self.strip(label) if self.keys.has_key(l): shortcut = self.keys[l] if shortcut: return '%s\t%s'%(label,shortcut) else: return label def strip(self,x): return x.replace('&','').replace('.','') shortcuts = config.get("Default","shortcuts") if shortcuts == smdi.DEFAULT: if smdi.DARWIN: _shortcuts = 'Macintosh' else: _shortcuts = 'Windows' else: _shortcuts = shortcuts import _spe.shortcuts as sc execfile(os.path.join(os.path.dirname(sc.__file__),'%s.py'%_shortcuts)) import wxgMenu wxgMenu._ = Translate(keys) #---feedback if __debug: print """Spe is running in debugging mode with this configuration: - platform : %s - python : %s - wxPython : %s - interface : %s - encoding : %s """%(smdi.PLATFORM,INFO['pyVersionC'],INFO['wxVersionC'],mdi,INFO['encoding']) ####Application app = smdi.App(\ ParentPanel = Parent.Panel, ChildPanel = Child.Panel, MenuBar = Menu.Bar, ToolBar = Menu.Tool, StatusBar = Menu.Status, Palette = Menu.Palette, mdi = mdi, debug = __debug, fCrypto = fCrypto, title = 'SPE %s'%INFO['version'], panelFrameTitle = 'Shell', redraw = redraw, Blender = Blender, openFiles = openFiles, size = wx.Size(sizeX,sizeY), config = config, pos = wx.Point(posX,posY), shortcuts = shortcuts, imagePath = IMAGE_PATH, singleInstance = singleInstance, style = style) app.MainLoop() print "\nThank you for using SPE, please donate to support further development." if __debug: try: import msvcrt print "\nPress any key to quit..." msvcrt.getch( ) except: import time print "\nPress Ctrl+C to quit..." #time.sleep(10) spe-0.8.4.h/_spe/smdi.wmf0000644000175000017500000004606410272471120014161 0ustar stanistaniƚh|K i &   Kh|45451Courier Newk ~~ ~0-.  --2  SMDI  --."System & ~-1Courier Newk ~~ ~0-.  --<2 [ #Stani's Multiple Document Interface --.- -1Courier Newk ~~ ~0-.  --2 JU Child  --.-1Courier Newk ~~ ~0-.  --2 J1 Application  --.-1Courier Newk ~~ ~0-.  --2 J --.-1Courier Newk ~~ ~0-.  --2 4 __init__: --.-1Courier Newk ~~ ~0-.  --2  ParentPanel  --.-1Courier Newk ~~ ~0-.  --2  --.-1Courier Newk ~~ ~0-.  --2 m ChildPanel --.-1Courier Newk ~~ ~0-.  --2 m --.-1Courier Newk ~~ ~0-.  --2 0 MenuBar  --.-1Courier Newk ~~ ~0-.  --2   --.-1Courier Newk ~~ ~0-.  --2 ! ToolBar  --.-1Courier Newk ~~ ~0-.  --2 !  --.-1Courier Newk ~~ ~0-.  -- 2 T"0 mdi  --.-1Courier Newk ~~ ~0-.  --2 T" --.-1Courier Newk ~~ ~0-.  --2 $ Private attrs: --.-1Courier Newk ~~ ~0-.  --2 ;& ParentFrame  --.-1Courier Newk ~~ ~0-.  --2 ;& MDI/SDI --.-1Courier Newk ~~ ~0-.  --2 ;& --.-1Courier Newk ~~ ~0-.  --2 ' ChildFrame  --.-1Courier Newk ~~ ~0-.  --2 ' MDI/SDI --.-1Courier Newk ~~ ~0-.  --2 ' --.-1Courier Newk ~~ ~0-.  --2 ^,0 MenuBar --.-1Courier Newk ~~ ~0-.  --2 ^, --.-1Courier Newk ~~ ~0-.  --(2 . Parent, SDIChildFrame: --.-1Courier Newk ~~ ~0-.  --2 60 application  --.-1Courier Newk ~~ ~0-.  --2 60  --.-1Courier Newk ~~ ~0-.  --2 1, parent --.-1Courier Newk ~~ ~0-.  --2 1 --.-1Courier Newk ~~ ~0-.  --2 2, parentPanel  --.-1Courier Newk ~~ ~0-.  --2 2 --.-1Courier Newk ~~ ~0-.  --2 4 toolBar> --.-1Courier Newk ~~ ~0-.  --2 4  --.--$ "("(  $ "( "(  $zT r rzTzT $ "("(Z# Z# $ Z#"(Z#"(Y( Y( Z#$ #+"(#+"( - - #+$ -"( -"(4 4 ---- $  "(  $ "( "(--$  "("(  -- $ #+ -"(#+ $ -"(#+"( ---$ #+ -"( -"(#+ #+-- $ 7 9"(7 $ 9"(7"(9-1Courier NewW  ~~ ~0-.  - - 2 8 ToolBar> - - .-1Courier NewW  ~~ ~0-.  - - 2 8> - - .-1Courier NewW  ~~ ~0-.  - - (2 ]; Parent, SDIChildFrame: - - .-1Courier NewW  ~~ ~0-.  - - 2 < application> - - .-1Courier NewW ~~ ~0-.  - - 2 <  - - .-1Courier NewW ~~ ~0-.  - - 2 =, parent - - .-1Courier NewW ~~ ~0-.  - - 2 = - - .-1Courier NewW ~~ ~0-.  - - 2 C?, parentPanel  - - .-1Courier NewW ~~ ~0-.  - - 2 C? - - .-1Courier NewW  ~~ ~0-.  - - 2 @0 menuBar> - - .-1Courier NewW  ~~ ~0-.  - - 2 @  - - .--$ 7 9"(9"(7 7---$ 7"(7"(9 9 7$ 9"(9"(DA DA 9-- $  "( $ "("(--$  "("( -- $zT zTr  $zTr r--$zT zTrr zT -- $+ +P  $+P P--$+ +PP + --1Courier Newk ~~ ~0-.  - - 2 G4,Parent - - .-1Courier Newk ~~ ~0-.  - - *2 G= - - .-1Courier Newk ~~ ~0-.  - - 2 Q, __init__:l - - .-1Courier Newk ~~ ~0-.  - - 2 9, application> - - .-1Courier Newk ~~ ~0-.  - - 2 =  - - .-1Courier Newk ~~ ~0-.  - - 2 m5,children - - .-1Courier Newk ~~ ~0-.  - - 2 m= - - .-1Courier Newk ~~ ~0-.  - - $2 I,panel = parentPanel - - .-1Courier Newk ~~ ~0-.  - - 2 = - - .-1Courier Newk ~~ ~0-.  - - 2 !M,menuBar - - .-1Courier Newk ~~ ~0-.  - - 2 !=  - - .-1Courier Newk ~~ ~0-.  - - 2 Q"9,toolBar - - .-1Courier Newk ~~ ~0-.  - - 2 Q"=  - - .--$+ P P++ $+PPZ#+Z#+$ "("(B B -spe-0.8.4.h/_spe/tabs/0000755000175000017500000000000011004131466013431 5ustar stanistanispe-0.8.4.h/_spe/examples/0000755000175000017500000000000011004131466014316 5ustar stanistanispe-0.8.4.h/_spe/sidebar/0000755000175000017500000000000011004131466014111 5ustar stanistanispe-0.8.4.h/_spe/plugins/0000755000175000017500000000000011004131466014161 5ustar stanistanispe-0.8.4.h/_spe/doc/0000755000175000017500000000000011004131464013243 5ustar stanistanispe-0.8.4.h/_spe/view/0000755000175000017500000000000011004131464013450 5ustar stanistanispe-0.8.4.h/_spe/sm/0000755000175000017500000000000011004131463013114 5ustar stanistanispe-0.8.4.h/_spe/dialogs/0000755000175000017500000000000011004131466014122 5ustar stanistanispe-0.8.4.h/_spe/images/0000755000175000017500000000000011004131464013743 5ustar stanistanispe-0.8.4.h/_spe/test/0000755000175000017500000000000011004131464013455 5ustar stanistanispe-0.8.4.h/_spe/skins/0000755000175000017500000000000011004131464013625 5ustar stanistanispe-0.8.4.h/_spe/shortcuts/0000755000175000017500000000000011004131464014534 5ustar stanistanispe-0.8.4.h/_spe/tabs/Output.py0000644000175000017500000001610010776650466015326 0ustar stanistani"""Panel to execute scripts and redirect their output for SPE""" import os, re from cgi import escape import wx import wx.stc as wx_stc import wx.html as html import _spe.info as info def icon(x): return os.path.join(info.INFO['skinLocation'],x) FIND_ICON = icon('lookup.png').replace('\\','\\\\') RUN_ICON = icon('run.png') RE_LINK = re.compile('(\s*)(File "(.*))\n') RE_LOCATION = re.compile('File "([^"]*)", line (\d+)') KILL_ERROR = { wx.KILL_OK : 'ok', wx.KILL_BAD_SIGNAL : 'bad signal', wx.KILL_ACCESS_DENIED : 'access denied', wx.KILL_NO_PROCESS : 'no such process', wx.KILL_ERROR : 'unspecified error', } class Output(html.HtmlWindow): pid = -1 def __init__(self,parent=None,*args,**keyw): html.HtmlWindow.__init__(self,parent,*args,**keyw) self.SetFonts(normal_face='courier',fixed_face='courier',sizes=[8,9,10,12,16,20,22]) self.app = parent.app #---execute def _check_run(self,bool): #assing method for check run tool button if self.app.children: child = self.app.childActive if child.frame.menuBar: child.frame.menuBar.check_run(bool) else: child.parentFrame.menuBar.check_run(bool) def Execute(self, command, label = None, statustext = "Running script...",beep=False): """Executes a command of which the output will be redirected by OnIdle and OnEndProcess.""" if self.pid is -1: if not label: label = command #give feedback self.AddText('
 %s
'%(RUN_ICON,label)) self.SetStatusText(statustext) self.UpdateToolbar() self.Raise() #bind events self.Bind(wx.EVT_IDLE,self.OnIdle) self.Bind(wx.EVT_END_PROCESS,self.OnEndProcess) self.Bind(wx.EVT_TEXT_COPY,self.Copy) #create process self.process = wx.Process(self) self.process.Redirect() if info.WIN: self.pid = wx.Execute(command, wx.EXEC_ASYNC | wx.EXEC_NOHIDE, self.process) else: self.pid = wx.Execute(command, wx.EXEC_ASYNC | wx.EXEC_MAKE_GROUP_LEADER, self.process) self.inputstream = self.process.GetInputStream() self.errorstream = self.process.GetErrorStream() self.outputstream = self.process.GetOutputStream() self.inputstream.Write = Write self._check_run(True) self.beep = beep def Kill(self): if wx.Process.Exists(self.pid) and self.pid != -1: result = wx.Process.Kill(self.pid, wx.SIGKILL, flags=wx.KILL_CHILDREN) self.OnEndProcess(event=None) message = 'Script stopped by user (%s).'%KILL_ERROR.get(result,'unknown error') self.SetStatusText(message) self.AddText(message,error=True) def IsBusy(self): """Is the instance busy executing a command.""" return not (self.pid is -1) #---user feedback def AddText(self,text,error=False): """Add text and in case of error, colour red and provide links.""" text = text.replace('\r\n','\n').replace("","<string>") if error: text = escape(text) text = RE_LINK.sub(r"\g<1> \g<2>
"%FIND_ICON,text) text = '%s'%text text = text.replace('\n','
') self.AppendToPage(text) self.Scroll(0,self.GetVirtualSize()[1]/self.GetScrollPixelsPerUnit()[1]) def SetStatusText(self,text): print text def UpdateToolbar(self): #print 'Updating toolbar...' pass #---view def Clear(self): self.SetPage('') def Copy(self, event): text_data = wx.TextDataObject(self.SelectionToText()) if wx.TheClipboard.Open(): try: if not wx.TheClipboard.SetData(text_data): self.app.parentPanel.messageError("Data can't be copied to clipboard.") finally: wx.TheClipboard.Close() else: self.app.parentPanel.messageError("Clipboard can't be opened.") event.Skip() #---event handlers def OnIdle(self, event): if self.inputstream.CanRead(): text = self.inputstream.read() self.AddText(escape(text).replace(' ',' ').replace('\t',' ')) if self.errorstream.CanRead(): text = self.errorstream.read() self.AddText(text,error=True) def OnEndProcess(self, event): #unbind events self.Unbind(wx.EVT_IDLE) self.Unbind(wx.EVT_END_PROCESS) #check for any leftover output. self.OnIdle(event) #destroy process if event != None: self.process.Destroy() self.process = None self.pid = -1 #give feedback self.UpdateToolbar() self._check_run(False) if event: message = "Script terminated." self.SetStatusText(message) self.AddText(message)#''+ wx.Bell() def OnLinkClicked(self,linkInfo): match = RE_LOCATION.match(linkInfo.GetHref()) try: fileName = match.group(1) lineno = int(match.group(2)) self.OpenFile(fileName,lineno-1) self.SetStatusText('Jumped to file "%s" (line %s).'%(fileName,lineno)) except Exception, message: self.SetStatusText('SPE could not locate source file. (%s)'%message) def OpenFile(self,fileName,lineno): print fileName,lineno def Write(self,*args,**keyw): wx.OutputStream.Write(self,*args,**keyw) class Panel(Output): def __init__(self,panel,*args,**keyw): Output.__init__(self,parent=panel,id=-1,*args,**keyw) self.app = panel.app self.OpenFile = panel.openList self.SetStatusText = panel.SetActiveStatusText def Raise(self): self.GetParent().SetSelection(3)#todo: 3 should be determined dynamic class TestFrame(wx.Frame): def __init__(self,parent=None,id=-1,*args,**keyw): wx.Frame.__init__(self,parent=parent,id=id,*args,**keyw) self.output = Output(parent=self,id=-1) self.Show() def test(self): import time for i in range (1): self.output.Execute('python -c "%s/0"'%i) ## while self.output.IsBusy(): ## print self.output.pid ## time.sleep(1) def test(): app = wx.PySimpleApp() frame = TestFrame() app.SetTopWindow(frame) wx.CallAfter(frame.test) app.MainLoop() if __name__ == '__main__': print "" print " hello world" spe-0.8.4.h/_spe/tabs/Find.py0000644000175000017500000005456010754716453014715 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4cvs on Thu Jul 07 12:43:06 2005 ####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """This a demonstration of how to make a tab plugin for spe with wxGlade: Just design a wxPanel and send it to %(author_email)s This tab uses the FindReplaceEngine, copyrighted by Tim Hochberg."""%INFO __doc__=INFO['doc']%INFO def _(x): return x ####wxGlade--------------------------------------------------------------------- import wx class wxgPanel(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: wxgPanel.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.results = wx.Notebook(self, -1, style=wx.NB_BOTTOM) self.find = wx.Button(self, -1, _("Find in files")) self.clear = wx.Button(self, -1, _("Clear")) self.label_1 = wx.StaticText(self, -1, _("Depth")) self.pathDepth = wx.SpinCtrl(self, -1, "5", min=0, max=100) self.patternLabel = wx.StaticText(self, -1, _("What")) self.pattern = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER) self.pathLabel = wx.StaticText(self, -1, _("Path")) self.current = wx.BitmapButton(self, -1, wx.NullBitmap,style=wx.NO_BORDER) self.browse = wx.BitmapButton(self, -1, wx.NullBitmap,style=wx.NO_BORDER) self.path = wx.TextCtrl(self, -1, "") self.label_16 = wx.StaticText(self, -1, _("Extensions")) self.extensions = wx.TextCtrl(self, -1, _(".py,.pyw")) self.case = wx.CheckBox(self, -1, _("Match case")) self.wildcards = wx.CheckBox(self, -1, _("Wildcards")) self.word = wx.CheckBox(self, -1, _("Whole words")) self.regex = wx.CheckBox(self, -1, _("Regular expressions")) self.text_ctrl_1 = wx.TextCtrl(self.results, -1, _("Tip: Leave the 'Path' field empty to search in all open files.\n\nBesides from being usefull, this tab is an example how to extend spe with wxGlade. Just design a panel (or frame) and send it to spe.stani.be@gmail.com Than I'll integrate in the next spe release. For more information see in spe/tabs the files Find.wxg (open in wxGlade) and spe/tabs/Find.py (open in spe)."), style=wx.TE_MULTILINE|wx.TE_READONLY) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_BUTTON, self.onCurrentButton, self.current) # end wxGlade def __set_properties(self): # begin wxGlade: wxgPanel.__set_properties self.pattern.SetMinSize((178, -1)) self.current.SetMinSize((23, 23)) self.browse.SetMinSize((23, 23)) # end wxGlade def __do_layout(self): # begin wxGlade: wxgPanel.__do_layout sizerHor = wx.BoxSizer(wx.HORIZONTAL) sizer_1 = wx.BoxSizer(wx.VERTICAL) sizerVerForm = wx.BoxSizer(wx.VERTICAL) sizerFGoptions = wx.FlexGridSizer(2, 2, 4, 4) sizerFGfields = wx.FlexGridSizer(4, 2, 4, 4) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizerFGfields.Add(self.find, 0, wx.ALIGN_CENTER_VERTICAL, 0) sizer_2.Add(self.clear, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0) sizer_2.Add(self.label_1, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 4) sizer_2.Add(self.pathDepth, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0) sizerFGfields.Add(sizer_2, 1, wx.EXPAND, 0) sizerFGfields.Add(self.patternLabel, 0, wx.ALIGN_CENTER_VERTICAL, 0) sizerFGfields.Add(self.pattern, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0) sizer_3.Add(self.pathLabel, 1, wx.ALIGN_CENTER_VERTICAL, 0) sizer_3.Add(self.current, 0, wx.ALIGN_CENTER_VERTICAL, 0) sizer_3.Add(self.browse, 0, wx.ALIGN_CENTER_VERTICAL, 0) sizerFGfields.Add(sizer_3, 1, wx.EXPAND, 0) sizerFGfields.Add(self.path, 0, wx.EXPAND, 0) sizerFGfields.Add(self.label_16, 0, wx.ALIGN_CENTER_VERTICAL, 0) sizerFGfields.Add(self.extensions, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0) sizerFGfields.AddGrowableCol(1) sizerVerForm.Add(sizerFGfields, 0, wx.EXPAND, 0) sizerFGoptions.Add(self.case, 0, 0, 2) sizerFGoptions.Add(self.wildcards, 0, 0, 2) sizerFGoptions.Add(self.word, 0, 0, 2) sizerFGoptions.Add(self.regex, 0, 0, 2) sizerVerForm.Add(sizerFGoptions, 0, wx.TOP, 4) sizerHor.Add(sizerVerForm, 0, wx.ALL|wx.EXPAND, 4) self.results.AddPage(self.text_ctrl_1, _("Results")) sizer_1.Add(self.results, 1, wx.ALL|wx.EXPAND, 4) sizerHor.Add(sizer_1, 1, wx.EXPAND, 0) self.SetAutoLayout(True) self.SetSizer(sizerHor) sizerHor.Fit(self) sizerHor.SetSizeHints(self) # end wxGlade def onCurrentButton(self, event): # wxGlade: wxgPanel. print "Event handler `onCurrentButton' not implemented" event.Skip() # end of class wxgPanel ####Custom---------------------------------------------------------------------- import os,sm.osx import _spe.help class Panel(wxgPanel): """ wildcards? """ #---constructor def __init__(self, panel, *args, **kwds): wxgPanel.__init__(self,parent=panel,id=-1) self.panel = panel self.browse.SetBitmapLabel(panel.app.bitmap('fileopen.png')) self.current.SetBitmapLabel(panel.app.bitmap('down.png')) self.used=0 self.data=[] self.SetHelpText(_spe.help.FIND) self.browse.Bind(wx.EVT_BUTTON, self.onBrowseButton) self.find.Bind(wx.EVT_BUTTON, self.onFindButton) self.clear.Bind(wx.EVT_BUTTON, self.onClearButton) self.pattern.Bind(wx.EVT_TEXT_ENTER,self.onFindButton) #---events def onCurrentButton(self, event): """When current is clicked, use current path.""" self.path.SetValue(os.path.dirname(self.panel.app.childActive.fileName)) def onBrowseButton(self,event): """ When browse is clicked, show dir select dialog. If path ends in ';' we append the new path, otherwise we replace what is there. """ path = self.path.GetValue() dlg = wx.DirDialog(self,defaultPath=path) if dlg.ShowModal() == wx.ID_OK: dir = dlg.GetPath() # see if this is a valid path and if it ends in ; - if so append path if path and path[-1]==';': dir = path + dir self.path.SetValue(dir) dlg.Destroy() def onFindButton(self,event): #get values pattern = self.pattern.GetValue() path = self.path.GetValue() extensions = self.extensions.GetValue().split(',') pathDepth = self.pathDepth.GetValue() case = self.case.GetValue() word = self.word.GetValue() regex = self.regex.GetValue() self.panel.SetStatusText('Collecting filenames ...',1) engine = FindReplace(case=case, word=word, regex=regex, wrap=1, reverse=0) if path: # traverse ; seperated list of file paths names = [] for p in path.split(';'): names += sm.osx.listdirR(p, pathDepth, extensions) else: names = self.panel.getFileNames() results = engine.findAllInFiles(names, self, pattern, path=path) #---Clear Results Event added by Sam Widmer def onClearButton(self,event): if self.results.GetPageCount() > 1: curpage = self.results.GetSelection() self.results.DeletePage(curpage) else: self.results.DeletePage(0) txtctl = wx.TextCtrl(self.results, -1, "", style = wx.TE_MULTILINE) self.results.AddPage(txtctl, "Results") def onEntrySelect(self,event): file,line,col=self.data[event.GetData()] self.panel.openList(file,line-1,col) #---methods def add(self,pattern, results): report=wx.ListCtrl(self.results, -1, style=wx.LC_REPORT) report.InsertColumn(0,"File") report.SetColumnWidth(0, 150) report.InsertColumn(1,"Line") report.SetColumnWidth(1, 50) report.InsertColumn(2,"Col") report.SetColumnWidth(2, 50) report.InsertColumn(3,"Text") report.SetColumnWidth(3, 600) report.InsertColumn(4,"Path") report.SetColumnWidth(4, 300) row=0 for filename, entries in results.items(): for entry in entries: line,col,text = entry col -= 1 path,base = os.path.split(filename) item = report.InsertStringItem(row,base) report.SetStringItem(row,1,str(line)) report.SetStringItem(row,2,str(col)) report.SetStringItem(row,3,text) report.SetStringItem(row,4,path) report.SetItemData(item,len(self.data)) self.data.append((filename,line,col)) row += 1 if not self.used: self.results.DeletePage(0) self.used=1 wx.EVT_LIST_ITEM_SELECTED(report,-1,self.onEntrySelect) self.results.InsertPage(0,report, pattern, select=1) self.results.Refresh() self.results.SetSelection(0) self.panel.SetStatusText('"%s" was found %s times in %s files.'%(pattern,row,len(results)),1) # end of class Panel ####FindReplaceEngine by Tim Hochberg------------------------------------------- #----------------------------------------------------------------------------- # Name: FindReplaceEngine.py # Purpose: # # Author: Tim Hochberg # # Created: 2001/29/08 # Changed: 2003/10/02 by www.stani.be to pass values by __init__ # RCS-ID: $Id: FindReplaceEngine.py,v 1.5 2003/01/03 01:46:12 riaan Exp $ # Copyright: (c) 2001 Tim Hochberg # Licence: GPL #----------------------------------------------------------------------------- import re, string class FindError(ValueError): pass def _fix(match, offset, length, selectionStart): if match is None: return None r = [] try: for i in match.span(): r.append((i + offset) % length + selectionStart) except:pass return tuple(r) class FindReplaceEngine: def __init__(self, case=0, word=0, regex=0, wrap=1, wildcard=0, reverse=0): self.case = case self.word = word if regex: self.mode = 'regex' elif wildcard: self.mode = 'wildcard' # or wildcard or regex else: self.mode = 'text' # or wildcard or regex self.wrap = wrap self.closeOnFound = 0 self.reverse = reverse self.selection = 0 self.findHistory = [''] self.replaceHistory = [''] self.folderHistory = [''] self.suffixHistory = ['*.py'] self.suffixes = [".py"] self.regions = {} self.loadOptions() def _addHistory(self, pattern, history): if pattern: if pattern in history: history.remove(pattern) history.append(pattern) def addFind(self, pattern): self._addHistory(pattern, self.findHistory) def addReplace(self, pattern): self._addHistory(pattern, self.replaceHistory) def addFolder(self, pattern): self._addHistory(pattern, self.folderHistory) def addSuffix(self, pattern): self._addHistory(pattern, self.suffixHistory) def setRegion(self, view, region): self.regions[view] = region def getRegion(self, view): region = self.regions.get(view, view.GetSelection()) if region[0] == region[1]: region = (0, view.GetTextLength()) return region def findInSource(self, view, pattern): region = self.getRegion(view) self.addFind(pattern) start = view.GetSelection()[not self.reverse] if self.selection: result = self._find(apply(view.GetTextRange, region), pattern, start, region[0]) else: result = self._find(view.GetText(), pattern, start, 0) if result is None: raise FindError("'%s' not found" % pattern) view.model.editor.addBrowseMarker(view.GetCurrentLine()) if (result[0] < view.GetCurrentPos() and not self.reverse and self.wrap) or \ (result[0] > view.GetCurrentPos() and self.reverse and self.wrap): view.model.editor.setStatus('Search wrapped', 'Warning', ringBell=1) view.SetSelection(result[0], result[1]) def findNextInSource(self, view): self.findInSource(view, self.findHistory[-1]) def _findAllInSource(self, text, pattern, selectionStart): viewResults = [] for s, e in self._findAll(text, pattern, selectionStart, selectionStart): t = text[:s] lineNo = string.count(t, '\n') left = max(string.rfind(t, '\n'), 0) + 1 index = s - left line = string.split(text[left:], "\n", 1)[0] viewResults.append((lineNo+1, index+1, line)) return viewResults def findAllInSource(self, view, pattern): region = self.getRegion(view) self.addFind(pattern) if self.selection: results = self._findAllInSource(apply(view.GetTextRange, region), pattern, region[0]) else: results = self._findAllInSource(view.GetText(), pattern, 0) name = 'Results: ' + pattern if not view.model.views.has_key(name): resultView = view.model.editor.addNewView(name, FindResults) else: resultView = view.model.views[name] resultView.tabName = name resultView.results = {view.model.filename : results} # XXX should this be viewName? resultView.findPattern = pattern resultView.refresh() resultView.focus() resultView.rerunCallback = self.findAllInSource resultView.rerunParams = (view, pattern) def replaceInSource(self, view, pattern, new): region = self.getRegion(view) self.addFind(pattern) self.addReplace(new) # GetSelectedText returns bugus string when nothing is selected selRange = view.GetSelection() selText = view.GetSelectedText() if selRange[0] == selRange[1]: selText = '' # If the text to be replaced is not yet selected, don't replace, just # look for the next occurence. if self._find(selText, pattern, 0, 0) is not None: # XXX make more specific start = selRange[self.reverse] if self.selection: result = self._find(apply(view.GetTextRange, region), pattern, start, region[0]) else: result = self._find(view.GetText(), pattern, start, 0) if result is None: raise FindError("'%s' not found" % pattern) view.SetSelection(result[0], result[1]) compiled = self._compile(pattern) if self.mode == 'regex': new = compiled.sub(new, view.GetSelectedText()) view.ReplaceSelection(new) # Attempt to find the next replacement try: self.findInSource(view, pattern) except FindError: pass def replaceAllInSource(self, view, pattern, new): region = self.getRegion(view) self.addFind(pattern) self.addReplace(new) text = view.GetText() # Replace from the end so that we can do the replace in place without # the indices getting messed up. self.reverse, oldReverse = 1, self.reverse if self.selection: results = self._findAll(apply(view.GetTextRange, region), pattern, region[0], region[0]) else: results = self._findAll(view.GetText(), pattern, 0, 0) self.reverse = oldReverse compiled = self._compile(pattern) if results == []: return view.model.editor.addBrowseMarker(view.GetCurrentLine()) for item in results: view.SetSelection(item[0], item[1]) n = new if self.mode == 'regex': n = compiled.sub(new, view.GetSelectedText()) view.ReplaceSelection(n) view.model.editor.statusBar.setHint("%s items replaced" % len(results)) def findNamesInPackage(self, view): names = [] packages = [os.path.dirname(view.model.assertLocalFile())] for base in packages: for p in map(lambda n, base=base: os.path.join(base, n), os.listdir(base)): #for p in [os.path.join(base, n) for n in os.listdir(base)]: #1.5.2 support if os.path.isfile(p) and os.path.splitext(p)[1] in self.suffixes: names.append(p) elif os.path.isdir(p) and os.path.isfile(os.path.join(base, "__init__.py")): packages.append(p) names.sort(lambda x, y : os.path.basename(x) > os.path.basename(y)) return names def findAllInFiles(self, names, view, pattern): self.addFind(pattern) results = {} # Setup progress dialog dlg = wx.ProgressDialog("Finding '%s' in files" % pattern, 'Searching...', len(names), view, wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE) try: for i in range(len(names)): filename = self._getValidFilename(names[i]) if not filename: continue results[names[i]] = self._findAllInSource(open(filename).read(), pattern, 0) if not dlg.Update(i, "Searching in file '%s'"%filename): try: view.model.editor.statusBar.setHint("Search aborted") except: pass view.rerunCallback = self.findAllInFiles view.rerunParams = (names, view, pattern) view.addFindResults(pattern, results) finally: dlg.Destroy() def findAllInPackage(self, view, pattern): self.findAllInFiles(self.findNamesInPackage(view), view, pattern) def findAllInApp(self, view, pattern): names = map(view.model.moduleFilename, view.model.modules.keys()) names.sort() self.findAllInFiles(names, view, pattern) def _compile(self, pattern): flags = [re.IGNORECASE, 0][self.case] if not self.mode == 'regex': pattern = re.escape(pattern) if self.mode == 'wildcard': pattern = pattern.replace(r'\?', '.?') pattern = pattern.replace(r'\*', '.*') if self.word: pattern = r"\b%s\b" % pattern return re.compile(pattern, flags) def _processText(self, text, start): before, after = text[:start], text[start:] if self.wrap: offset = start domain = after + before elif not self.reverse: offset = start domain = after else: offset = 0 domain = before return domain, offset def _findAll(self, text, pattern, start, selectionStart): start = start - selectionStart compiled = self._compile(pattern) domain, offset = self._processText(text, start) matches = [] start = 0 while 1: s = compiled.search(domain, start) if s is None or s.end() == 0: break start = s.end() matches.append(_fix(s, offset, len(text), selectionStart)) if self.reverse: matches.reverse() return matches def _find(self, text, pattern, start, selectionStart): if self.reverse: return (self._findAll(text, pattern, start, selectionStart) + [None])[0] start = start - selectionStart compiled = self._compile(pattern) domain, offset = self._processText(text, start) return _fix(compiled.search(domain), offset, len(text), selectionStart) def loadOptions(self): pass ## try: ## conf = Utils.createAndReadConfig('Explorer') ## if conf.has_section('finder'): ## self.wrap = conf.getint('finder', 'wrap') ## self.closeOnFound = conf.getint('finder', 'closeonfound') ## except: ## print 'Problem loading finder options' def saveOptions(self): pass ## try: ## conf = Utils.createAndReadConfig('Explorer') ## if not conf.has_section('finder'): conf.add_section('finder') ## conf.set('finder', 'wrap', self.wrap) ## conf.set('finder', 'closeonfound', self.closeOnFound) ## Utils.writeConfig(conf) ## except Exception, err: ## print 'Problem saving finder options: %s' % err def _getValidFilename(self, filename): protsplit = string.split(filename, '://') if len(protsplit) > 1: if protsplit[0] != 'file' or len(protsplit) > 2: wx.LogWarning('%s not searched, only local files allowed'%filename) return '' return protsplit[1] return filename class FindReplace(FindReplaceEngine): def findAllInFiles(self, names, view, pattern, path=''): self.addFind(pattern) results = {} # Setup progress dialog dlg = wx.ProgressDialog("Finding '%s' in %s" % (pattern,os.path.basename(path)), 'Searching...', len(names), view, wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE) try: for i in range(len(names)): filename = self._getValidFilename(names[i]) if not (filename and os.path.exists(filename)): continue results[names[i]] = self._findAllInSource(open(filename).read(), pattern, 0)#(lineNo+1, index+1, line) if not dlg.Update(i, "Searching in file '%s'"%filename): try: view.panel.SetStatusText("Search aborted",1) except: pass view.rerunCallback = self.findAllInFiles view.rerunParams = (names, view, pattern) view.add(pattern, results) return results finally: dlg.Destroy() def loadOptions(self): pass def saveOptions(self): pass if __name__=='__main__': import sm.wxp sm.wxp.panelApp(Panel) spe-0.8.4.h/_spe/tabs/Donate.py0000644000175000017500000000107110272471120015214 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Index as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import sm.wxp import os, webbrowser #import _spe.help class Panel(sm.wxp.HtmlWindow): def __init__(self,panel,*args,**kwds): self.panel = panel sm.wxp.HtmlWindow.__init__(self,parent=panel,id=-1) self.LoadPage(os.path.join(panel.path,'doc','donate.html')) spe-0.8.4.h/_spe/tabs/Notes.py0000644000175000017500000000111610342711136015074 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info as info INFO = info.copy() INFO['description']=\ """Notes as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import wx import _spe.help class Panel(wx.TextCtrl): def __init__(self,panel,*args,**kwds): style = wx.TE_MULTILINE if not info.DARWIN: style |= wx.TE_DONTWRAP wx.TextCtrl.__init__(self,parent=panel,id=-1,style=style) self.SetHelpText(_spe.help.NOTES) spe-0.8.4.h/_spe/tabs/Find.wxg0000644000175000017500000003046410342711136015051 0ustar stanistani wxHORIZONTAL wxALL|wxEXPAND 4 wxVERTICAL wxEXPAND 0 4 4 1 2 4 wxALIGN_CENTER_VERTICAL 0 wxEXPAND 0 wxHORIZONTAL wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE 0 wxLEFT|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 1 wxEXPAND|wxALIGN_CENTER_VERTICAL 0 5 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND|wxALIGN_CENTER_VERTICAL 0 178, -1 wxEXPAND 0 wxHORIZONTAL wxALIGN_CENTER_VERTICAL 0 1 wxALIGN_CENTER_VERTICAL 0 onCurrentButton 23, 23 wxALIGN_CENTER_VERTICAL 0 23, 23 wxEXPAND 0 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND|wxALIGN_CENTER_VERTICAL 0 .py,.pyw wxTOP 4 4 2 2 4 2 2 2 2 wxEXPAND 0 wxVERTICAL wxALL|wxEXPAND 4 Results Tip: Leave the 'Path' field empty to search in all open files.\n\nBesides from being usefull, this tab is an example how to extend spe with wxGlade. Just design a panel (or frame) and send it to spe.stani.be@gmail.com Than I'll integrate in the next spe release. For more information see in spe/tabs the files Find.wxg (open in wxGlade) and spe/tabs/Find.py (open in spe). spe-0.8.4.h/_spe/tabs/Index.py0000644000175000017500000000166410272471120015061 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Index as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import wx import sys import _spe.help if sys.platform == 'win32': LIST_STYLE = wx.LC_LIST|wx.LC_SMALL_ICON else: LIST_STYLE = wx.LC_LIST class Panel(wx.ListCtrl): def __init__(self,panel,*args,**kwds): self.panel = panel wx.ListCtrl.__init__(self,parent=panel,style=panel.LIST_STYLE) self.SetImageList(panel.iconsList,wx.IMAGE_LIST_SMALL) self.SetHelpText(_spe.help.INDEX) #---events wx.EVT_LIST_ITEM_SELECTED(self,-1,self.onSelect) #---events def onSelect(self,event): stripped,entry,line,colour,icon,file=self.list[event.GetData()] self.panel.openList(file,line-1) spe-0.8.4.h/_spe/tabs/Browser.wxg0000644000175000017500000001146410272471120015611 0ustar stanistani wxHORIZONTAL wxEXPAND 0 wxSPLIT_VERTICAL 229 fileList sideBar wxVERTICAL wxEXPAND 0 wxHORIZONTAL 0 folder_new.png 24, 24 0 folder_delete.png 24, 24 wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 wxLEFT|wxEXPAND 4 0 wxEXPAND 0 0 Current folder spe-0.8.4.h/_spe/tabs/__init__.py0000644000175000017500000000000010272471120015530 0ustar stanistanispe-0.8.4.h/_spe/tabs/Locals.py0000644000175000017500000000125310365020320015214 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Locals as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import sm.wxp import _spe.help import sys class Panel(sm.wxp.SmFilling): def __init__(self,panel,*args,**options): sm.wxp.SmFilling.__init__(self,parent=panel, rootObject=panel.shell.interp.locals, rootLabel='locals()', rootIsNamespace=1) self.tree.setStatusText=panel.SetStatusText self.SetHelpText(_spe.help.LOCALS) spe-0.8.4.h/_spe/tabs/Browser.py0000644000175000017500000001775710754716453015467 0ustar stanistani# generated by wxGlade 0.3.2 on Mon Apr 12 02:14:33 2004 ####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """File browser as tab.""" __doc__=INFO['doc']%INFO ####wxGlade--------------------------------------------------------------------- CURRENT = "Current folder" import wx import _spe.help class wxgPanel(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: wxgPanel.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.split = wx.SplitterWindow(self, -1) self.sideBar = wx.Panel(self.split, -1) self.folderNew = wx.BitmapButton(self.sideBar, -1, wx.Bitmap("folder_new.png", wx.BITMAP_TYPE_ANY)) self.folderDelete = wx.BitmapButton(self.sideBar, -1, wx.Bitmap("folder_delete.png", wx.BITMAP_TYPE_ANY)) self.depthLabel = wx.StaticText(self.sideBar, -1, "Depth") self.depth = wx.SpinCtrl(self.sideBar, -1, "0", min=0, max=100) self.folderList = wx.ListBox(self.sideBar, -1, choices=["Current folder"]) self.fileList = wx.ListCtrl(self.split, -1, style=wx.LC_LIST) self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: wxgPanel.__set_properties self.folderNew.SetSize((24, 24)) self.folderDelete.SetSize((24, 24)) self.folderList.SetSelection(0) self.split.SplitVertically(self.sideBar, self.fileList, 229) # end wxGlade def __do_layout(self): # begin wxGlade: wxgPanel.__do_layout main = wx.BoxSizer(wx.HORIZONTAL) sideBarSizer = wx.BoxSizer(wx.VERTICAL) controls = wx.BoxSizer(wx.HORIZONTAL) controls.Add(self.folderNew, 0, 0, 0) controls.Add(self.folderDelete, 0, 0, 0) controls.Add(self.depthLabel, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 10) controls.Add(self.depth, 1, wx.LEFT|wx.EXPAND, 4) sideBarSizer.Add(controls, 0, wx.EXPAND, 0) sideBarSizer.Add(self.folderList, 1, wx.EXPAND, 0) self.sideBar.SetAutoLayout(1) self.sideBar.SetSizer(sideBarSizer) sideBarSizer.Fit(self.sideBar) sideBarSizer.SetSizeHints(self.sideBar) main.Add(self.split, 1, wx.EXPAND, 0) self.SetAutoLayout(1) self.SetSizer(main) main.Fit(self) main.SetSizeHints(self) # end wxGlade # end of class wxgPanel ####Custom---------------------------------------------------------------------- import os,types import sm.osx, sm.scriptutils ##if sys.platform == 'win32': ## wx.LC_LIST = wx.LC_LIST|wx.LC_SMALL_ICON ##else: ## wx.LC_LIST = wx.LC_LIST class Panel(wxgPanel): #---constructors def __init__(self, panel, *args, **kwds): """Arguments come from the parent frame.""" wx.Bitmap = panel.app.bitmap wx.LC_LIST = panel.LIST_STYLE wxgPanel.__init__(self, parent=panel, id=-1) self.panel = panel self.imageList = wx.ImageList(16,16) self.pyIcon = self.imageList.Add(wx.Bitmap('source_py.png')) self.fileList.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL) self.split.SetMinimumPaneSize(1) self.SetDropTarget(DropAdd(self.add)) self.SetHelpText(_spe.help.BROWSER) self.__events__() #---events def __events__(self): wx.EVT_BUTTON(self.folderNew,-1,self.onFolderNew) wx.EVT_BUTTON(self.folderDelete,-1,self.onFolderDelete) wx.EVT_LISTBOX(self.folderList,-1, self.onFolderSelect) wx.EVT_LIST_ITEM_SELECTED(self.fileList,-1,self.onFileSelect) wx.EVT_LIST_ITEM_RIGHT_CLICK(self.fileList,-1,self.onFileRightClick) wx.EVT_LIST_ITEM_MIDDLE_CLICK(self.fileList,-1,self.onFileMiddleClick) self.folderList.GetSelection() def onFileSelect(self,event): file=self.files[event.GetIndex()][1] self.panel.openList(file) def onFileRightClick(self,event): file=self.files[event.GetIndex()][1] sm.scriptutils.run(file) def onFileMiddleClick(self,event): file=self.files[event.GetIndex()][1] sm.scriptutils.importMod(file) def onFolderNew(self,event): """When add button clicked, add directory with browse dir dialog.""" folder = self.folderList.GetStringSelection() if folder == 'Current folder': folder = self.getCurrentFolder() print "-----name : ", folder dlg = wx.DirDialog(self,defaultPath=folder ) if dlg.ShowModal() == wx.ID_OK: dir = dlg.GetPath() self.add(dir) dlg.Destroy() def onFolderDelete(self,event): """When remove button clicked, remove folder from listbox""" index = self.folderList.GetSelection() self.deleteFolder(index) def onFolderSelect(self,event): """Display a list of files when the user clicks a folder.""" ## Todo: Figure out why this event gets called twice. # When SPE is launched the first time you click on any folder in the browser # it generates two selection events. However after that first click events # get generated normally. if not self.depth: return self.panel.busyShow() recursion=self.depth.GetValue() folder=event.GetString() print "this is the value of folder here : ",folder if folder == 'Current folder': folder = self.getCurrentFolder() self.add(folder) if not os.path.exists(folder): index = event.GetInt() self.deleteFolder(index) self.setFileList(folder, recursion) self.panel.busyHide() #---methods #---New Methods added by Sam Widmer def deleteFolder(self, index): """Delete the folder listbox item @ index and clear the file listcontrol this method also will not delete the Current folder item""" if index > 0: self.folderList.Delete(index) self.setFileList('',0) def getCurrentFolder(self): """Returns the folder path that the 'Current folder' item references""" try: filename = self.panel.childActive.fileName except: filename = '' if filename in ('unnamed', ''): folder = os.getcwd() else: folder = os.path.dirname(self.panel.childActive.fileName) return folder def setFileList(self, folder, recursion): """Set self.files, clear and add files to the files listcontrol""" self.fileList.DeleteAllItems() self.files = [] try: self.fileList.SetColumnWidth(-1,300) except: pass if os.path.exists(folder): flen = len(folder)+1 if folder[-1] in ['\\','/']: flen -= 1 self.files=[(file[flen:], file) for file in sm.osx.listdirR(folder,recursion,['.py','.pyw'])] self.files.sort() for i, file in enumerate(self.files): self.fileList.InsertImageStringItem(i, file[0], self.pyIcon) # End of new methods def add(self,folders): """Add folders to the listbox.""" if type(folders) not in [types.ListType,types.TupleType]: folders=[folders] already = self.getFolders() for folder in folders: if folder not in already: if os.path.exists(folder): self.folderList.Append(folder) def getFolders(self): return [self.folderList.GetString(index) for index in range(self.folderList.GetCount())] class DropAdd(wx.FileDropTarget): """Adds a file to browser when dropped on browser tab.""" def __init__(self,add): wx.FileDropTarget.__init__(self) self.add=add def OnDropFiles(self,x,y,fileNames): fileNames=[dir for dir in fileNames if os.path.isdir(dir)] if fileNames: self.add(fileNames) return 1 else: return 0 spe-0.8.4.h/_spe/tabs/Blender.wxg0000644000175000017500000000703010272471120015533 0ustar stanistani wxHORIZONTAL wxEXPAND 0 wxVERTICAL wxRIGHT 50 1 ../skins/default/blenpy.png wxEXPAND|wxADJUST_MINSIZE 0 0 Blender Armatures Cameras Curves Effects Images Ipos IpoCurves Lamps Lattices Materials Metaballs Objects Scenes Texts Textures Worlds 94, 212 wxALL|wxEXPAND 4 1 spe-0.8.4.h/_spe/tabs/Blender.py0000644000175000017500000001171310767547632015406 0ustar stanistani# generated by wxGlade 0.3.2 on Mon Apr 12 01:28:29 2004 ####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Blender browser as tab.""" __doc__=INFO['doc']%INFO ####wxGlade--------------------------------------------------------------------- import wx, os class wxgPanel(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: wxgPanel.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.logo = wx.StaticBitmap(self, -1, wx.Bitmap("../skins/default/blenpy.png", wx.BITMAP_TYPE_ANY)) self.modules = wx.ListBox(self, -1, choices=["Blender", "Armatures", "BezTriples", "Cameras", "Curves", "Effects", "Groups", "Images", "Ipos", "Keys", "Lamps", "Lattices", "Materials", "Meshes", "Metaballs", "NMeshes", "Objects", "Registry", "Scenes", "Sounds", "Texts", "Text3ds", "Textures", "Worlds"], style=wx.LB_SINGLE) self.filling = wx.StaticText(self, -1, "Only available when Spe is launched from Blender. How? Open the file _spe/spe.blend and press Alt+P in the lower right text window.\n\nBlender is a free 3d modeller, renderer and animation program with a Python scripting engine (http://www.blender.org).") self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: wxgPanel.__set_properties self.modules.SetSize((94, 212)) self.modules.SetSelection(0) # end wxGlade def __do_layout(self): # begin wxGlade: wxgPanel.__do_layout main = wx.BoxSizer(wx.HORIZONTAL) sideBar = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""), wx.VERTICAL) sideBar.Add(self.logo, 0, wx.RIGHT, 50) sideBar.Add(self.modules, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) main.Add(sideBar, 0, wx.EXPAND, 0) main.Add(self.filling, 10, wx.ALL|wx.EXPAND, 4) self.SetAutoLayout(1) self.SetSizer(main) main.Fit(self) main.SetSizeHints(self) # end wxGlade self.main = main # end of class wxgPanel ####Custom---------------------------------------------------------------------- import sm.wxp import _spe.help class Panel(wxgPanel): #---constructors def __init__(self, panel, *args, **kwds): wx.Bitmap = panel.app.bitmap self.Blender = panel.Blender wxgPanel.__init__(self, parent=panel,id=-1) self.update() self.SetHelpText(_spe.help.BLENDER) #events wx.EVT_LISTBOX(self.modules,self.modules.GetId(),self.update) #---methods def update(self,event=None): if self.Blender: welcome = 'This is an inventory of all %s in the Blender drawing. Currently there %s %s %s%s...\n\n %s' label = self.modules.GetStringSelection() l = label.lower() if label =='Blender': object = self.Blender welcome = 'Blender Module' elif label=='Registry': welcome = 'Registry Keys' label = 'Blender.Registry' object = {} for key in self.Blender.Registry.Keys(): object[key] = self.Blender.Registry.GetKey(key) else: if label == 'NMeshes': attr = 'NMesh' NMesh = self.Blender.NMesh names = NMesh.GetNames() object = [NMesh.GetRaw(name) for name in names] multi = min(len(object)-1,1) welcome = welcome%(l,('is only','are')[multi],len(object),'nmesh',('','es')[multi],', '.join(names)) else: #convert plural to singular if label in ['Meshes']: attr = label[:-2] else: attr = label[:-1] try: object = getattr(self.Blender,attr).Get() except: object = [] welcome += 'There was an error retrieving the list.' multi = min(len(object)-1,1) welcome = welcome%(l,('is only','are')[multi],len(object),l[:-1],('','s')[multi],', '.join([str(o) for o in object])) label = 'Blender.%s.Get()'%attr self.main.Remove(self.filling) self.filling.Destroy() self.filling = sm.wxp.SmFilling(parent=self, rootObject=object, rootLabel=label, welcome=welcome, rootIsNamespace=1) self.main.Add(self.filling, 1, wx.ALL | wx.EXPAND, 0) self.main.Layout() self.filling.SetFocus() spe-0.8.4.h/_spe/tabs/Todo.py0000644000175000017500000000216210272471120014711 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Todo as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import wx import _spe.help class Panel(wx.ListCtrl): def __init__(self,panel,*args,**kwds): wx.ListCtrl.__init__(self,parent=panel,style=wx.LC_REPORT) self.panel = panel self.InsertColumn(col=0, format=wx.LIST_FORMAT_LEFT, heading='File',width=120) self.InsertColumn(col=1, format=wx.LIST_FORMAT_LEFT, heading='Line',width=40) self.InsertColumn(col=2, format=wx.LIST_FORMAT_LEFT, heading='!',width=20) self.InsertColumn(col=3, format=wx.LIST_FORMAT_LEFT, heading='Task',width=500) self.SetHelpText(_spe.help.TODO) #events wx.EVT_LIST_ITEM_SELECTED(self,-1,self.onSelect) #---events def onSelect(self,event): file,line=self.list[event.GetData()] self.panel.openList(file,line-1) spe-0.8.4.h/_spe/tabs/Session.py0000644000175000017500000000102110272471120015420 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Session as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import wx import _spe.help from wx.py.crust import SessionListing class Panel(SessionListing): def __init__(self,panel,*args,**kwds): SessionListing.__init__(self,parent=panel) self.SetHelpText(_spe.help.SESSION) spe-0.8.4.h/_spe/tabs/Shell.py0000644000175000017500000001114610755657026015076 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Session as tab. pyChecker support by Nicodemus""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- import wx, re, os, sys import _spe.help INTRO = """Portions Copyright 2003-2007 www.stani.be - see credits in manual for further copyright information. Please donate if you find this program useful (see help menu). Double click to jump to error source code.""" class Shell(wx.py.shell.Shell): def __init__(self,app,**keyw): self.locals = keyw['locals'] = {'SPEapp':app,'__name__':'__main__'} wx.py.shell.Shell.__init__(self,**keyw) self.SetUseAntiAliasing(True) self.Bind(wx.EVT_LEFT_DCLICK,self.jumpToSource) self.Unbind(wx.EVT_IDLE) def jumpToSource(self,event=None): line = self.GetCurrentLine() text = None while not text and line > 0: text=self.GetLine(line) if text.find('File')!=-1 and text.find('line')!=-1: text='{%s}'%text.split('in ')[0].strip().replace('File ','"file":r').replace('line','"line":') try: text=eval(text) except: text=None else: text=None line-=1 #pyChecker support by Nicodemus if not text: # check if the line in the form filename:line: message current_line = self.GetLine(self.GetCurrentLine()) m = re.match('(.*):(\d+): .*', current_line) if m: text = {} text['file'] = m.group(1) text['line'] = int(m.group(2))+1 else: text = None if text: text['line']-=1 self.open(r'%s'%text['file'],text['line']) self.setStatusText('Jumped to file "%s" (line %s)'%(text['file'],text['line'])) else: self.setStatusText('Error: Impossible to locate file and line number.') def Execute(self,text): """Replace selection with clipboard contents, 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() class DropRun(wx.FileDropTarget): """Runs a file when dropped on shell.""" def __init__(self,run): wx.FileDropTarget.__init__(self) self.run=run def OnDropFiles(self,x,y,fileNames): fileNames=[script for script in fileNames if os.path.splitext(script)[-1].lower() in ['.py','.pyw']] if fileNames: for fileName in fileNames: self.run(fileName) return 1 else:return 0 class Panel(Shell): def __init__(self,panel,*args,**kwds): Shell.__init__(self, panel.app, parent = panel, introText = INTRO) self.setStatusText = panel.SetActiveStatusText self.open = panel.openList self.SetDropTarget(DropRun(panel.runFile)) self.SetHelpText(_spe.help.SHELL) spe-0.8.4.h/_spe/tabs/Recent.py0000644000175000017500000000571511002666475015246 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Recent files as tab.""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import os import wx import sm.scriptutils as scriptutils import _spe.help as help class DropAdd(wx.FileDropTarget): """Adds a file to recent files when dropped on recent tab.""" def __init__(self,add): wx.FileDropTarget.__init__(self) self.add=add def OnDropFiles(self,x,y,fileNames): fileNames=[script for script in fileNames if os.path.splitext(script)[-1].lower() in ['.py','.pyw']] if fileNames: self.add(fileNames) return 1 else:return 0 class Panel(wx.ListCtrl): def __init__(self,panel,**options): wx.ListCtrl.__init__(self,parent=panel,style=panel.LIST_STYLE) self.imageList = wx.ImageList(16,16) self.pyIcon = self.imageList.Add(panel.icons['source_py.png']) self.files = [] self.panel = panel self.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL) self.SetDropTarget(DropAdd(self.add)) self.SetHelpText(help.RECENT) #events wx.EVT_LIST_ITEM_SELECTED(self, -1, self.onLeftClick) wx.EVT_LIST_ITEM_ACTIVATED(self, -1, self.onRightClick) wx.EVT_LIST_ITEM_MIDDLE_CLICK(self, -1, self.onMiddleClick) def add(self,fileList): """Register file list as recent.""" files = [file for file in self.files \ if file not in fileList and os.path.exists(file)] if len(self.files)-len(files)!=len(fileList): fileList.extend(files) self.files=fileList self.update() def update(self): self.DeleteAllItems() i=0 self.files = [(os.path.basename(str(file)),file) for file in self.files] try: self.files.sort(key=lambda (name,path): name.lower()) except: #python2.3 self.files.sort() self.files = [file[1] for file in self.files] for file in self.files: self.InsertImageStringItem(i, os.path.basename(str(file)),self.pyIcon) i+=1 try: self.SetColumnWidth(-1,300) except: pass #---events def onLeftClick(self,event): """Open file on left click.""" file=self.files[event.GetIndex()] f=self.panel.openList(file) if not f: self.panel.toolBar.SetFocus() self.files.remove(file) self.update() def onRightClick(self,event): """Run file on right click.""" file=self.files[event.GetIndex()] scriptutils.run(file) self.panel.shell.prompt() def onMiddleClick(self,event): """Import file on middle click.""" file=self.files[event.GetIndex()] scriptutils.importMod(file) self.panel.shell.prompt() spe-0.8.4.h/_spe/examples/example.py0000644000175000017500000000242510272471120016326 0ustar stanistani"""SPE (c)www.stani.be 2003 This python script is useless. It just demonstrates the functionality of the sidebar. Press the different tabs to see how to add: - seperator: start a line at column 1 with '#---' (See Help>Seperators for more information.) ->the seperators will respect the hierarchy - todo: start a line anywhere with '# TODO:' ->the most important tasks will be highlighted - notes Navigation: In all tabs of the sidebar right-clicking or double clicking will jump to location in the source code of the selected item. In the todo, index and recent files (down) a normal mouse click also will work. """ ####constants #---math ZERO=0 # TODO: Add more constants ####functions #---general def function(argument): return argument #---crazy colors---#FF8040#8000FF----------------------------------------------- def foo(x): return x # TODO: Add more functions!! ####classes class Example: #---private---#8000FF#80FFFF---------------------------------------------------- def __init__(self,name): self.name=name def __repr__(self): return name #---public---#8000FF#80FFFF----------------------------------------------------- def hello(): print hello,self.name # TODO: Add more classes! spe-0.8.4.h/_spe/examples/example_notes.txt0000644000175000017500000000044110272471120017721 0ustar stanistaniblabla Here you can type some usefull information for the script, which will be saved in an external file. This external file has the same name as the script file but with a '.txt' extension. Once you make this empty, the external file and so the notes will also disappear.spe-0.8.4.h/_spe/examples/__init__.py0000644000175000017500000000000010275052655016430 0ustar stanistanispe-0.8.4.h/_spe/examples/signature.py0000644000175000017500000000200010754716453016701 0ustar stanistani# -*- coding: ISO-8859-1 -*- __author__ = 'www.stani.be' __license__ = 'GPL' __doc__ = """ This module was originally developed for SPE - Stani's Python Editor Pleave leave this header intact. Homepage: http://pythonide.stani.be Email: spe.stani.be@gmail.com Copyright: (c) 2005 www.stani.be License: GPL (contact me for other licenses) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ spe-0.8.4.h/_spe/examples/uml_example.py0000644000175000017500000000242610272471120017204 0ustar stanistaniclass Timer: def __init__(self): pass #---private def _synchronize(self): pass #---public def start(self): pass def stop(self): pass class Frame: def __init__(self): pass #---output def clear(self): pass def write(self): pass #---events def onLeftMouseClick(self): pass def onRightMouseClick(self): pass class Dialog(Frame): def __init__(self): pass #---data def verify(self): pass def reset(self): pass #---events def onOk(self): pass def onCancel(self): pass class Warning(Dialog,Timer): #---separator def question(self): pass class Window(Frame): def __init__(self): pass #---transform def move(self): pass def resize(self): pass #---events def onMaximize(self): pass def onMinimize(self): pass def onClose(self): pass class ScrolledWindow(Window): def __init__(self): pass #---scrollbars def setHscroll(self): pass def setVscroll(self): pass class SplitWindow(Window): def split(self): pass spe-0.8.4.h/_spe/sidebar/__init__.py0000644000175000017500000000000010272471120016210 0ustar stanistanispe-0.8.4.h/_spe/sidebar/Browser.py0000644000175000017500000000156510366063006016121 0ustar stanistaniimport wx import os import _spe.info as info class Browser(wx.GenericDirCtrl) : def __init__ (self, parent, id, init_path=''): wx.GenericDirCtrl.__init__(self,parent,id, dir = init_path, #size=(200,225), filter = info.WILDCARD_EXTENDED, style = wx.DIRCTRL_SHOW_FILTERS) self.dir = init_path self.tree = self.GetTreeCtrl() self.home = os.path.dirname(info.INFO['userPath']) self.tree.Bind(wx.EVT_LEFT_DCLICK, self.onClick) self.tree.Bind(wx.EVT_RIGHT_DOWN, self.onClick) def update(self): self.SetPath(self.dir) #onClick def onClick (self, event) : event.Skip() path = self.GetFilePath() if os.path.isfile(path): self.open(path) def open(self, fname) : pass spe-0.8.4.h/_spe/plugins/spe_xrced.py0000644000175000017500000000033310772205444016517 0ustar stanistaniimport os, sys try: from wx.tools.XRCed import xrced except ImportError: from plugins.XRCed import xrced parent_path = os.path.dirname(os.path.dirname(xrced.__file__)) sys.path.append(parent_path) xrced.main()spe-0.8.4.h/_spe/plugins/__init__.py0000644000175000017500000000035610272471120016276 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """This package contains various contributions for spe.""" __doc__=INFO['doc']%INFO spe-0.8.4.h/_spe/plugins/spe_winpdb.py0000644000175000017500000002277210764106050016702 0ustar stanistani# -*- coding: ISO-8859-1 -*- __author__ = 'www.stani.be' __license__ = 'GPL' __doc__ = """ This module was originally developed for SPE - Stani's Python Editor Pleave leave this header intact. Homepage: http://pythonide.stani.be Email: spe.stani.be@gmail.com Copyright: (c) 2005 www.stani.be License: GPL (contact me for other licenses) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import os, thread import wx import _spe.info as info import _spe.Menu as Menu from dialogs import winpdbDialog ###import winpdb ##from _spe.plugins.winpdb.rpdb2 import CSimpleSessionManager ##from _spe.plugins.winpdb.winpdb import __file__ as WINPDB #import winpdb try: import winpdb winpdb_dir = os.path.dirname(winpdb.__file__) except ImportError: plugins_dir = os.path.dirname(__file__) winpdb_dir = os.path.join(plugins_dir, 'winpdb') WINPDB = os.path.join(winpdb_dir, 'winpdb.py') import sys sys.path.insert(0, winpdb_dir) from rpdb2 import CSimpleSessionManager from rpdb2 import start_embedded_debugger del sys.path[0] if info.WIN and ' ' in WINPDB: WINPDB = '"%s"'%WINPDB def _(x): return x class SessionManager(CSimpleSessionManager): command_line = '' debugger = False #---private def __init__(self,runner): self.runner = runner self.app = runner.app self.encrypted = runner.app.fCrypto CSimpleSessionManager.__init__(self,fAllowUnencrypted = not self.encrypted) def _ask_to_launch_debugger(self,status,message,showDialog): if self.debugger: return child = self.app.childActive child.setStatus(status) if showDialog: dlg = wx.MessageDialog(child.frame, '%s\nDo you want to launch the debugger?\n\n'%message, 'SPE - %s'%self.command_line, wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION ) answer = dlg.ShowModal() dlg.Destroy() else: answer = wx.ID_CANCEL if answer == wx.ID_YES: self.runner.debug() else: self.request_go() def _feedback_terminate(self): #print "_feedback_terminate" self.runner.running = False self.runner._check_run(False) child = self.app.childActive child.setStatus('Terminated "%s"'%self.command_line) child.statusBar.throbber.stop() #---exception callbacks def unhandled_exception_callback(self): #print "unhandled_exception_callback" wx.CallAfter(self._ask_to_launch_debugger, status = 'Unhandled exception at "%s"'%self.command_line, message = 'An unhandled exception occurred.', showDialog = self.runner.exceptionPrevious) def script_about_to_terminate_callback(self): #print "script_about_to_terminate_callback" child = self.app.childActive wx.CallAfter(child.setStatus, 'Terminating "%s"'%self.command_line) self.request_go() def script_terminated_callback(self): #print "script_terminated_callback" wx.CallAfter(self._feedback_terminate) self.detach() #---public def debug(self): """Attach WinPdb to the running script.""" #todo: encrypted child = self.app.childActive (rid, pwd) = self.prepare_attach() args = [os.P_NOWAIT, info.PYTHON_EXEC, info.PYTHON_EXEC, #WINPDB, WINPDB] if not self.encrypted: args.append('-t') if info.WIN: args.extend(['-p"%s"'%pwd]) args.extend(['-a',rid]) try: os.spawnl(*args) self.debugger = True child.setStatus('WinPdb Debugger is attached to "%s".'%self.command_line,1) except Exception, message: child.setStatus('WinPdb Debugger failed: "%s".'%message,1) def launch(self, command_line, fchdir = True): """Launch a script with rpdb2.""" self.command_line = command_line #Give launching feedback child = self.app.childActive child.statusBar.throbber.run() child.setStatus('Running "%s"'%command_line) self.runner._check_run(True) self.runner.running = True thread.start_new_thread(CSimpleSessionManager.launch,(self,fchdir,command_line)) class Runner: argumentsPrevious = [] dlg_arguments = '' exceptionPrevious = True #exitPrevious = False running = False def __init__(self,app): self.app = app #initialize self.session = None self.title = 'SPE - Run file' if app.fCrypto: self.title += ' (encrypted)' #assing method for check run tool button child = self.app.childActive if child.frame.menuBar: self._check_run = child.frame.menuBar.check_run_debug else: self._check_run = child.parentFrame.menuBar.check_run_debug def _debug_childActive(self): child = self.app.childActive if child.confirmSave() and not child.isNew(): name = child.fileName debugDialog = winpdbDialog.dialog(self.app.parentFrame,name) answer = debugDialog.ShowModal() debugDialog.Destroy() if answer != wx.ID_CANCEL: _info = self.app.debugInfo args = [os.P_NOWAIT, info.PYTHON_EXEC, info.PYTHON_EXEC] args.extend(_info['parameters']) if os.path.exists(name): if info.WIN and ' ' in name: name = '"%s"'%name args.append(name) script_args = _info['arguments'] if script_args: args.append(script_args) os.spawnl(*args) child.setStatus('WinPdb Debugger is succesfully started.',1) else: self._check_run(False) child.setStatus('WinPdb Debugger was cancelled.',1) else: self._check_run(False) child.setStatus('File must be saved before WinPdb Debugger is launched.',1) def switch(self): "Run/stop file" #todo: update toolbar if self.running: self.stop() else: child = self.app.childActive if child.confirmSave() and not child.isNew(): self.run(child) else: self.cancel() def run(self,child): """Show dialog for arguments and launch script.""" fileName = child.fileName from _spe.dialogs.runWinPdbDialog import RunWinPdbDialog runWinPdbDialog = RunWinPdbDialog(fileName, self.argumentsPrevious, self.exceptionPrevious, #self.exitPrevious, parent=self.app.parentFrame, id=-1) answer = runWinPdbDialog.ShowModal() dlg_arguments = runWinPdbDialog.arguments.GetValue() dlg_exception = runWinPdbDialog.exception.GetValue() #dlg_exit = runWinPdbDialog.exit.GetValue() runWinPdbDialog.Destroy() if answer == wx.ID_OK: self.argumentsPrevious.append(self.dlg_arguments) self.dlg_arguments = dlg_arguments self.exceptionPrevious = dlg_exception #self.exitPrevious = dlg_exit command_line = fileName if self.dlg_arguments: command_line += ' ' + self.dlg_arguments self.session = SessionManager(self) self.session.launch(command_line) else: self.cancel() def stop(self): """Stop script.""" try: self.session.stop_debuggee() except Exception, message: if message: child = self.app.childActive child.setStatus('WinPdb unhandled exception while stopping debuggee: "%s".'%message,1) def debug(self): """Debug running script or current script.""" if self.running: self.session.debug() else: self._debug_childActive() def cancel(self): """Cancel running a script. (feedback on toolbar)""" self._check_run(False) child = self.app.childActive child.setStatus('Running the script with WinPdb was cancelled.',1) spe-0.8.4.h/_spe/plugins/Pycheck.py0000644000175000017500000001473511002674135016136 0ustar stanistani"""File ImportChecks of pychecker2 is modified.""" import os import wx from wx.lib.evtmgr import eventManager import _spe.info as info if 1 or info.WIN: QUOTE = '"' else: QUOTE = '' COLOR = (wx.Colour(220,220,220),wx.Colour(255,255,255)) IGNORE = ['Warnings...'] METHOD_NAMES = ['byte code','compiler package'] try: import pychecker except ImportError: import _spe.plugins.pychecker as pychecker PYCHECKER = os.path.join(os.path.dirname(pychecker.__file__),'checker.py') try: import pychecker2 except ImportError: import _spe.plugins.pychecker2 as pychecker2 PYCHECKER2 = os.path.join(os.path.dirname(pychecker2.__file__),'main.py') METHOD_PATHS = [\ '%s%s --stdlib --blacklist --varlist'%(PYCHECKER,QUOTE), '%s%s --incremental'%(PYCHECKER2,QUOTE) ] #---------------------------------------------------------------------- class Panel(wx.ListCtrl): def __init__(self, notebook, page=5, *args, **kwds): wx.ListCtrl.__init__(self, notebook, -1,style=wx.LC_REPORT) self.notebook = notebook self.page = page self.panel = notebook.GetParent() self.process = None self.reset() self.InsertColumn(col=0, format=wx.LIST_FORMAT_LEFT, heading='Line',width=40) self.InsertColumn(col=1, format=wx.LIST_FORMAT_LEFT, heading='Remark',width=600) self.InsertColumn(col=2, format=wx.LIST_FORMAT_LEFT, heading='File',width=200) self.InsertColumn(col=3, format=wx.LIST_FORMAT_LEFT, heading='Path',width=400) self.InsertStringItem(0,'') if info.DARWIN: ctrl = 'Cmd' else: ctrl = 'Ctrl' self.SetStringItem(0,1,'Press %s+Alt+C to check the current file [%s method]'%(ctrl,METHOD_NAMES[self.methodIndex],)) #events (eventManager doesn't work here ;-() wx.EVT_LIST_ITEM_SELECTED(self,-1,self.onSelect) # We can either derive from wx.Process and override OnTerminate # or we can let wx.Process send this window an event that is # caught in the normal way... wx.EVT_END_PROCESS(self,-1,self.OnProcessEnded) def reset(self): self.list = [('','')] self.fileIndex = 0 self.lastFile = 0 self.methodIndex = 1 def __del__(self): if self.process is not None: self.process.Detach() self.process.CloseOutput() self.process = None def check(self): if not self.process: if self.panel.confirmSave('File must be saved to be analyzed by Pychecker.'): if self.panel.isNew(): return self.reset() #update wx ListCtrl self.DeleteAllItems() self.InsertStringItem(0,'') self.SetStringItem(0,1,'%s checking...'%METHOD_NAMES[self.methodIndex]) self.SetItemBackgroundColour(0,wx.Colour(255,200,200)) self.focus() #register idle event eventManager.Register(self.OnIdle, wx.EVT_IDLE, self) #initialize self.index = 1 self.methodIndex = 1 self.started = 1 fileName = self.panel.fileName path = os.path.dirname(fileName) #change path os.chdir(path) #start process self.process = wx.Process(self) self.process.Redirect() #run pychecker cmd = 'python -u %s%s %s%s%s'%\ (QUOTE, os.path.join(self.panel.parentPanel.pathPlugins,METHOD_PATHS[self.methodIndex]), QUOTE, fileName, QUOTE) pid = wx.Execute(cmd, wx.EXEC_ASYNC, self.process) else: self.panel.parentPanel.message('Sorry, only one pycheck at a time.') def OnCloseStream(self, evt): self.process.CloseOutput() def OnIdle(self, evt): if self.process is not None: stream = self.process.GetInputStream() if stream.CanRead(): text = stream.read() self.add(text) def OnProcessEnded(self, evt): self.DeleteItem(0) if self.list: del self.list[0] self.index -=1 eventManager.DeregisterListener(self.OnIdle) self.focus() wx.Bell() stream = self.process.GetInputStream() if stream.CanRead(): text = stream.read() self.add(text) self.process.Destroy() self.process = None def add(self,text): self.focus() if self.started: #self.DeleteAllItems(0) self.started = 0 text = text.splitlines() for data in text: data = data.strip() if data and data not in IGNORE: if self.methodIndex == 0: i=1 columns = data[2:].split(':') if len(columns)==3: file, line, remark = columns file = data[:2]+file else: file = '' line = '' remark = columns[0] else: f = data.find(':',2) file = data[:f] l = data.find(' ',f) line = data[f+1:l] remark = data[l+1:] if not line.isdigit(): continue self.InsertStringItem(self.index,line) self.SetStringItem(self.index,1,remark) self.SetStringItem(self.index,2,os.path.basename(file)) self.SetStringItem(self.index,3,os.path.dirname(file)) self.list.insert(self.index,(file,line)) if file != self.lastFile: self.lastFile = file self.fileIndex += 1 #self.SetItemBackgroundColour(self.index,COLOR[self.fileIndex%2]) self.index+=1 def onSelect(self,event): file,line=self.list[event.GetIndex()] if file and line: self.panel.parentPanel.openList(file,int(line)-1) def focus(self): self.notebook.SetSelection(self.page) spe-0.8.4.h/_spe/plugins/pychecker2/0000755000175000017500000000000011004131464016216 5ustar stanistanispe-0.8.4.h/_spe/plugins/pychecker/0000755000175000017500000000000011004131466016136 5ustar stanistanispe-0.8.4.h/_spe/plugins/XRCed/0000755000175000017500000000000011004131464015124 5ustar stanistanispe-0.8.4.h/_spe/plugins/winpdb/0000755000175000017500000000000011004131464015442 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/0000755000175000017500000000000011004131466015554 5ustar stanistanispe-0.8.4.h/_spe/plugins/kiki/0000755000175000017500000000000011004131465015107 5ustar stanistanispe-0.8.4.h/_spe/plugins/pychecker2/ClassChecks.py0000644000175000017500000003372210576076542021007 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Check import Warning from pychecker2 import symbols from pychecker2.util import * from compiler.misc import mangle from compiler import ast, walk _ignorable = {} for ignore in ['repr', 'dict', 'class', 'doc', 'str']: _ignorable['__%s__' % ignore] = 1 class GetDefs(BaseVisitor): "Record definitions of a attribute of self, who's name is provided" def __init__(self, name): self.selfname = name self.result = {} def visitAssAttr(self, node): if isinstance(node.expr, ast.Name) and \ node.expr.name == self.selfname and \ isinstance(node.parent, (ast.Assign, ast.AssTuple)): self.result[node.attrname] = node def visitClass(self, node): # ignore nested classes pass class GetRefs(BaseVisitor): "Record references to a attribute of self, who's name is provided" def __init__(self, name): self.selfname = name self.result = {} def visitAssAttr(self, node): if isinstance(node.expr, ast.Name) and \ node.expr.name == self.selfname and \ not isinstance(node.parent, (ast.Assign, ast.AssTuple)): self.result[node.attrname] = node self.visitChildren(node) def visitGetattr(self, node): if isinstance(node.expr, ast.Name) and \ node.expr.name == self.selfname: self.result[node.attrname] = node self.visitChildren(node) def visitClass(self, node): # ignore nested classes pass def _get_methods(class_scope): return type_filter(class_scope.get_children(), symbols.FunctionScope) class NotSimpleName(Exception): pass # compress Getattr(Getattr(Name(x), y), z) -> "x.y.z" def get_name(node): if isinstance(node, ast.Getattr): return get_name(node.expr) + (node.attrname, ) elif isinstance(node, ast.Name): return (node.name,) else: raise NotSimpleName def get_base_names(scope): names = [] for b in scope.node.bases: try: names.append(get_name(b)) except NotSimpleName: # FIXME: hiding expressions pass return names def find_in_module(package, remotename, names, checker): # No other names, must be a name from the module if not names: f = checker.check_module(package) if f: return find_scope_going_down(f.root_scope, [remotename], checker) return None # complex name lookup try: # first, get the real name of the package name = package.__name__ module = __import__(name, globals(), {}, ['']) except AttributeError: # ok, so its a fake module... go with that module = package if remotename: name += "." + remotename # now import it, and chase down any other modules submodule = getattr(module, names[0], None) if type(submodule) == type(symbols): return find_in_module(submodule, None, names[1:], checker) # object in the module is not another module, so chase down the source f = checker.check_module(submodule) if f: return find_scope_going_down(f.root_scope, names, checker) return None def find_scope_going_down(scope, names, checker): "Drill down scopes to find definition of x.y.z" for c in scope.get_children(): if getattr(c, 'name', '') == names[0]: if len(names) == 1: return c return find_scope_going_down(c, names[1:], checker) # Not defined here, check for import return find_imported_class(scope.imports, names, checker) def find_imported_class(imports, names, checker): # may be defined by import for i in range(1, len(names) + 1): # try x, then x.y, then x.y.z as imported names try: name = ".".join(names[:i]) ref = imports[name] # now look for the rest of the name result = find_in_module(ref.module, ref.remotename, names[i:], checker) if result: return result except (KeyError, ImportError): pass return None def find_scope_going_up(scope, names, checker): "Search up to find scope defining x of x.y.z" for p in parents(scope): if p.defs.has_key(names[0]): return find_scope_going_down(p, names, checker) # name imported via 'from module import *' try: return find_in_module(p.imports[names[0]].module, None, names, checker) except KeyError: return None def get_base_classes(scope, checker): result = [] for name in get_base_names(scope): base = find_scope_going_up(scope, name, checker) if base: result.append(base) result.extend(get_base_classes(base, checker)) return result def conformsTo(a, b): alen = len(a.node.argnames) blen = len(b.node.argnames) # f(a, *args, **kw) conforms to f(a, b, *args, **kw) # f(a, *args) conforms to f(a, b, *args) # f(a, *args) conforms to f(a, b, c) # f(a, b, c, *args) does not conform to f(a, b) if alen == blen: if a.node.kwargs == b.node.kwargs and a.node.varargs == b.node.varargs: return 1 if a.node.varargs and alen - 1 <= blen: return a.node.kwargs == b.node.kwargs return None class AttributeCheck(Check): "check `self.attr' expressions for attr" unknownAttribute = Warning('Report unknown object attributes in methods', 'Class %s has no attribute %s') unusedAttribute = Warning('Report attributes unused in methods', 'Attribute %s is not used in class %s') methodRedefined = Warning('Report the redefinition of class methods', 'Method %s in class %s redefined') signatureChanged = Warning('Report methods whose signatures do not ' 'match base class methods', 'Signature does not match method ' '%s in base class %s') attributeInitialized = \ Warning('Report attributes not initialized in __init__', 'Attribute %s is not initialized in __init__') def check(self, file, checker): def visit_with_self(Visitor, method): if not method.node.argnames: return {} return walk(method.node, Visitor(method.node.argnames[0])).result # for all class scopes for node, scope in file.class_scopes(): init_attributes = None # attributes initilized in __init__ attributes = {} # "self.foo = " kinda things methods = {} # methods -> scopes # get attributes defined on self for m in _get_methods(scope): defs = visit_with_self(GetDefs, m) if m.name == '__init__': init_attributes = defs attributes.update(defs) methods[mangle(m.name, scope.name)] = m # complain about attributes not initialized in __init__ if init_attributes is not None: for name, node in dict_minus(attributes, init_attributes).items(): file.warning(node, self.attributeInitialized, name) # collect inherited gunk: methods and attributes # check for non-conformant methods inherited_methods = scope.defs.copy() inherited_attributes = attributes.copy() for base in get_base_classes(scope, checker): for m in _get_methods(base): inherited_attributes.update(visit_with_self(GetDefs, m)) mname = mangle(m.name, base.name) if m.name != "__init__" and \ methods.has_key(mname) and \ not conformsTo(methods[mname], m): file.warning(methods[mname].node, self.signatureChanged, m.name, base.name) else: methods[mname] = m inherited_methods.update(base.defs) # complain about attributes with the same name as methods both = dict_intersect(attributes, inherited_methods) for name, node in both.items(): file.warning(node, self.methodRedefined, name, scope.name) # find refs on self refs = {} for m in _get_methods(scope): refs.update(visit_with_self(GetRefs, m)) # Now complain about refs on self that aren't known unknown = dict_minus(refs, inherited_methods) unknown = dict_minus(unknown, _ignorable) unknown = dict_minus(unknown, scope.defs) unknown = dict_minus(unknown, inherited_attributes) for name, node in unknown.items(): file.warning(node, self.unknownAttribute, scope.name, name) unused = dict_minus(attributes, refs) for name, node in unused.items(): if name.startswith('__'): file.warning(node, self.unusedAttribute, name, scope.name) class GetReturns(BaseVisitor): def __init__(self): self.result = [] def visitReturn(self, node): self.result.append(node) def visitFunction(self, node): pass visitClass = visitFunction class InitCheck(Check): initReturnsValue = Warning('Report value returned from __init__', 'Method __init__ should not return a value') def check(self, file, unused_checker): for node, scope in file.class_scopes(): for m in _get_methods(scope): if m.name == '__init__': for r in walk(m.node.code, GetReturns()).result: if isinstance(r.value, ast.Const) and \ r.value.value is None: continue if isinstance(r.value, ast.Name) and \ r.value.name == 'None': continue file.warning(r, self.initReturnsValue) special = { '__cmp__': 2, '__del__': 1, '__delitem__': 2, '__eq__': 2, '__ge__': 2, '__getitem__': 2, '__gt__': 2, '__hash__': 1, '__le__': 2, '__len__': 1, '__lt__': 2, '__ne__': 2, '__nonzero__': 1, '__repr__': 1, '__setitem__': 3, '__str__': 1, '__getattr__': 2, '__setattr__': 3, '__delattr__': 2, '__len__': 1, '__delitem__': 2, '__iter__': 1, '__contains__': 2,'__setslice__': 4,'__delslice__': 3, '__add__': 2, '__sub__': 2, '__mul__': 2, '__floordiv__': 2, '__mod__': 2, '__divmod__': 2, '__lshift__': 2, '__rshift__': 2, '__and__': 2, '__xor__': 2, '__or__': 2, '__div__': 2, '__truediv__': 2, '__radd__': 2, '__rsub__': 2, '__rmul__': 2, '__rdiv__': 2, '__rmod__': 2, '__rdivmod__': 2, '__rpow__': 2, '__rlshift__': 2, '__rrshift__': 2, '__rand__': 2, '__rxor__': 2, '__ror__': 2, '__iadd__': 2, '__isub__': 2, '__imul__': 2, '__idiv__': 2, '__imod__': 2, '__ilshift__': 2, '__irshift__': 2, '__iand__': 2, '__ixor__': 2, '__ior__': 2, '__neg__': 1, '__pos__': 1, '__abs__': 1, '__invert__': 1, '__complex__': 1, '__int__': 1, '__long__': 1, '__float__': 1, '__oct__': 1, '__hex__': 1, '__coerce__': 2, '__new__': None, '__getinitargs__': 1, '__reduce__': 1, '__getstate__': 1,'__setstate__': 2, '__copy__': 1, '__deepcopy__': 1, '__pow__': 2, '__ipow__': 2, # 2 or 3 '__call__': None, # any number > 1 '__getslice__': 3, # deprecated '__getattribute__': 2, } def check_special(scope): try: count = special[scope.name] max_args = len(scope.node.argnames) min_args = max_args - len(scope.node.defaults) if min_args > count or max_args < count or \ scope.node.varargs or scope.node.kwargs: return special[scope.name] except KeyError: pass return None class SpecialCheck(Check): specialMethod = Warning('Report special methods with incorrect ' 'number of arguments', 'The %s method requires %d argument%s, ' 'including self') notSpecial = Warning('Report methods with "__" prefix and suffix ' 'which are not defined as special methods', 'The method %s is not a special method, ' 'but is reserved.') def check(self, file, unused_checker): for node, scope in file.class_scopes(): for m in _get_methods(scope): n = check_special(m) if n: file.warning(m.node, self.specialMethod, m.name, n, n > 1 and "s" or "") name = m.name if name.startswith('__') and name.endswith('__') and \ name != '__init__' and not special.has_key(name): file.warning(m.node, self.notSpecial, name) class BackQuote(BaseVisitor): def __init__(self, selfname): self.results = [] self.selfname = selfname def visitBackquote(self, node): if isinstance(node.expr, ast.Name) and node.expr.name == self.selfname: self.results.append(node) class ReprCheck(Check): backquoteSelf = Warning('Report use of `self` in __repr__ methods', 'Using `self` in __repr__') def check(self, file, unused_checker): for node, scope in file.class_scopes(): for m in _get_methods(scope): if m.name == '__repr__' and m.node.argnames: visitor = BackQuote(m.node.argnames[0]) for n in walk(m.node.code, visitor).results: file.warning(n, self.backquoteSelf) spe-0.8.4.h/_spe/plugins/pychecker2/ScopeChecks.py0000644000175000017500000000222410576076542021004 0ustar stanistani from pychecker2.Check import Check from pychecker2.Warning import Warning from pychecker2 import util from compiler.ast import * class RedefineCheck(Check): redefinedScope = Warning('Report redefined scopes', 'Scope (%s) is redefined at line %d') def check(self, file, unused_checker): names = {} # map name, parent to this scope for node, scope in file.scopes.items(): if hasattr(node, 'name'): # classes, functions key = (scope.parent, node.name) if names.has_key(key): # oops, another scope has the same name and parent first = node second = names[key] # but don't warn if the parent node is the same If or Try if util.try_if_exclusive(first, second): continue if first.lineno > second.lineno: second, first = first, second file.warning(first, self.redefinedScope, first.name, second.lineno) names[key] = node spe-0.8.4.h/_spe/plugins/pychecker2/ReturnChecks.py0000644000175000017500000000243010576076542021211 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Check import Warning from pychecker2.util import BaseVisitor, type_filter from pychecker2 import symbols from compiler import ast, walk class Returns(BaseVisitor): def __init__(self): self.result = [] def visitReturn(self, node): self.result.append(node) # Don't descend into other scopes def visitFunction(self, node): pass visitClass = visitFunction visitLambda = visitFunction def _is_implicit(node): if isinstance(node, ast.Const) and node.value is None: return 1 return None class MixedReturnCheck(Check): mixedReturns = \ Warning('Report functions using "return" and "return value"', 'Function %s uses both "return" and "return value"') def check(self, file, unused_checker): for scope in type_filter(file.scopes.values(), symbols.FunctionScope): returns = walk(scope.node.code, Returns()).result empty, value = [], [] for node in returns: if _is_implicit(node.value): empty.append(node) else: value.append(node) if len(empty) > 0 and len(value) > 0: file.warning(empty[0], self.mixedReturns, scope.name) spe-0.8.4.h/_spe/plugins/pychecker2/File.py0000644000175000017500000000212510576076542017471 0ustar stanistanifrom pychecker2.util import parents from compiler import ast class File: def __init__(self, name): self.name = name self.parseTree = None self.scopes = {} self.root_scope = None self.warnings = [] def __cmp__(self, other): return cmp(self.name, other.name) def warning(self, line, warn, *args): lineno = getattr(line, 'lineno', line) if not lineno and hasattr(line, 'parent'): for p in parents(line): if p.lineno: lineno = p.lineno break self.warnings.append( (lineno, warn, args) ) def scope_filter(self, type): return [x for x in self.scopes.iteritems() if isinstance(x[0], type)] def function_scopes(self): return self.scope_filter(ast.Function) def class_scopes(self): return self.scope_filter(ast.Class) def not_class_scopes(self): result = [] for n, s in self.scopes.iteritems(): if not isinstance(n, ast.Class): result.append( (n, s) ) return result spe-0.8.4.h/_spe/plugins/pychecker2/ConditionalChecks.py0000644000175000017500000000252510576076542022202 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.util import BaseVisitor from compiler import ast, walk class ConstantFinder(BaseVisitor): def __init__(self): self.result = [] def visitConst(self, node): if isinstance(node.parent, (ast.Or, ast.Not, ast.And)): self.result.append((node, `node.value`)) def visitName(self, node): if node.name == 'None': if isinstance(node.parent, (ast.Or, ast.Not, ast.And)): self.result.append((node, 'None')) class GetConditionalConstants(BaseVisitor): def __init__(self): self.result = [] def visitIf(self, node): for test, code in node.tests: self.result.extend(walk(test, ConstantFinder()).result) def visitWhile(self, node): self.result.extend(walk(node.test, ConstantFinder()).result) visitListCompIf = visitWhile visitAssert = visitWhile class ConstantCheck(Check): constantInConditional = \ Warning('Report constants used in conditionals', 'Constant used in conditional %s') def check(self, file, unused_checker): if file.parseTree: v = GetConditionalConstants() for n, value in walk(file.parseTree, v).result: file.warning(n, self.constantInConditional, value) spe-0.8.4.h/_spe/plugins/pychecker2/NOTES.txt0000644000175000017500000001076710576076542017704 0ustar stanistaniThis is a re-write of pychecker using traditional parse tree techniques, rather than the bytecode. There are some other design changes, related to Warning objects and Option handling. In general, pychecker2 tries to distribute checks to separate classes. These classes are more self-contained: they hold onto the option variables and define the Warning objects they support. ToDo: All missing stuff Always returning None It is illegal to delete a name from the local namespace if it occurs as a free variable in a nested block. More path analysis used before set for if/else try/except Warn about unpacking args: def f(a, (b, c)): pass Items still missing: Error suppression (errors may be suppressed globally) Detail of exception is an exception Local used after deleted, already deleted, deleted before set Not calling base class __init__ Using return value which is always None Wrong # of args on function (including ctor) Function arguments, kwargs Abstract methods exec may use locals/globals import x with from x import Modifying a default parameter Tuple access to list list[1, 2] List .append() takes one argument Return None from __getattr__ string iteration Inconsistent return type Object has no attr Method read as attribute, but not called: Function always returns None (use empty return) Unpack wrong size Unpack wrong type Exec warnings Security warning: input() Module imports itself Complexity Doc strings New python features: slots properties integer division Warning for string raising Bugs: More member not used Speed Is __file__ a builtin? Aliases: class C: def f(a, b): pass def g(a, b): pass h = f h = g # redef of h, not caught now foo = 1 del foo # should not be unused from __future__ import produces unused warnings import of readline has side effect on input/raw_input, and should be marked as used Important stuff: If you want to add new checks, there are some parts to be aware of: File A stupid data structure to hold everything we know about a file to be checked. Members: name The file name. parseTree The root of the Abstract Syntax Tree returned from compiler.parseFile. Will be None if the file won't even parse. scopes A dictionary of { node, scope } computed with from compiler.symbols. For convenience, scopes also refer back to the node and to the enclosing parent scope (node and parent, respectively). root_scope Convience for scopes[parseTree] Check Basic step for checking a file. Usually contributes Warnings or additional information to File. New checks will subclass this, and be added to the chain of checks given in main(). Warning A description of a warning emitted by pychecker. CheckList Contains "global" check information: cached module data and the list of Check objects. Command line options are pulled from each check. A Warning is also turned into a boolean-style command line option. To add a new check, write a class (e.g., CompareCheck) that subclasses the Check class. In its check method if you need to visit nodes of a particular type, write a Visitor class (subclass of BaseVisitor) which has a visit method, where is the name of a type of node to visit. See http://www.python.org/~jeremy/compiler/module-compiler.ast.html for the types of the nodes or print file.parseTree to see what classes all the nodes are. See the OpChecks.CompareCheck class for an example of a check that visits all Compare nodes and the OpChecksExceptCheck class for an example that visits all TryExcept nodes. New checks should have unit tests in utest/. spe-0.8.4.h/_spe/plugins/pychecker2/__init__.py0000644000175000017500000000000310576076542020342 0ustar stanistani"" spe-0.8.4.h/_spe/plugins/pychecker2/test.py0000644000175000017500000000267610576076542017604 0ustar stanistaniimport os import sys import unittest import glob def test(modules, verbosity): for m in modules: s = unittest.defaultTestLoader.loadTestsFromName(m) result = unittest.TextTestRunner(verbosity=verbosity).run(s) if not result.wasSuccessful(): return 1 return 0 def _modules(root): modules = [] files = glob.glob(os.path.join(root, 'utest', '*.py')) files.sort() for fname in files: fname = os.path.split(fname)[1] # remove path module = 'pychecker2.utest.' + os.path.splitext(fname)[0] if not module.endswith('_'): # ignore __init__ modules.append(module) return modules class Usage(Exception): pass def main(args): import getopt verbosity = 1 try: opts, files = getopt.getopt(args, 'v') for opt, arg in opts: if opt == '-v': verbosity += 1 else: raise Usage('unknown option ' + opt) except getopt.GetoptError, detail: raise Usage(str(detail)) root = os.path.dirname(os.path.realpath(sys.argv[0])) pychecker2 = os.path.split(root)[0] sys.path.append(pychecker2) return test(_modules(root), verbosity) if __name__ == '__main__': try: sys.exit(main(sys.argv[1:])) except Usage, error: err = sys.stderr print >>err, "Error: " + str(error) print >>err, "Usage: %s [-v]" % sys.argv[0] sys.exit(1) spe-0.8.4.h/_spe/plugins/pychecker2/ParseChecks.py0000644000175000017500000000563511002666475021011 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Warning import Warning from pychecker2.Options import BoolOpt from pychecker2 import symbols from compiler import parseFile, walk import parser def _parent_link(node): for c in node.getChildNodes(): c.parent = node _parent_link(c) class ParseCheck(Check): syntaxErrors = Warning('Report/ignore syntax errors', 'Unable to parse: %s') def __init__(self): self.main = None def get_options(self, options): desc = 'Ignore module-level code protected by __name__ == "__main__"' options.add(BoolOpt(self, 'main', desc, 1)) def check(self, file, unused_checker): try: file.parseTree = parseFile(file.name) # link each node to it's parent _parent_link(file.parseTree) file.parseTree.parent = None except parser.ParserError, detail: file.warning(1, self.syntaxErrors, detail.args[0]) except IOError, detail: file.warning(0, self.syntaxErrors, detail.strerror) if not file.parseTree: return if not self.main: # remove __name__ == '__main__' code from module-level for n in file.parseTree.node.nodes: try: test, code = n.tests[0] comparison, value = test.ops[0] if comparison == '==': try: if test.expr.name == '__name__' and \ value.value == '__main__': file.parseTree.node.nodes.remove(n) break except AttributeError: if test.expr.value == '__main__' and \ value.name == '__name__': file.parseTree.node.nodes.remove(n) break except (AttributeError, IndexError): pass file.scopes = walk(file.parseTree, symbols.SymbolVisitor()).scopes file.root_scope = file.scopes[file.parseTree] # add starting lineno into scopes, since they don't have it for k, v in file.scopes.items(): v.lineno = k.lineno # define the root of the scope tree (global scope, within # the module) file.root_scope.lineno = 1 # create a mapping from scopes back to the nodes which made 'em for node, scope in file.scopes.items(): scope.node = node # create a mapping from each scope back to it's enclosing scope for s in file.scopes.values(): for c in s.get_children(): c.parent = s file.root_scope.parent = None # initialize the mapping of imported names to modules for s in file.scopes.values(): s.imports = {} spe-0.8.4.h/_spe/plugins/pychecker2/TestSupport.py0000644000175000017500000000352710576076542021135 0ustar stanistanifrom pychecker2 import main from pychecker2 import Options import unittest class WarningTester(unittest.TestCase): def __init__(self, arg): unittest.TestCase.__init__(self, arg) self.options = Options.Options() self.checklist = main.create_checklist(self.options) self.argv = [] def check_warning(self, w, expected_line, expected_type, *expected_args): warn_line, warn_type, warn_args = w try: self.assertEqual(warn_type, expected_type) self.assertEqual(warn_line, expected_line) self.assertEqual(len(warn_args), len(expected_args)) for i in range(len(expected_args)): self.assertEqual(warn_args[i], expected_args[i]) except AssertionError: # help w/debugging print warn_line, warn_type, warn_args print expected_line, expected_type, expected_args raise def check_file(self, data): import tempfile, os fname = tempfile.mktemp() fp = open(fname, 'wb') try: fp.write(data) fp.close() f, = self.options.process_options(self.argv + [fname]) self.checklist.check_file(f) finally: fp.close() os.unlink(fname) return f def warning_file(self, f, line, warning, *args): assert len(f.warnings) == 1, "Not just one warning:" + `f.warnings` self.check_warning(f.warnings[0], line, warning, *args) def warning(self, test, line, warning, *args): test += '\n' f = self.check_file(test) self.warning_file(f, line, warning, *args) def silent(self, test): f = self.check_file(test) if f.warnings: print f.warnings self.assertEqual(len(f.warnings), 0) def setUp(self): self.argv = [] spe-0.8.4.h/_spe/plugins/pychecker2/VariableChecks.py0000644000175000017500000003223110576076542021461 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Options import Opt, BoolOpt from pychecker2.Warning import Warning from pychecker2.util import * from pychecker2 import symbols from compiler import ast, walk def _is_method(scope): return scope.__class__ is symbols.FunctionScope and \ scope.parent.__class__ is symbols.ClassScope def _is_self(scope, name): return _is_method(scope) and name in scope.node.argnames[:1] def is_arg_and_defaulted_to_same_name(name, scope): if isinstance(scope, symbols.FunctionScope): if name in scope.node.argnames and scope.node.defaults: # compute default args args = scope.node.argnames[:] # knock off kwargs if scope.node.kwargs: args = args[:-1] # knock off varags if scope.node.varargs: args = args[:-1] # take the last args as the defaults args = args[-len(scope.node.defaults):] try: # get the corresponding default arg value default = scope.node.defaults[args.index(name)] # must be a Name node of the same name if isinstance(default, ast.Name) and \ default.name == name: return 1 except ValueError: pass return None class ShadowCheck(Check): """Use symbol information to check that no scope defines a name already known to a parent scope""" defineNone = Warning('Report any redefinition of None', 'Do not redefine None') shadowBuiltins = Warning('Report names that shadow builtins', 'Identifier (%s) shadows builtin', 0) shadowIdentifier = Warning('Report names already defined in outer scopes', 'Identifier (%s) shadows definition in scope %s') def check(self, file, unused_checker): # warn if any name defined in a scope is defined in a parent scope # or even the builtins for node, scope in file.not_class_scopes(): for name in scope.defs: if name == 'None': file.warning(scope.defs[name], self.defineNone) continue if name in scope.globals: continue if is_arg_and_defaulted_to_same_name(name, scope): continue if _is_self(scope, name): continue if __builtins__.has_key(name): file.warning(scope.defs[name], self.shadowBuiltins, name) for p in parents(scope): if p.defs.has_key(name) and \ not isinstance(p, symbols.ClassScope): file.warning(scope.defs[name], \ self.shadowIdentifier, name, `p`) def _str_value(s): if type(s) == type(''): return eval(s) return s def _empty_function(stmts): if not stmts: return 1 stmt = stmts[0] # functions which only raise exceptions if isinstance(stmt, ast.Raise): return 1 # functions which do nothing if len(stmts) == 1 and isinstance(stmt, ast.Pass): return 1 # functions which just return a constant if len(stmts) == 1 and \ isinstance(stmt, ast.Return) and isinstance(stmt.value, ast.Const): return 1 # functions which only assert falsehood if isinstance(stmt, ast.Assert): if (isinstance(stmt.test, ast.Const) and not stmt.test.value) or \ (isinstance(stmt.test, ast.Name) and stmt.test.name == 'None'): return 1 return 0 class UnusedCheck(Check): """Use symbol information to check that no scope defines a name not used in this or any child scope""" unused = Warning('Report names not used', 'Identifier (%s) not used') def __init__(self): self.reportUnusedSelf = None self.unusedPrefixes = None def get_options(self, options): desc = 'Ignore unused identifiers that start with these values' default = ['unused', 'empty', 'dummy', '__pychecker__', '__all__', '__version__', 'ignored'] options.add(Opt(self, 'unusedPrefixes', desc, default)) desc = 'Ignore unused method "self" parameter' options.add(BoolOpt(self, 'reportUnusedSelf', desc)) def check(self, file, unused_checker): self.unusedPrefixes = _str_value(self.unusedPrefixes) def used(name, parent_scope): if parent_scope.uses.has_key(name): return 1 for c in parent_scope.get_children(): if used(name, c): return 1 return 0 for nodes, scope in file.not_class_scopes(): if isinstance(nodes, ast.Function): if _empty_function(nodes.code.nodes): continue # ensure that every defined variable is used in some scope for var in scope.defs: # ignore '_'... just because if var == '_': continue # check for method self if not self.reportUnusedSelf and _is_self(scope, var): continue # ignore names in the root scope which are not imported: # class defs, function defs, variables, etc, unless # they start with '_' if scope == file.root_scope: if not scope.imports.has_key(var): if not var.startswith('_'): continue for prefix in self.unusedPrefixes: if var.startswith(prefix): break else: if not used(var, scope) and not scope.globals.has_key(var): file.warning(scope.defs[var], self.unused, var) def _importedName(scope, name): if scope.imports.has_key(name): return 1 if scope.parent: return _importedName(scope.parent, name) return None class UnknownCheck(Check): """Use symbol information to check that no scope uses a name not defined in a parent scope""" unknown = Warning('Report names that are not defined', 'Unknown identifier: %s') builtins = {} builtins.update(__builtins__) builtins['__builtins__'] = __builtins__ builtins['WindowsError'] = getattr(__builtins__, 'WindowsError', None) def check(self, file, unused_checker): # if a name used is not found in the defined variables, complain for scope in file.scopes.values(): unknown = dict_minus(scope.uses, scope.defs) unknown = dict_minus(unknown, self.builtins) for var in unknown: for p in parents(scope): if p.defs.has_key(var): break else: if not _importedName(scope, var): file.warning(scope.uses[var], self.unknown, var) def _first_arg_defaulted(function_node): count = len(function_node.argnames) if function_node.varargs: count -= 1 if function_node.kwargs: count -= 1 if count > 0 and len(function_node.defaults) == count: return 1 return None class SelfCheck(Check): 'Check for simple self parameter' selfName = Warning('Report any methods whose first argument is not self', 'First argument to method %s (%s) is not in %s') selfDefault = Warning('Report a self parameter with a default value', 'First argument to method %s (%s) has a default value') functionSelf = Warning('Report functions (not methods) with ' 'arguments named "self"', 'Argument to function (%s) is "%s"') missingSelf = Warning('Report methods without "self"', 'Method %s is missing self parameter') def get_options(self, options): desc = 'Name of self parameter' default = ["self", "this", "s"] options.add(Opt(self, 'selfNames', desc, default)) desc = 'Suspicious self parameters' self.selfSuspicious = ["self"] options.add(Opt(self, 'selfSuspicious', desc, self.selfSuspicious)) def check(self, file, unused_checker): self.selfNames = _str_value(self.selfNames) self.selfSuspicious = _str_value(self.selfSuspicious) for node, scope in file.function_scopes(): args = node.argnames name = getattr(scope.node, 'name', 'lambda') if _is_method(scope): if not args: file.warning(scope.node, self.missingSelf, name) else: if args[0] not in self.selfNames: file.warning(scope.node, self.selfName, name, args[0], `self.selfNames`) if _first_arg_defaulted(scope.node): file.warning(scope.node, self.selfDefault, name, args[0]) else: for arg in args: if arg in self.selfSuspicious: file.warning(scope.defs[arg], self.functionSelf, name, arg) class UnpackCheck(Check): 'Mark all unpacked variables as used' def __init__(self): self.unpackedUsed = None def get_options(self, options): desc = 'Do not treat variables used in tuple assignment as used' options.add(BoolOpt(self, 'unpackedUsed', desc, 1)) def check(self, file, unused_checker): if not self.unpackedUsed: return class Visitor: def visitAssTuple(self, node): for c in node.getChildNodes(): for n in parents(c): try: file.scopes[n].uses[c.name] = node break except (KeyError, AttributeError): pass visitAssList = visitAssTuple # local args unpacked on the `def' line are used, too for scope_node, scope in file.function_scopes(): for arg in type_filter(scope_node.argnames, tuple): for unpacked in ast.flatten(arg): scope.uses[unpacked] = scope.uses.get(unpacked, scope_node) if file.root_scope: walk(file.root_scope.node, Visitor()) def intersect2(a, b): return [i for i in a if i in b] def intersect(items): result = items[0] for item in items[1:]: result = intersect2(result, item) return result class UsedBeforeSetCheck(Check): usedBeforeDefined = \ Warning('Report variables that may be used before they are defined', 'The local %s may be used before defined') def check(self, file, unused_checker): class Visitor(BaseVisitor): def __init__(self, defines = None, uses = None): # list of vars defined self.defines = [] # name->node vars used before defined self.uses = {} if defines is not None: self.defines = defines[:] if uses is not None: self.uses = uses.copy() def visitFunction(self, n): self.defines.append(n.name) visitClass = visitFunction visitAssName = visitFunction def visitGlobal(self, node): for name in node.names: self.defines.append(name) def visitListComp(self, n): # visit qualifiers before expression children = ast.flatten_nodes(n.quals) + [n.expr] for c in children: self.visit(c) def visitName(self, n): if n.name not in self.defines: self.uses[n.name] = self.uses.get(n.name, n) def visitIf(self, n): if not n.else_: return visits = [] for test, code in n.tests: visits.append(walk(code, Visitor(self.defines, self.uses))) visits.append(walk(n.else_, Visitor(self.defines, self.uses))) # compute the intersection of defines self.defines = intersect([v.defines for v in visits]) # compute the union of uses, perserving first occurances union = {} visits.reverse() for v in visits: union.update(v.uses) union.update(self.uses) self.uses = union for node, scope in file.function_scopes(): predefined = ast.flatten(scope.params) + scope.imports.keys() visitor = walk(node.code, Visitor(predefined)) usedBefore = dict_intersect(visitor.uses, scope.defs) for name, use_node in usedBefore.items(): file.warning(use_node, self.usedBeforeDefined, name) spe-0.8.4.h/_spe/plugins/pychecker2/FormatStringChecks.py0000644000175000017500000001547210576076542022363 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.util import BaseVisitor from pychecker2.Warning import Warning from compiler import ast, walk from types import * import re class UnknownError(Exception): pass def _compute_node(node, recurse): if isinstance(node, ast.Add): return recurse(node.left) + recurse(node.right) elif isinstance(node, ast.Mul): return recurse(node.left) * recurse(node.right) elif isinstance(node, ast.Sub): return recurse(node.left) - recurse(node.right) elif isinstance(node, ast.Div): return recurse(node.left) / recurse(node.right) raise UnknownError def _compute_constant(node): "Compute a simple forms of constant strings from an expression node" if isinstance(node, ast.Const): return node.value return _compute_node(node, _compute_constant) def _compute_tuple_size(node): "Compute the length of simple forms of tuples from an expression node" if isinstance(node, ast.Tuple): return (None,) * len(node.nodes) if isinstance(node, ast.Const): return node.value if isinstance(node, ast.Backquote): return '' return _compute_node(node, _compute_tuple_size) # for details: http://www.python.org/doc/current/lib/typesseq-strings.html _MOD_AND_TYPE = '([hlL])?([diouxXeEfFgGcrs%])' _TUP_FORMAT_REGEX = re.compile('%(())?[ #+-]*' '([0-9]*|[*])(|[.](|[*]|[0-9]*))' + _MOD_AND_TYPE) _DICT_FORMAT_REGEX = re.compile('%([(]([a-zA-Z_]+)[)])?[ #+-]*' '([0-9]*)(|[.](|[0-9]*))' + _MOD_AND_TYPE) class FormatError(Exception): def __init__(self, position): Exception.__init__(self) self.position = position def _check_format(s): pos = 0 specs = [] while 1: pos = s.find('%', pos) if pos < 0: return specs match = _TUP_FORMAT_REGEX.search(s, pos) if not match or match.start(0) != pos: match = _DICT_FORMAT_REGEX.search(s, pos) if not match or match.start(0) != pos: raise FormatError(pos) if match.group(7) != '%': # ignore "%%" specs.append( (match.group(2), match.group(3), match.group(5), match.group(6)) ) pos = match.end(0) return specs class _GetMod(BaseVisitor): def __init__(self): self.mods = [] def visitMod(self, node): self.mods.append(node) self.visitChildren(node) # don't descend into other scopes def visitFunction(self, node): pass visitClass = visitFunction visitLambda = visitFunction def get_mods(node): try: return walk(node.code, _GetMod()).mods except AttributeError: return walk(node.node, _GetMod()).mods _BAD_FORMAT_MAX = 10 def _bad_format_str(s, pos): result = s[pos : pos + _BAD_FORMAT_MAX] return result + (len(s) > pos + _BAD_FORMAT_MAX and "..." or "") class FormatStringCheck(Check): "Look for warnings in format strings" badFormat = \ Warning('Report illegal format specifications in format strings', 'Bad format specifier at position %d (%s)') uselessModifier = \ Warning('Report unused modifiers for format strings (l, h, L)', 'Modifier %s is not necessary') mixedFormat = \ Warning('Report format strings which use both positional ' 'and named formats', 'Cannot mix positional and named formats (%%%s)') formatCount = \ Warning('Report positional format string with the wrong ' 'number of arguments', 'Wrong number of arguments supplied for format: ' '%d given %d required') unknownFormatName = \ Warning('Report unknown names if locals() or globals() ' 'are used for format strings', 'The name "%s" is not defined in %s') badConstant = \ Warning('Report bad constant expressions for format strings', 'Error computing constant: %s') def check(self, file, unused_checker): if not file.parseTree: return for scope in file.scopes.values(): for mod in get_mods(scope.node): formats = [] try: s = _compute_constant(mod.left) formats = _check_format(s) except FormatError, detail: file.warning(mod, self.badFormat, detail.position, _bad_format_str(s, detail.position)) except TypeError, detail: file.warning(mod, self.badConstant, str(detail)) except UnknownError: pass if not formats: continue count = len(formats) for name, width, precision, lmodifier in formats: if lmodifier: file.warning(mod, self.uselessModifier, lmodifier) if width == '*': count += 1 if precision == '*': count += 1 names = [f[0] for f in formats if f[0]] if len(names) == 0: # tuple try: t = _compute_tuple_size(mod.right) n = 1 if type(t) == TupleType: n = len(t) if n != count: file.warning(mod, self.formatCount, n, count) except UnknownError: pass except TypeError, detail: file.warning(mod, self.badConstant, str(detail)) elif len(names) == len(formats): # dictionary defines = None if isinstance(mod.right, ast.CallFunc) and \ isinstance(mod.right.node, ast.Name): if mod.right.node.name in ['locals', 'vars']: defines = scope.defs uses = scope.uses if mod.right.node.name == 'globals': defines = file.root_scope.defs uses = file.root_scope.uses if defines is not None: for n in names: if not defines.has_key(n): file.warning(mod, self.unknownFormatName, n, mod.right.node.name) else: uses[n] = uses.get(n, mod) else: file.warning(mod, self.mixedFormat, "(%s)" % names[0]) spe-0.8.4.h/_spe/plugins/pychecker2/symbols.py0000644000175000017500000002743510576076542020315 0ustar stanistani####################################################################### # # THIS FILE IS __NOT__ under the pychecker copyright. # # The majority of this file is from the python2.2 distribution. # It is under the python2.2 copyright. # ####################################################################### """Module symbol-table generator""" from compiler import ast from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN from compiler.misc import mangle import types import sys MANGLE_LEN = 256 class Scope: # XXX how much information do I need about each name? def __init__(self, name, module, klass=None): self.name = name self.module = module self.defs = {} self.uses = {} self.globals = {} self.params = {} self.frees = {} self.cells = {} self.children = [] # nested is true if the class could contain free variables, # i.e. if it is nested within another function. self.nested = None self.generator = None self.klass = None if klass is not None: for i in range(len(klass)): if klass[i] != '_': self.klass = klass[i:] break def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.name) def mangle(self, name): if self.klass is None: return name return mangle(name, self.klass) def add_def(self, name, node): self.defs[self.mangle(name)] = node def add_use(self, name, node): name = self.mangle(name) self.uses[name] = self.uses.get(name, node) def add_global(self, name, node): name = self.mangle(name) if self.uses.has_key(name) or self.defs.has_key(name): pass # XXX warn about global following def/use if self.params.has_key(name): raise SyntaxError, "%s in %s is global and parameter" % \ (name, self.name) self.globals[name] = None self.module.add_def(name, node) def add_param(self, name, node): name = self.mangle(name) self.defs[name] = node self.params[name] = node def get_names(self): d = {} d.update(self.defs) d.update(self.uses) d.update(self.globals) return d.keys() def add_child(self, child): self.children.append(child) def get_children(self): return self.children def DEBUG(self): print >> sys.stderr, self.name, self.nested and "nested" or "" print >> sys.stderr, "\tglobals: ", self.globals print >> sys.stderr, "\tcells: ", self.cells print >> sys.stderr, "\tdefs: ", self.defs print >> sys.stderr, "\tuses: ", self.uses print >> sys.stderr, "\tfrees:", self.frees def check_name(self, name): """Return scope of name. The scope of a name could be LOCAL, GLOBAL, FREE, or CELL. """ if self.globals.has_key(name): return SC_GLOBAL if self.cells.has_key(name): return SC_CELL if self.defs.has_key(name): return SC_LOCAL if self.nested and (self.frees.has_key(name) or self.uses.has_key(name)): return SC_FREE if self.nested: return SC_UNKNOWN else: return SC_GLOBAL def get_free_vars(self): if not self.nested: return {} free = {} free.update(self.frees) for name in self.uses.keys(): if not (self.defs.has_key(name) or self.globals.has_key(name)): free[name] = self.uses[name] return free def handle_children(self): for child in self.children: frees = child.get_free_vars() globals = self.add_frees(frees) for name, node in globals.items(): child.force_global(name, node) def force_global(self, name, node): """Force name to be global in scope. Some child of the current node had a free reference to name. When the child was processed, it was labelled a free variable. Now that all its enclosing scope have been processed, the name is known to be a global or builtin. So walk back down the child chain and set the name to be global rather than free. Be careful to stop if a child does not think the name is free. """ self.globals[name] = node if self.frees.has_key(name): del self.frees[name] for child in self.children: if child.check_name(name) == SC_FREE: child.force_global(name, node) def add_frees(self, names): """Process list of free vars from nested scope. Returns a list of names that are either 1) declared global in the parent or 2) undefined in a top-level parent. In either case, the nested scope should treat them as globals. """ child_globals = {} for name, node in names.items(): sc = self.check_name(name) if self.nested: if sc == SC_UNKNOWN or sc == SC_FREE \ or isinstance(self, ClassScope): self.frees[name] = node elif sc == SC_GLOBAL: child_globals[name] = node elif isinstance(self, FunctionScope) and sc == SC_LOCAL: self.cells[name] = node elif sc != SC_CELL: child_globals[name] = node else: if sc == SC_LOCAL: self.cells[name] = node elif sc != SC_CELL: child_globals[name] = node return child_globals def get_cell_vars(self): return self.cells.keys() class ModuleScope(Scope): __super_init = Scope.__init__ def __init__(self): self.__super_init("global", self) class FunctionScope(Scope): pass class LambdaScope(FunctionScope): __super_init = FunctionScope.__init__ __counter = 1 def __init__(self, module, klass=None): i = self.__counter self.__counter += 1 self.__super_init("lambda.%d" % i, module, klass) class ClassScope(Scope): __super_init = Scope.__init__ def __init__(self, name, module): self.__super_init(name, module, name) class SymbolVisitor: def __init__(self): self.scopes = {} self.klass = None # node that define new scopes def visit(self, unused_node, *args): "overwritten by compiler.walk" pass def visitModule(self, node): scope = self.module = self.scopes[node] = ModuleScope() self.visit(node.node, scope) visitExpression = visitModule def visitFunction(self, node, parent): parent.add_def(node.name, node) for n in node.defaults: self.visit(n, parent) scope = FunctionScope(node.name, self.module, self.klass) if parent.nested or isinstance(parent, FunctionScope): scope.nested = 1 self.scopes[node] = scope self._do_args(scope, node.argnames, node) self.visit(node.code, scope) self.handle_free_vars(scope, parent) def visitLambda(self, node, parent): for n in node.defaults: self.visit(n, parent) scope = LambdaScope(self.module, self.klass) if parent.nested or isinstance(parent, FunctionScope): scope.nested = 1 self.scopes[node] = scope self._do_args(scope, node.argnames, node) self.visit(node.code, scope) self.handle_free_vars(scope, parent) def _do_args(self, scope, args, node): for name in args: if type(name) == types.TupleType: self._do_args(scope, name, node) else: scope.add_param(name, node) def handle_free_vars(self, scope, parent): parent.add_child(scope) scope.handle_children() def visitClass(self, node, parent): parent.add_def(node.name, node) for n in node.bases: self.visit(n, parent) scope = ClassScope(node.name, self.module) if parent.nested or isinstance(parent, FunctionScope): scope.nested = 1 self.scopes[node] = scope prev = self.klass self.klass = node.name self.visit(node.code, scope) self.klass = prev self.handle_free_vars(scope, parent) # name can be a def or a use # XXX a few calls and nodes expect a third "assign" arg that is # true if the name is being used as an assignment. only # expressions contained within statements may have the assign arg. def visitName(self, node, scope, assign=0): if assign: scope.add_def(node.name, node) else: scope.add_use(node.name, node) # operations that bind new names def visitFor(self, node, scope): self.visit(node.assign, scope, 1) self.visit(node.list, scope) self.visit(node.body, scope) if node.else_: self.visit(node.else_, scope) def visitFrom(self, node, scope): for name, asname in node.names: if name == "*": continue scope.add_def(asname or name, node) def visitImport(self, node, scope): for name, asname in node.names: i = name.find(".") if i > -1: name = name[:i] scope.add_def(asname or name, node) def visitGlobal(self, node, scope): for name in node.names: scope.add_global(name, node) def visitAssign(self, node, scope): """Propagate assignment flag down to child nodes. The Assign node doesn't itself contains the variables being assigned to. Instead, the children in node.nodes are visited with the assign flag set to true. When the names occur in those nodes, they are marked as defs. Some names that occur in an assignment target are not bound by the assignment, e.g. a name occurring inside a slice. The visitor handles these nodes specially; they do not propagate the assign flag to their children. """ for n in node.nodes: self.visit(n, scope, 1) self.visit(node.expr, scope) def visitAssName(self, node, scope, unused_assign=1): scope.add_def(node.name, node) def visitAssAttr(self, node, scope, unused_assign=0): self.visit(node.expr, scope, 0) def visitSubscript(self, node, scope, unused_assign=0): self.visit(node.expr, scope, 0) for n in node.subs: self.visit(n, scope, 0) def visitSlice(self, node, scope, unused_assign=0): self.visit(node.expr, scope, 0) if node.lower: self.visit(node.lower, scope, 0) if node.upper: self.visit(node.upper, scope, 0) def visitAugAssign(self, node, scope): # If the LHS is a name, then this counts as assignment. # Otherwise, it's just use. self.visit(node.node, scope) if isinstance(node.node, ast.Name): self.visit(node.node, scope, 1) # XXX worry about this self.visit(node.expr, scope) # prune if statements if tests are false _const_types = types.StringType, types.IntType, types.FloatType def visitIf(self, node, scope): for test, body in node.tests: if isinstance(test, ast.Const): if type(test.value) in self._const_types: if not test.value: continue self.visit(test, scope) self.visit(body, scope) if node.else_: self.visit(node.else_, scope) # a yield statement signals a generator def visitYield(self, node, scope): scope.generator = 1 self.visit(node.value, scope) spe-0.8.4.h/_spe/plugins/pychecker2/Warning.py0000644000175000017500000000047510576076542020225 0ustar stanistani class Warning: def __init__(self, description, message, value = 1): self.message = message self.description = description self.value = value def __cmp__(self, other): return cmp(self.message, other.message) def __repr__(self): return repr(self.message) spe-0.8.4.h/_spe/plugins/pychecker2/main.py0000644000175000017500000001106610725624770017540 0ustar stanistaniimport sys from os.path import dirname, realpath #---Patched by Stani http://pythonide.stani.be (begin) import os def userPath(dirname=''): """'safer' function to find user path.""" # 'safer' function to find user path: look for one of these directories try: path = os.path.expanduser("~") if os.path.isdir(path): return os.path.join(path, dirname) except: pass for evar in ('HOME', 'USERPROFILE', 'TMP'): try: path = os.environ[evar] if os.path.isdir(path): return os.path.join(path, dirname) except: pass #if no match found, use module directory return os.path.join(os.path.dirname(os.path.abspath(__file__)), dirname) CACHE_FILE = userPath(".pychecker_cache") #Patched by Stani http://pythonide.stani.be (end) sys.path.append(dirname(dirname(realpath(sys.argv[0])))) from pychecker2.Check import CheckList from pychecker2 import Options from pychecker2 import ParseChecks from pychecker2 import OpChecks from pychecker2 import VariableChecks from pychecker2 import ScopeChecks from pychecker2 import ImportChecks from pychecker2 import ClassChecks from pychecker2 import ReachableChecks from pychecker2 import ReturnChecks from pychecker2 import ConditionalChecks from pychecker2 import FormatStringChecks def print_warnings(f, out): if not f.warnings: return 0 f.warnings.sort() last_line = -1 last_msg = None for line, warning, args in f.warnings: if warning.value: msg = warning.message % args if msg != last_msg or line != last_line: print >>out, \ '%s:%s %s' % (f.name, line or '[unknown line]', msg) last_msg, last_line = msg, line if last_msg: print >>out return 1 def create_checklist(options): checks = [ ParseChecks.ParseCheck(), OpChecks.OpCheck(), OpChecks.ExceptCheck(), OpChecks.CompareCheck(), ReachableChecks.ReachableCheck(), ConditionalChecks.ConstantCheck(), ClassChecks.ReprCheck(), ImportChecks.ImportCheck(), FormatStringChecks.FormatStringCheck(), VariableChecks.ShadowCheck(), VariableChecks.UnpackCheck(), VariableChecks.UnusedCheck(), VariableChecks.UnknownCheck(), VariableChecks.SelfCheck(), VariableChecks.UsedBeforeSetCheck(), ReturnChecks.MixedReturnCheck(), ClassChecks.AttributeCheck(), ClassChecks.SpecialCheck(), ClassChecks.InitCheck(), ScopeChecks.RedefineCheck(), ] for checker in checks: checker.get_warnings(options) checker.get_options(options) return CheckList(checks) def main(): import cPickle options = Options.Options() try: checker = cPickle.load(open(CACHE_FILE, 'rb')) #---Patched by Stani http://pythonide.stani.be (added ImportError) except (EOFError, IOError, ImportError): checker = create_checklist(options) try: files = options.process_options(sys.argv[1:]) except Options.Error, detail: print >> sys.stderr, "Error: %s" % detail options.usage(sys.argv[0], sys.stderr) return 1 #---Patched by Stani http://pythonide.stani.be (begin) sys_path = sys.path[:] for f in files: f_dir = dirname(f.name) sys.path= sys_path[:] if f_dir not in sys.path: sys.path.insert(0,f_dir) checker.check_file(f) if options.incremental and not options.profile: print_warnings(f, sys.stdout) sys.path = sys_path #Patched by Stani http://pythonide.stani.be (end) result = 0 if not options.incremental and not options.profile: files.sort() for f in files: result |= print_warnings(f, sys.stdout) if not result and options.verbose: print >>sys.stdout, None fp = open(CACHE_FILE, 'wb') cPickle.dump(checker, fp, 1) fp.close() return result if __name__ == "__main__": if '--profile' in sys.argv: print 'profiling' import hotshot.stats import time hs = hotshot.Profile('logfile.dat') now = time.time() hs.run('main()') print 'total run time', time.time() - now hs.close() stats = hotshot.stats.load('logfile.dat') stats.sort_stats('time', 'cum').print_stats(50) else: sys.exit(main()) spe-0.8.4.h/_spe/plugins/pychecker2/Check.py0000644000175000017500000000462010576076542017631 0ustar stanistani from pychecker2.Warning import Warning from pychecker2.File import File from pychecker2 import Options import time import os import stat class WarningOpt(Options.BoolOpt): __pychecker__ = 'no-callinit' def __init__(self, longName, warning): self.warning = warning self.longName = longName self.default = warning.value def set_value(self, unused): self.warning.value = not self.warning.value def get_value(self): return self.warning.value def get_description(self): return self.warning.description def reset(self): self.warning.value = self.default class CheckList: def __init__(self, checks): self.checks = checks self.modules = {} def check_file(self, f): for c in self.checks: c.check(f, self) def check_module(self, m): f = None try: f = self.modules[m] except KeyError: import inspect try: fname = inspect.getsourcefile(m) if fname: f = File(fname) except TypeError: pass self.modules[m] = f if f: self.check_file(f) return f def __getstate__(self): modules = [] for k, v in self.modules.items(): modules.append( (k.__name__, v) ) return (time.time(), self.checks, modules) def __setstate__(self, data): import inspect cache_time, self.checks, modules = data self.modules = {} for k, v in modules: module = __import__(k, globals(), {}, ['']) # Don't recover files that are newer than the save time try: fname = inspect.getsourcefile(module) last_modified = os.stat(fname)[stat.ST_MTIME] except TypeError: last_modified = 0 if last_modified < cache_time: self.modules[module] = v class Check: def __str__(self): return self.__class__.__name__ def get_warnings(self, options): for attr in vars(self.__class__): object = getattr(self, attr) if isinstance(object, Warning): options.add(WarningOpt(attr, object)) def get_options(self, options): pass def check(self, file, checker): pass spe-0.8.4.h/_spe/plugins/pychecker2/ImportChecks.py0000644000175000017500000000733710576076542021217 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Check import Warning from pychecker2 import util from compiler import walk class ModuleReference: def __init__(self, localname, remotename, module, nodes): self.localname = localname self.remotename = remotename self.module = module self.nodes = nodes def __getstate__(self): return (self.localname, self.remotename, self.module.__name__, self.nodes) def __setstate__(self, data): (self.localname, self.remotename, module, self.nodes) = data self.module = __import__(module, globals(), {}, ['']) class ImportCheck(Check): ''' Get 'from module import *' names hauled into the file and modules. Figure out which names come from 'import name'. ''' importError = Warning('Report/ignore imports that may fail', 'Error trying to import %s: %s') duplicateImport = Warning('Report/ignore duplicate imports', 'Import of "%s" is duplicate%s') shadowImport = Warning('Report imports which shadow names from ' 'other imports', 'Import of "%s" duplicates import from ' 'module %s at %d') def check(self, file, checker): def try_import(name, node): try: return __import__(name, globals(), {}, ['']) except ImportError, detail: file.warning(node, ImportCheck.importError, name, str(detail)) except Exception, detail: file.warning(node, ImportCheck.importError, name, str(detail)) return None def add_import(node, local, remote, module): scopes = util.enclosing_scopes(file.scopes, node) for scope in scopes: try: ref = scope.imports[local] if not util.try_if_exclusive(ref.nodes, node): if ref.module == module: if scope == scopes[0]: extra = " in current scope" else: extra = " of import in parent scope %s" % scope file.warning(node, ImportCheck.duplicateImport, local, extra) else: file.warning(node, ImportCheck.shadowImport, local, ref.module.__name__, ref.nodes.lineno) except KeyError: pass scopes[0].imports[local] = ModuleReference(local, remote, module, node) checker.check_module(module) class FromImportVisitor: def visitFrom(self, node): m = try_import(node.modname, node) if m: for module_name, local_name in node.names: if module_name == '*': for name in dir(m): if not name.startswith('_'): add_import(node, name, name, m) else: add_import(node, local_name or module_name, module_name, m) def visitImport(self, node): for module, name in node.names: m = try_import(module, node) if m: add_import(node, name or module, None, m) if file.root_scope: walk(file.root_scope.node, FromImportVisitor()) spe-0.8.4.h/_spe/plugins/pychecker2/OpChecks.py0000644000175000017500000000460010576076542020311 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.Warning import Warning from pychecker2.util import BaseVisitor import compiler class OpCheck(Check): operator = Warning( "Check for (++) and (--) which are legal, but not useful", "Operator (%s) doesn't exist, statement has no effect" ) operatorPlus = Warning( 'Check for unary +', "Operator (+) normally has no effect" ) def check(self, file, unused_checklist): class OpVisitor: def visitUnaryAdd(s, n): if n.getChildren()[0].__class__ == compiler.ast.UnaryAdd: file.warning(n, self.operator, '++') else: file.warning(n, self.operatorPlus) def visitUnarySub(s, n): if n.getChildren()[0].__class__ == compiler.ast.UnarySub: file.warning(n, self.operator, '--') if file.parseTree: compiler.walk(file.parseTree, OpVisitor()) class ExceptCheck(Check): emptyExcept = Warning('Warn about "except:"', 'Empty except clauses can hide unexpected errors') def check(self, file, unused_checklist): class ExceptVisitor(BaseVisitor): def visitTryExcept(s, node): for exc, det, code in node.handlers: if exc is None: file.warning(code.nodes[0], self.emptyExcept) s.visitChildren(node) if file.parseTree: compiler.walk(file.parseTree, ExceptVisitor()) class CompareCheck(Check): useIs = Warning('warn about "== None"', 'use "is" when comparing with None') def check(self, file, unused_checklist): def checkEqualNone(node, expr, op): if (op == '==' and expr.__class__ == compiler.ast.Name and expr.name == "None"): file.warning(node, self.useIs) class CompareVisitor(BaseVisitor): def visitCompare(s, node): children = node.getChildren() for i in range(0, len(children) - 1, 2): left, op = children[i:i+2] checkEqualNone(node, left, op) op, right = children[-2:] checkEqualNone(node, right, op) if file.parseTree: compiler.walk(file.parseTree, CompareVisitor()) spe-0.8.4.h/_spe/plugins/pychecker2/util.py0000644000175000017500000000362310576076542017573 0ustar stanistani class BaseVisitor: def visit(self, unused_node): "method is really overridden by compiler.visitor.ASTVisitor" assert 0, 'Unreachable' def visitChildren(self, n): for c in n.getChildNodes(): self.visit(c) def try_if_exclusive(stmt_node1, stmt_node2): from compiler import ast as ast """return true if the statements are in exclusive parts of if/elif/else or try/finally/else""" parent = stmt_node1.parent.parent if parent == stmt_node2.parent.parent: if isinstance(parent, ast.If): parts = [code for test, code in parent.tests] parts.append(parent.else_) for part in parts: if part and stmt_node1 in part.nodes: return stmt_node2 not in part.nodes if isinstance(parent, ast.TryExcept): parts = [] if parent.body: parts.extend(parent.body.nodes) if parent.else_: parts.extend(parent.else_.nodes) return not (stmt_node1 in parts and stmt_node2 in parts) return None def parents(obj): class Parents: def __init__(self, start): self.next = start def __call__(self): retval = self.next.parent self.next = retval return retval return iter(Parents(obj), None) def enclosing_scopes(scopes, node): result = [] n = node while n: try: result.append(scopes[n]) except KeyError: pass n = n.parent return result def type_filter(seq, *classes): return [s for s in seq if isinstance(s, classes)] def dict_minus(a, b): r = {} for k, v in a.iteritems(): if not b.has_key(k): r[k] = v return r def dict_intersect(a, b): r = {} for k, v in a.iteritems(): if b.has_key(k): r[k] = v return r spe-0.8.4.h/_spe/plugins/pychecker2/ReachableChecks.py0000644000175000017500000000674410576076542021614 0ustar stanistanifrom pychecker2.Check import Check from pychecker2.util import BaseVisitor from pychecker2.Warning import Warning from compiler import ast, walk class ReachableCheck(Check): unreachable = Warning('Report unreachable code', 'Line is unreachable') implicitReturn = \ Warning('Report implicit return in a function with explicit returns', 'Function %s uses both implicit and explicit returns') def check(self, file, unused_checker): class ReturnsVisitor(BaseVisitor): def __init__(s): s.always_returns = 0 # icky: result value by side-effect s.has_returns = 0 def check_returns(s, node): s.always_returns = 0 s.visit(node) return s.always_returns def alternatives_with_else(s, nodes, else_): for n in nodes: if not s.check_returns(n): return s.always_returns = 0 if else_: s.visit(else_) def visitAssert(s, node): if isinstance(node.test, ast.Const): s.always_returns = not node.test.value if isinstance(node.test, ast.Name): if node.test.name == 'None': s.always_returns = 1 def visitReturn(s, node): s.always_returns = 1 if not isinstance(node.value, ast.Const) or \ node.value.value is not None: s.has_returns = 1 def visitRaise(s, unused_node): s.always_returns = 1 def visitTryExcept(s, node): # if body always returns, else code is unreachable if s.check_returns(node.body) and node.else_: file.warning(node.else_.nodes[0], self.unreachable) s.always_returns = 0 # no matter what happens in the try clause, it might # cause an exception, so check the handlers and else # conditions all return handlers = [code for exc, detail, code in node.handlers] s.alternatives_with_else(handlers, node.else_ or node.body) def visitIf(s, node): code = [code for cond, code in node.tests] s.alternatives_with_else(code, node.else_) def visitStmt(s, node): for n in range(len(node.nodes) - 1): if s.check_returns(node.nodes[n]): file.warning(node.nodes[n + 1], self.unreachable) break else: if node.nodes and \ not s.check_returns(node.nodes[-1]) and \ isinstance(node.parent, ast.Function) and \ s.has_returns: file.warning(node.nodes[-1], self.implicitReturn, node.parent.name) def visitFunction(s, node): pass visitClass = visitFunction def visitWhile(s, unused): # FIXME: while's may never execute and not return s.always_returns = 0 visitFor = visitWhile for scope in file.scopes.values(): if isinstance(scope.node, ast.Function): walk(scope.node.code, ReturnsVisitor()) spe-0.8.4.h/_spe/plugins/pychecker2/Options.py0000644000175000017500000000644710576076542020260 0ustar stanistaniclass Error(Exception): pass class Opt: def __init__(self, object, longName, description, default): self.object = object self.longName = longName self.description = description setattr(object, longName, default) self.default = default def set_value(self, value): setattr(self.object, self.longName, value) def get_value(self): return getattr(self.object, self.longName) def get_description(self): return self.description def is_boolean(self): return None def reset(self): setattr(self.object, self.longName, self.default) class BoolOpt(Opt): def __init__(self, object, longName, description, default = None): Opt.__init__(self, object, longName, description, default) def set_value(self, unused): setattr(self.object, self.longName, not self.get_value()) def is_boolean(self): return 1 MAJOR = 'Major' ERROR = 'Error' MISC = 'Miscellaneous' Categories = [MAJOR, ERROR, MISC] class Options: def __init__(self): self.options = {} for c in Categories: self.options[c] = [] self.add(BoolOpt(self, 'verbose', 'turn on verbose messages'), MISC) self.add(BoolOpt(self, 'incremental', 'print warnings as they are created'), MISC) self.add(BoolOpt(self, 'profile', 'print a profile of pychecker', 0), MISC) def add(self, option, category=ERROR): self.options[category].append(option) def process_options(self, args): import getopt try: longopts = {} for opts in self.options.values(): for opt in opts: opt.reset() optname = opt.longName if opt.is_boolean() and opt.get_value(): optname = "no-" + opt.longName longopts[optname] = opt specs = [] for k, v in longopts.items(): if not v.is_boolean(): k += '=' specs.append(k) opts, args = getopt.getopt(args, '', specs) except getopt.GetoptError, detail: raise Error(detail) for opt, arg in opts: longopts[opt[2:]].set_value(arg) from pychecker2.File import File return [ File(f) for f in args ] def usage(self, argv0, stream): indent = " " over = 20 print >> stream, "Usage:" print >> stream, \ "%s%s [options] [--] file1.py file2.py ..." % (indent, argv0) print >> stream, "available options:" for c in Categories: if not self.options[c]: continue print >> stream print >> stream, "%s:" % c opts = self.options[c] opts.sort(lambda x, y: cmp(x.longName, y.longName)) for opt in opts: name = opt.longName if opt.is_boolean() and opt.get_value(): name = "no-" + name print >> stream, "%s--%*s %s" % ( indent, -over, name, opt.get_description()) if not opt.is_boolean(): print >> stream, "%s %*s %s" % ( indent, -over, '', opt.get_value()) spe-0.8.4.h/_spe/plugins/pychecker/Stack.py0000755000175000017500000000711011002645341017557 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2002, MetaSlash Inc. All rights reserved. """ Module to hold manipulation of elements on the stack. """ import types from pychecker import utils DATA_UNKNOWN = "-unknown-" LOCALS = 'locals' # These should really be defined by subclasses TYPE_UNKNOWN = "-unknown-" TYPE_FUNC_RETURN = "-return-value-" TYPE_ATTRIBUTE = "-attribute-" TYPE_COMPARISON = "-comparison-" TYPE_GLOBAL = "-global-" TYPE_EXCEPT = "-except-" class Item : "Representation of data on the stack" def __init__(self, data, dataType, const = 0, length = 0) : self.data = data self.type = dataType self.const = const self.length = length self.is_really_string = 0 def __str__(self) : if type(self.data) == types.TupleType : value = '(' for item in self.data : value = value + utils.safestr(item) + ', ' # strip off the ', ' for multiple items if len(self.data) > 1 : value = value[:-2] return value + ')' return utils.safestr(self.data) def __repr__(self): return 'Stack Item: (%s, %s, %d)' % (self.data, self.type, self.const) def isNone(self) : return (self.type != TYPE_UNKNOWN and self.data is None or (self.data == 'None' and not self.const)) def isImplicitNone(self) : return self.data is None and self.const def isMethodCall(self, c, methodArgName): return self.type == TYPE_ATTRIBUTE and c != None and \ len(self.data) == 2 and self.data[0] == methodArgName def isLocals(self) : return self.type == types.DictType and self.data == LOCALS def setStringType(self, value = types.StringType): self.is_really_string = value == types.StringType def getType(self, typeMap) : if self.type != types.StringType or self.is_really_string: return self.type if self.const : return type(self.data) if type(self.data) == types.StringType : localTypes = typeMap.get(self.data, []) if len(localTypes) == 1 : return localTypes[0] return TYPE_UNKNOWN def getName(self) : if self.type == TYPE_ATTRIBUTE and type(self.data) != types.StringType: strValue = "" # convert the tuple into a string ('self', 'data') -> self.data for item in self.data : strValue = '%s.%s' % (strValue, utils.safestr(item)) return strValue[1:] return utils.safestr(self.data) def addAttribute(self, attr) : if type(self.data) == types.TupleType : self.data = self.data + (attr,) else : self.data = (self.data, attr) self.type = TYPE_ATTRIBUTE def makeDict(values = (), const = 1) : values = tuple(values) if not values: values = ('',) return Item(values, types.DictType, const, len(values)) def makeTuple(values = (), const = 1) : return Item(tuple(values), types.TupleType, const, len(values)) def makeList(values = [], const = 1) : return Item(values, types.ListType, const, len(values)) def makeFuncReturnValue(stackValue, argCount) : data = DATA_UNKNOWN # vars() without params == locals() if stackValue.type == TYPE_GLOBAL and \ (stackValue.data == LOCALS or (argCount == 0 and stackValue.data == 'vars')) : data = LOCALS return Item(data, TYPE_FUNC_RETURN) def makeComparison(stackItems, comparison) : return Item((stackItems[0], comparison, stackItems[1]), TYPE_COMPARISON) spe-0.8.4.h/_spe/plugins/pychecker/Options.ad0000644000175000017500000000026010576076436020117 0ustar stanistani*ok.text: Ok *cancel.text: Cancel *default.text: Reset *helpBox.wrapLength: 400 *helpBox.height: 2 *getfile.text: File: *check.text: Check! *fname.width: 50 *close.text: Close spe-0.8.4.h/_spe/plugins/pychecker/Config.py0000755000175000017500000004466511002645341017737 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Configuration information for checker. """ import sys import os import getopt import string import re import time def get_warning_levels(): import types from pychecker import msgs WarningClass = msgs.WarningClass result = {} for name in vars(msgs).keys(): obj = getattr(msgs, name) if (obj is not WarningClass and isinstance(obj, types.ClassType) and issubclass(obj, WarningClass)): result[name.capitalize()] = obj return result _WARNING_LEVELS = get_warning_levels() _RC_FILE = ".pycheckrc" CHECKER_VAR = '__pychecker__' _VERSION = '0.8.17' _DEFAULT_BLACK_LIST = [ "Tkinter", "wxPython", "gtk", "GTK", "GDK", ] _DEFAULT_VARIABLE_IGNORE_LIST = [ '__version__', '__warningregistry__', '__all__', '__credits__', '__test__', '__author__', '__email__', '__revision__', '__id__', '__copyright__', '__license__', '__date__', ] _DEFAULT_UNUSED_LIST = [ '_', 'empty', 'unused', 'dummy', ] _OPTIONS = ( ('Major Options', [ ('', 0, 'only', 'only', 'only warn about files passed on the command line'), ('e', 1, 'level', None, 'the maximum error level of warnings to be displayed'), ('#', 1, 'limit', 'limit', 'the maximum number of warnings to be displayed'), ('F', 1, 'config', None, 'specify .pycheckrc file to use'), ('', 0, 'quixote', None, 'support Quixote\'s PTL modules'), ('', 1, 'evil', 'evil', 'list of evil C extensions that crash the interpreter'), ]), ('Error Control', [ ('i', 0, 'import', 'importUsed', 'unused imports'), ('k', 0, 'pkgimport', 'packageImportUsed', 'unused imports from __init__.py'), ('M', 0, 'reimportself', 'reimportSelf', 'module imports itself'), ('X', 0, 'reimport', 'moduleImportErrors', 'reimporting a module'), ('x', 0, 'miximport', 'mixImport', 'module does import and from ... import'), ('l', 0, 'local', 'localVariablesUsed', 'unused local variables, except tuples'), ('t', 0, 'tuple', 'unusedLocalTuple', 'all unused local variables, including tuples'), ('9', 0, 'members', 'membersUsed', 'all unused class data members'), ('v', 0, 'var', 'allVariablesUsed', 'all unused module variables'), ('p', 0, 'privatevar', 'privateVariableUsed', 'unused private module variables'), ('g', 0, 'allglobals', 'reportAllGlobals', 'report each occurrence of global warnings'), ('n', 0, 'namedargs', 'namedArgs', 'functions called with named arguments (like keywords)'), ('a', 0, 'initattr', 'onlyCheckInitForMembers', 'Attributes (members) must be defined in __init__()'), ('I', 0, 'initsubclass', 'initDefinedInSubclass', 'Subclass.__init__() not defined'), ('u', 0, 'callinit', 'baseClassInitted', 'Baseclass.__init__() not called'), ('0', 0, 'abstract', 'abstractClasses', 'Subclass needs to override methods that only throw exceptions'), ('N', 0, 'initreturn', 'returnNoneFromInit', 'Return None from __init__()'), ('8', 0, 'unreachable', 'unreachableCode', 'unreachable code'), ('2', 0, 'constCond', 'constantConditions', 'a constant is used in a conditional statement'), ('1', 0, 'constant1', 'constant1', '1 is used in a conditional statement (if 1: or while 1:)'), ( '', 0, 'stringiter', 'stringIteration', 'check if iterating over a string'), ( '', 0, 'stringfind', 'stringFind', 'check improper use of string.find()'), ('A', 0, 'callattr', 'callingAttribute', 'Calling data members as functions'), ('y', 0, 'classattr', 'classAttrExists', 'class attribute does not exist'), ('S', 1, 'self', 'methodArgName', 'First argument to methods'), ('', 1, 'classmethodargs', 'classmethodArgNames', 'First argument to classmethods'), ('T', 0, 'argsused', 'argumentsUsed', 'unused method/function arguments'), ('z', 0, 'varargsused', 'varArgumentsUsed', 'unused method/function variable arguments'), ('G', 0, 'selfused', 'ignoreSelfUnused', 'ignore if self is unused in methods'), ('o', 0, 'override', 'checkOverridenMethods', 'check if overridden methods have the same signature'), ('', 0, 'special', 'checkSpecialMethods', 'check if __special__ methods exist and have the correct signature'), ('U', 0, 'reuseattr', 'redefiningFunction', 'check if function/class/method names are reused'), ('Y', 0, 'positive', 'unaryPositive', 'check if using unary positive (+) which is usually meaningless'), ('j', 0, 'moddefvalue', 'modifyDefaultValue', 'check if modify (call method) on a parameter that has a default value'), ( '', 0, 'changetypes', 'inconsistentTypes', 'check if variables are set to different types'), ( '', 0, 'unpack', 'unpackNonSequence', 'check if unpacking a non-sequence'), ( '', 0, 'unpacklen', 'unpackLength', 'check if unpacking sequence with the wrong length'), ( '', 0, 'badexcept', 'badExceptions', 'check if raising or catching bad exceptions'), ('4', 0, 'noeffect', 'noEffect', 'check if statement appears to have no effect'), ('', 0, 'modulo1', 'modulo1', 'check if using (expr % 1), it has no effect on integers and strings'), ('', 0, 'isliteral', 'isLiteral', "check if using (expr is const-literal), doesn't always work on integers and strings"), ]), ('Possible Errors', [ ('r', 0, 'returnvalues', 'checkReturnValues', 'check consistent return values'), ('C', 0, 'implicitreturns', 'checkImplicitReturns', 'check if using implict and explicit return values'), ('O', 0, 'objattrs', 'checkObjectAttrs', 'check that attributes of objects exist'), ('7', 0, 'slots', 'slots', 'various warnings about incorrect usage of __slots__'), ('3', 0, 'properties', 'classicProperties', 'using properties with classic classes'), ( '', 0, 'emptyslots', 'emptySlots', 'check if __slots__ is empty'), ('D', 0, 'intdivide', 'intDivide', 'check if using integer division'), ('w', 0, 'shadow', 'shadows', 'check if local variable shadows a global'), ('s', 0, 'shadowbuiltin', 'shadowBuiltins', 'check if a variable shadows a builtin'), ]), ('Security', [ ( '', 0, 'input', 'usesInput', 'check if input() is used'), ('6', 0, 'exec', 'usesExec', 'check if the exec statement is used'), ]), ('Suppressions', [ ('q', 0, 'stdlib', 'ignoreStandardLibrary', 'ignore warnings from files under standard library'), ('b', 1, 'blacklist', 'blacklist', 'ignore warnings from the list of modules\n\t\t\t'), ('Z', 1, 'varlist', 'variablesToIgnore', 'ignore global variables not used if name is one of these values\n\t\t\t'), ('E', 1, 'unusednames', 'unusedNames', 'ignore unused locals/arguments if name is one of these values\n\t\t\t'), ( '', 0, 'deprecated', 'deprecated', 'ignore use of deprecated modules/functions'), ]), ('Complexity', [ ('L', 1, 'maxlines', 'maxLines', 'maximum lines in a function'), ('B', 1, 'maxbranches', 'maxBranches', 'maximum branches in a function'), ('R', 1, 'maxreturns', 'maxReturns', 'maximum returns in a function'), ('J', 1, 'maxargs', 'maxArgs', 'maximum # of arguments to a function'), ('K', 1, 'maxlocals', 'maxLocals', 'maximum # of locals in a function'), ('5', 1, 'maxrefs', 'maxReferences', 'maximum # of identifier references (Law of Demeter)'), ('m', 0, 'moduledoc', 'noDocModule', 'no module doc strings'), ('c', 0, 'classdoc', 'noDocClass', 'no class doc strings'), ('f', 0, 'funcdoc', 'noDocFunc', 'no function/method doc strings'), ]), ('Debug', [ ( '', 0, 'rcfile', None, 'print a .pycheckrc file generated from command line args'), ('P', 0, 'printparse', 'printParse', 'print internal checker parse structures'), ('d', 0, 'debug', 'debug', 'turn on debugging for checker'), ('Q', 0, 'quiet', 'quiet', 'turn off all output except warnings'), ('V', 0, 'version', None, 'print the version of PyChecker and exit'), ]) ) def init() : GET_OPT_VALUE = (('', ''), (':', '='),) shortArgs, longArgs = "", [] for _, group in _OPTIONS : for opt in group: optStr = GET_OPT_VALUE[opt[1]] shortArgs = shortArgs + opt[0] + optStr[0] longArgs.append(opt[2] + optStr[1]) longArgs.append('no-' + opt[2] + optStr[1]) options = {} for _, group in _OPTIONS : for opt in group: shortArg, useValue, longArg, member, description = opt if shortArg != '' : options['-' + shortArg] = opt options['--no-' + longArg] = options['--' + longArg] = opt return shortArgs, longArgs, options _SHORT_ARGS, _LONG_ARGS, _OPTIONS_DICT = init() def _getRCfiles(filename) : """Return a list of .rc filenames, on Windows use the current directory on UNIX use the user's home directory """ files = [] home = os.environ.get('HOME') if home : files.append(home + os.sep + filename) files.append(filename) return files _RC_FILE_HEADER = '''# # .pycheckrc file created by PyChecker v%s @ %s # # It should be placed in your home directory (value of $HOME). # If $HOME is not set, it will look in the current directory. # ''' def outputRc(cfg) : output = _RC_FILE_HEADER % (_VERSION, time.ctime(time.time())) for name, group in _OPTIONS : for opt in group: shortArg, useValue, longArg, member, description = opt if member is None : continue description = string.strip(description) value = getattr(cfg, member) optStr = '# %s\n%s = %s\n\n' % (description, member, `value`) output = output + optStr return output class UsageError(Exception) : """Exception to indicate that the application should exit due to command line usage error.""" _SUPPRESSIONS_ERR = \ '''\nWarning, error processing defaults file: %s \%s must be a dictionary ({}) -- ignoring suppressions\n''' def _getSuppressions(name, dict, filename) : suppressions = dict.get(name, {}) if type(suppressions) != type({}) : print _SUPPRESSIONS_ERR % (filename, name) suppressions = {} return suppressions class Config : "Hold configuration information" def __init__(self) : "Initialize configuration with default values." # files to process (typically from cmd line) self.files = {} self.debug = 0 self.quiet = 0 self.only = 0 self.level = 0 self.limit = 10 self.onlyCheckInitForMembers = 0 self.printParse = 0 self.quixote = 0 self.evil = [] self.noDocModule = 0 self.noDocClass = 0 self.noDocFunc = 0 self.reportAllGlobals = 0 self.allVariablesUsed = 0 self.privateVariableUsed = 1 self.membersUsed = 0 self.importUsed = 1 self.reimportSelf = 1 self.moduleImportErrors = 1 self.mixImport = 1 self.packageImportUsed = 1 self.localVariablesUsed = 1 self.unusedLocalTuple = 0 self.initDefinedInSubclass = 0 self.baseClassInitted = 1 self.abstractClasses = 1 self.callingAttribute = 0 self.classAttrExists = 1 self.namedArgs = 0 self.returnNoneFromInit = 1 self.unreachableCode = 0 self.constantConditions = 1 self.constant1 = 0 self.stringIteration = 1 self.inconsistentTypes = 0 self.unpackNonSequence = 1 self.unpackLength = 1 self.badExceptions = 1 self.noEffect = 1 self.deprecated = 1 self.modulo1 = 1 self.isLiteral = 1 self.stringFind = 1 self.unusedNames = _DEFAULT_UNUSED_LIST self.variablesToIgnore = _DEFAULT_VARIABLE_IGNORE_LIST self.blacklist = _DEFAULT_BLACK_LIST self.ignoreStandardLibrary = 0 self.methodArgName = 'self' self.classmethodArgNames = ['cls', 'klass'] self.checkOverridenMethods = 1 self.checkSpecialMethods = 1 self.argumentsUsed = 1 self.varArgumentsUsed = 1 self.ignoreSelfUnused = 0 self.redefiningFunction = 1 self.maxLines = 200 self.maxBranches = 50 self.maxReturns = 10 self.maxArgs = 10 self.maxLocals = 40 self.maxReferences = 5 self.slots = 1 self.emptySlots = 1 self.classicProperties = 1 self.checkObjectAttrs = 1 self.checkReturnValues = 1 self.checkImplicitReturns = 1 self.intDivide = 1 self.shadows = 1 self.shadowBuiltins = 1 self.unaryPositive = 1 self.modifyDefaultValue = 1 self.usesExec = 0 self.usesInput = 1 self.constAttr = 1 def loadFile(self, filename) : suppressions = {} suppressionRegexs = {} try : tmpGlobal, dict = {}, {} execfile(filename, tmpGlobal, dict) for key, value in dict.items() : if self.__dict__.has_key(key) : self.__dict__[key] = value elif key not in ('suppressions', 'suppressionRegexs') and \ key[0] != '_': print "Warning, option (%s) doesn't exist, ignoring" % key suppressions = _getSuppressions('suppressions', dict, filename) regexs = _getSuppressions('suppressionRegexs', dict, filename) for regex_str in regexs.keys() : regex = re.compile(regex_str) suppressionRegexs[regex] = regexs[regex_str] except IOError : pass # ignore if no file except Exception, detail: print "Warning, error loading defaults file:", filename, detail return suppressions, suppressionRegexs def loadFiles(self, filenames, oldSuppressions = None) : if oldSuppressions is None : oldSuppressions = ({}, {}) suppressions = oldSuppressions[0] suppressionRegexs = oldSuppressions[1] for filename in filenames: updates = self.loadFile(filename) suppressions.update(updates[0]) suppressionRegexs.update(updates[1]) return suppressions, suppressionRegexs def processArgs(self, argList, otherConfigFiles = None) : try : args, files = getopt.getopt(argList, _SHORT_ARGS, _LONG_ARGS) except getopt.error, detail : raise UsageError, detail # setup files from cmd line for f in files: self.files[os.path.abspath(f)] = 1 if otherConfigFiles is None: otherConfigFiles = [] for arg, value in args : shortArg, useValue, longArg, member, description = _OPTIONS_DICT[arg] if member == None : # FIXME: this whole block is a hack if longArg == 'rcfile' : sys.stdout.write(outputRc(self)) continue elif longArg == 'quixote' : import quixote quixote.enable_ptl() self.quixote = 1 continue elif longArg == 'config' : otherConfigFiles.append(value) continue elif longArg == 'version' : # FIXME: it would be nice to define this in only one place print _VERSION sys.exit(0) elif longArg == 'level': normalizedValue = value.capitalize() if not _WARNING_LEVELS.has_key(normalizedValue): sys.stderr.write('Invalid warning level (%s). ' 'Must be one of: %s\n' % (value, _WARNING_LEVELS.keys())) sys.exit(1) self.level = _WARNING_LEVELS[normalizedValue].level continue elif value : newValue = value memberType = type(getattr(self, member)) if memberType == type(0) : newValue = int(newValue) elif memberType == type([]) : newValue = string.split(newValue, ',') elif memberType == type('') and \ newValue[0] in '\'"': try: newValue = eval(newValue) except: msg = 'Invalid option parameter: %s for %s\n' % \ (`newValue`, arg) sys.stderr.write(msg) setattr(self, member, newValue) elif arg[0:2] == '--' : setattr(self, member, arg[2:5] != 'no-') else : # for shortArgs we only toggle setattr(self, member, not getattr(self, member)) if self.variablesToIgnore.count(CHECKER_VAR) <= 0 : self.variablesToIgnore.append(CHECKER_VAR) return files def printArg(shortArg, longArg, description, defaultValue, useValue) : defStr = '' shortArgStr = ' ' if shortArg: shortArgStr = '-%s,' % shortArg if defaultValue != None : if not useValue : if defaultValue : defaultValue = 'on' else : defaultValue = 'off' defStr = ' [%s]' % defaultValue args = "%s --%s" % (shortArgStr, longArg) print " %-18s %s%s" % (args, description, defStr) def usage(cfg = None) : print "Usage for: checker.py [options] PACKAGE ...\n" print " PACKAGEs can be a python package, module or filename\n" print "Long options can be preceded with no- to turn off (e.g., no-namedargs)\n" print "Category" print " Options: Change warning for ... [default value]" if cfg is None : cfg = Config() for name, group in _OPTIONS : print print name + ":" for opt in group: shortArg, useValue, longArg, member, description = opt defValue = None if member != None : defValue = cfg.__dict__[member] printArg(shortArg, longArg, description, defValue, useValue) def setupFromArgs(argList) : "Returns (Config, [ file1, file2, ... ]) from argList" cfg = Config() try : suppressions = cfg.loadFiles(_getRCfiles(_RC_FILE)) otherConfigFiles = [] files = cfg.processArgs(argList, otherConfigFiles) if otherConfigFiles: suppressions = cfg.loadFiles(otherConfigFiles, suppressions) return cfg, files, suppressions except UsageError : usage(cfg) raise spe-0.8.4.h/_spe/plugins/pychecker/utils.py0000755000175000017500000000411111002645341017650 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. """ Print out warnings from Python source files. """ import sys import string import copy from pychecker import msgs from pychecker import Config from pychecker.Warning import Warning VAR_ARGS_BITS = 8 MAX_ARGS_MASK = ((1 << VAR_ARGS_BITS) - 1) INIT = '__init__' LAMBDA = '' # number of instructions to check backwards if it was a return BACK_RETURN_INDEX = 4 _cfg = [] def cfg() : return _cfg[-1] def initConfig(cfg) : _cfg.append(cfg) def pushConfig() : newCfg = copy.copy(cfg()) _cfg.append(newCfg) def popConfig() : del _cfg[-1] def shouldUpdateArgs(operand) : return operand == Config.CHECKER_VAR def updateCheckerArgs(argStr, func, lastLineNum, warnings) : try : argList = string.split(argStr) # don't require long options to start w/--, we can add that for them for i in range(0, len(argList)) : if argList[i][0] != '-' : argList[i] = '--' + argList[i] cfg().processArgs(argList) return 1 except Config.UsageError, detail : warn = Warning(func, lastLineNum, msgs.INVALID_CHECKER_ARGS % detail) warnings.append(warn) return 0 def debug(*args) : if cfg().debug: print args PYTHON_1_5 = 0x10502 PYTHON_2_0 = 0x20000 PYTHON_2_1 = 0x20100 PYTHON_2_2 = 0x20200 PYTHON_2_3 = 0x20300 PYTHON_2_4 = 0x20400 def pythonVersion() : return sys.hexversion >> 8 def startswith(s, substr) : "Ugh, supporting python 1.5 is a pain" return s[0:len(substr)] == substr def endswith(s, substr) : "Ugh, supporting python 1.5 is a pain" return s[-len(substr):] == substr # generic method that can be slapped into any class, thus the self parameter def std_repr(self) : return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), safestr(self)) try: unicode, UnicodeError except NameError: class UnicodeError(Exception): pass def safestr(value): try: return str(value) except UnicodeError: return unicode(value) spe-0.8.4.h/_spe/plugins/pychecker/OP.py0000755000175000017500000001016611002645341017035 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Python byte code operations. Very similar to the dis module, but dis does not exist in Jython, so recreate the small portion we need here. """ def LINE_NUM(op): return op == 127 def LOAD_GLOBAL(op): return op == 116 def LOAD_CONST(op): return op == 100 def LOAD_FAST(op): return op == 124 def LOAD_ATTR(op): return op == 105 def LOAD_DEREF(op): return op == 136 def STORE_ATTR(op): return op == 95 def POP_TOP(op): return op == 1 def IMPORT_FROM(op): return op == 108 def IMPORT_STAR(op): return op == 84 def UNARY_POSITIVE(op): return op == 10 def UNARY_NEGATIVE(op): return op == 11 def UNARY_INVERT(op): return op == 15 def RETURN_VALUE(op): return op == 83 def JUMP_FORWARD(op): return op == 110 def JUMP_ABSOLUTE(op): return op == 113 def FOR_ITER(op): return op == 93 def FOR_LOOP(op): return op == 114 def SETUP_LOOP(op): return op == 120 def BREAK_LOOP(op): return op == 80 def RAISE_VARARGS(op): return op == 130 def POP_BLOCK(op): return op == 87 def END_FINALLY(op): return op == 88 def CALL_FUNCTION(op): return op == 131 def UNPACK_SEQUENCE(op) : "Deal w/Python 1.5.2 (UNPACK_[LIST|TUPLE]) or 2.0 (UNPACK_SEQUENCE)" return op in (92, 93,) def IS_CONDITIONAL_JUMP(op): return op in (111, 112) def IS_NOT(op): return op == 12 HAVE_ARGUMENT = 90 EXTENDED_ARG = 143 _HAS_NAME = (90, 91, 95, 96, 97, 98, 101, 105, 107, 108, 116,) _HAS_LOCAL = (124, 125, 126,) _HAS_CONST = (100,) _HAS_COMPARE = (106,) _HAS_JREL = (110, 111, 112, 114, 120, 121, 122,) _HAS_JABS = (113, 119,) _CMP_OP = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is', 'is not', 'exception match', 'BAD') EXCEPT_COMPARISON = 10 IS_COMPARISON = 8 def getOperand(op, func_code, oparg) : if op in _HAS_NAME : return func_code.co_names[oparg] elif op in _HAS_LOCAL : return func_code.co_varnames[oparg] elif op in _HAS_CONST : return func_code.co_consts[oparg] elif op in _HAS_COMPARE : return _CMP_OP[oparg] return None def getLabel(op, oparg, i) : if op in _HAS_JREL : return i + oparg elif op in _HAS_JABS : return oparg return None def getInfo(code, index, extended_arg) : """Returns (op, oparg, index, extended_arg) based on code this is a helper function while looping through byte code, refer to the standard module dis.disassemble() for more info""" # get the operation we are performing op = ord(code[index]) index = index + 1 if op >= HAVE_ARGUMENT : # get the argument to the operation oparg = ord(code[index]) + ord(code[index+1])*256 + extended_arg index = index + 2 extended_arg = 0 if op == EXTENDED_ARG : extended_arg = oparg * 65536L else : oparg, extended_arg = 0, 0 return op, oparg, index, extended_arg def initFuncCode(func) : """Returns (func_code, code, i, maxCode, extended_arg) based on func, this is a helper function to setup looping through byte code""" func_code = func.func_code code = func_code.co_code return func_code, code, 0, len(code), 0 def conditional(op): "returns true if the code results in conditional execution" return op in [83, # return 93, # for_iter 111, 112, 114, # conditional jump 121, # setup_exec 130 # raise_varargs ] # this code is here for debugging purposes. # Jython doesn't support dis, so don't rely on it try : import dis name = dis.opname except ImportError : class Name: 'Turn name[x] into x' def __getitem__(self, x): from pychecker import utils return utils.safestr(x) name = Name() spe-0.8.4.h/_spe/plugins/pychecker/python.py0000755000175000017500000004135111002645341020040 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Setup a lot of info about Python builtin types, functions, methods, etc. """ import types import sys from pychecker import utils from pychecker import Stack from pychecker import Warning BOOL = types.IntType # name (type, args: min, max, kwArgs? GLOBAL_FUNC_INFO = { '__import__': (types.ModuleType, 1, 4), 'abs': (Stack.TYPE_UNKNOWN, 1, 1), 'apply': (Stack.TYPE_UNKNOWN, 2, 3), 'buffer': (types.BufferType, 1, 3), 'callable': (BOOL, 1, 1), 'chr': (types.StringType, 1, 1), 'cmp': (types.IntType, 2, 2), 'coerce': ([ types.NoneType, types.TupleType ], 2, 2), 'compile': (types.CodeType, 3, 3), 'complex': (types.ComplexType, 1, 2, ['real', 'imag']), 'delattr': (types.NoneType, 2, 2), 'dir': (types.ListType, 0, 1), 'divmod': (types.TupleType, 2, 2), 'eval': (Stack.TYPE_UNKNOWN, 1, 3), 'execfile': (types.NoneType, 1, 3), 'filter': (types.ListType, 2, 2), 'float': (types.FloatType, 1, 1), 'getattr': (Stack.TYPE_UNKNOWN, 2, 3), 'globals': (types.DictType, 0, 0), 'hasattr': (BOOL, 2, 2), 'hash': (types.IntType, 1, 1), 'hex': (types.StringType, 1, 1), 'id': (types.IntType, 1, 1), 'input': (Stack.TYPE_UNKNOWN, 0, 1), 'int': (types.IntType, 1, 2, ['x']), 'intern': (types.StringType, 1, 1), 'isinstance': (BOOL, 2, 2), 'issubclass': (BOOL, 2, 2), 'len': (types.IntType, 1, 1), 'list': (types.ListType, 1, 1, ['sequence']), 'locals': (types.DictType, 0, 0), 'long': (types.LongType, 1, 2, ['x']), 'map': (types.ListType, 2, None), 'max': (Stack.TYPE_UNKNOWN, 1, None), 'min': (Stack.TYPE_UNKNOWN, 1, None), 'oct': (types.StringType, 1, 1), 'open': (types.FileType, 1, 3, ['name', 'mode', 'buffering']), 'ord': (types.IntType, 1, 1), 'pow': (Stack.TYPE_UNKNOWN, 2, 3), 'range': (types.ListType, 1, 3), 'raw_input': (types.StringType, 0, 1), 'reduce': (Stack.TYPE_UNKNOWN, 2, 3), 'reload': (types.ModuleType, 1, 1), 'repr': (types.StringType, 1, 1), 'round': (types.FloatType, 1, 2), 'setattr': (types.NoneType, 3, 3), 'slice': (types.SliceType, 1, 3), 'str': (types.StringType, 1, 1), 'tuple': (types.TupleType, 1, 1), 'type': (types.TypeType, 1, 1), 'vars': (types.DictType, 0, 1), 'xrange': (types.ListType, 1, 3), } if hasattr(types, 'UnicodeType') : GLOBAL_FUNC_INFO['unichr'] = (types.UnicodeType, 1, 1) GLOBAL_FUNC_INFO['unicode'] = (types.UnicodeType, 1, 3, ['string', 'encoding', 'errors']) if utils.pythonVersion() >= utils.PYTHON_2_2 : GLOBAL_FUNC_INFO['compile'] = (types.CodeType, 3, 5) GLOBAL_FUNC_INFO['dict'] = (types.DictType, 0, 1, ['items']) GLOBAL_FUNC_INFO['file'] = GLOBAL_FUNC_INFO['open'] GLOBAL_FUNC_INFO['float'] = (types.FloatType, 0, 1, ['x']) GLOBAL_FUNC_INFO['int'] = (types.IntType, 0, 2, ['x']) GLOBAL_FUNC_INFO['list'] = (types.ListType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['long'] = (types.LongType, 0, 2, ['x']) GLOBAL_FUNC_INFO['str'] = (types.StringType, 0, 1, ['object']) # FIXME: type doesn't take 2 args, only 1 or 3 GLOBAL_FUNC_INFO['type'] = (types.TypeType, 1, 3, ['name', 'bases', 'dict']) GLOBAL_FUNC_INFO['tuple'] = (types.TupleType, 0, 1, ['sequence']) GLOBAL_FUNC_INFO['classmethod'] = (types.MethodType, 1, 1) GLOBAL_FUNC_INFO['iter'] = (Stack.TYPE_UNKNOWN, 1, 2) GLOBAL_FUNC_INFO['property'] = (Stack.TYPE_UNKNOWN, 0, 4, ['fget', 'fset', 'fdel', 'doc']) GLOBAL_FUNC_INFO['super'] = (Stack.TYPE_UNKNOWN, 1, 2) GLOBAL_FUNC_INFO['staticmethod'] = (types.MethodType, 1, 1) GLOBAL_FUNC_INFO['unicode'] = (types.UnicodeType, 0, 3, ['string', 'encoding', 'errors']) GLOBAL_FUNC_INFO['bool'] = (BOOL, 1, 1, ['x']) if utils.pythonVersion() >= utils.PYTHON_2_3: GLOBAL_FUNC_INFO['dict'] = (types.DictType, 0, 1, []) def tryAddGlobal(name, *args): if globals().has_key(name): GLOBAL_FUNC_INFO[name] = args zipMinArgs = 1 if utils.pythonVersion() >= utils.PYTHON_2_4: zipMinArgs = 0 tryAddGlobal('zip', types.ListType, zipMinArgs, None) tryAddGlobal('enumerate', types.TupleType, 1, 1, ['sequence']) # sum() could also return float/long tryAddGlobal('sum', types.IntType, 1, 2, ['start']) # sorted() and reversed() always return an iterator (FIXME: support iterator) tryAddGlobal('sorted', Stack.TYPE_UNKNOWN, 1, 1) tryAddGlobal('reversed', Stack.TYPE_UNKNOWN, 1, 1) _STRING_METHODS = { 'capitalize': (types.StringType, 0, 0), 'center': (types.StringType, 1, 1), 'count': (types.IntType, 1, 1), 'encode': (types.StringType, 0, 2), 'endswith': (BOOL, 1, 3), 'expandtabs': (types.StringType, 0, 1), 'find': (types.IntType, 1, 3), 'index': (types.IntType, 1, 3), 'isalnum': (BOOL, 0, 0), 'isalpha': (BOOL, 0, 0), 'isdigit': (BOOL, 0, 0), 'islower': (BOOL, 0, 0), 'isspace': (BOOL, 0, 0), 'istitle': (BOOL, 0, 0), 'isupper': (BOOL, 0, 0), 'join': (types.StringType, 1, 1), 'ljust': (types.StringType, 1, 1), 'lower': (types.StringType, 0, 0), 'lstrip': (types.StringType, 0, 0), 'replace': (types.StringType, 2, 3), 'rfind': (types.IntType, 1, 3), 'rindex': (types.IntType, 1, 3), 'rjust': (types.StringType, 1, 1), 'rstrip': (types.StringType, 0, 0), 'split': (types.ListType, 0, 2), 'splitlines': (types.ListType, 0, 1), 'startswith': (BOOL, 1, 3), 'strip': (types.StringType, 0, 0), 'swapcase': (types.StringType, 0, 0), 'title': (types.StringType, 0, 0), 'translate': (types.StringType, 1, 2), 'upper': (types.StringType, 0, 0), } if utils.pythonVersion() >= utils.PYTHON_2_2 : _STRING_METHODS['decode'] = (types.UnicodeType, 0, 2) if utils.pythonVersion() >= utils.PYTHON_2_4: _STRING_METHODS['rsplit'] = (types.StringType, 0, 2) _STRING_METHODS['center'] = (types.StringType, 1, 2), _STRING_METHODS['ljust'] = (types.StringType, 1, 2), _STRING_METHODS['rjust'] = (types.StringType, 1, 2), BUILTIN_METHODS = { types.DictType : { 'clear': (types.NoneType, 0, 0), 'copy': (types.DictType, 0, 0), 'get': (Stack.TYPE_UNKNOWN, 1, 2), 'has_key': (BOOL, 1, 1), 'items': (types.ListType, 0, 0), 'keys': (types.ListType, 0, 0), 'popitem': (types.TupleType, 0, 0), 'setdefault': (Stack.TYPE_UNKNOWN, 1, 2), 'update': (types.NoneType, 1, 1), 'values': (types.ListType, 0, 0), }, types.ListType : { 'append': (types.NoneType, 1, 1), 'count': (types.IntType, 1, 1), 'extend': (types.NoneType, 1, 1), 'index': (types.IntType, 1, 1), 'insert': (types.NoneType, 2, 2), 'pop': (Stack.TYPE_UNKNOWN, 0, 1), 'remove': (types.NoneType, 1, 1), 'reverse': (types.NoneType, 0, 0), 'sort': (types.NoneType, 0, 1), }, types.FileType : { 'close': (types.NoneType, 0, 0), 'fileno': (types.IntType, 0, 0), 'flush': (types.NoneType, 0, 0), 'isatty': (BOOL, 0, 0), 'read': (types.StringType, 0, 1), 'readinto': (types.NoneType, 1, 1), 'readline': (types.StringType, 0, 1), 'readlines': (types.ListType, 0, 1), 'seek': (types.NoneType, 1, 2), 'tell': (types.IntType, 0, 0), 'truncate': (types.NoneType, 0, 1), 'write': (types.NoneType, 1, 1), 'writelines': (types.NoneType, 1, 1), 'xreadlines': (types.ListType, 0, 0), }, } if utils.pythonVersion() >= utils.PYTHON_2_4: kwargs = ['cmp', 'key', 'reverse'] BUILTIN_METHODS[types.ListType]['sort'] =(types.NoneType, 0, 3, kwargs) if hasattr({}, 'pop'): BUILTIN_METHODS[types.DictType]['pop'] = (Stack.TYPE_UNKNOWN, 1, 2) def _setupBuiltinMethods() : if utils.pythonVersion() >= utils.PYTHON_2_2 : PY22_DICT_METHODS = { 'iteritems': (types.ListType, 0, 0), 'iterkeys': (types.ListType, 0, 0), 'itervalues': (types.ListType, 0, 0), } BUILTIN_METHODS[types.DictType].update(PY22_DICT_METHODS) try : BUILTIN_METHODS[types.ComplexType] = \ { 'conjugate': (types.ComplexType, 0, 0), } except AttributeError : pass if len(dir('')) > 0 : BUILTIN_METHODS[types.StringType] = _STRING_METHODS try : BUILTIN_METHODS[types.UnicodeType] = _STRING_METHODS except AttributeError : pass _setupBuiltinMethods() MUTABLE_TYPES = (types.ListType, types.DictType, types.InstanceType,) # identifiers which will become a keyword in a future version FUTURE_KEYWORDS = { 'yield': '2.2' } METHODLESS_OBJECTS = { types.NoneType : None, types.IntType : None, types.LongType : None, types.FloatType : None, types.BufferType : None, types.TupleType : None, types.EllipsisType : None, } def _setupBuiltinAttrs() : item = Stack.Item(None, None) BUILTIN_ATTRS[types.MethodType] = dir(item.__init__) del item if utils.pythonVersion() >= utils.PYTHON_2_2 : # FIXME: I'm sure more types need to be added here BUILTIN_ATTRS[types.StringType] = dir(''.__class__) BUILTIN_ATTRS[types.ListType] = dir([].__class__) BUILTIN_ATTRS[types.DictType] = dir({}.__class__) try : import warnings _MSG = "xrange object's 'start', 'stop' and 'step' attributes are deprecated" warnings.filterwarnings('ignore', _MSG) del warnings, _MSG except (ImportError, AssertionError): pass BUILTIN_ATTRS[types.XRangeType] = dir(xrange(0)) try: BUILTIN_ATTRS[types.ComplexType] = dir(complex(0, 1)) except: pass try: BUILTIN_ATTRS[types.UnicodeType] = dir(unicode('')) except: pass try: BUILTIN_ATTRS[types.CodeType] = dir(_setupBuiltinAttrs.func_code) except: pass try: BUILTIN_ATTRS[types.FileType] = dir(sys.__stdin__) except: pass try: raise TypeError except TypeError : try: tb = sys.exc_info()[2] BUILTIN_ATTRS[types.TracebackType] = dir(tb) BUILTIN_ATTRS[types.FrameType] = dir(tb.tb_frame) except: pass tb = None BUILTIN_ATTRS = { types.StringType : dir(''), types.TypeType : dir(type(type)), types.ListType : dir([]), types.DictType : dir({}), types.FunctionType : dir(_setupBuiltinAttrs), types.BuiltinFunctionType : dir(len), types.BuiltinMethodType : dir([].append), types.ClassType : dir(Stack.Item), types.UnboundMethodType : dir(Stack.Item.__init__), types.LambdaType : dir(lambda: None), types.SliceType : dir(slice(0)), } # have to setup the rest this way to support different versions of Python _setupBuiltinAttrs() PENDING_DEPRECATED_MODULES = { 'string': None, 'types': None, } DEPRECATED_MODULES = { 'FCNTL': 'fcntl', 'gopherlib': None, 'macfs': 'Carbon.File or Carbon.Folder', 'posixfile': 'fcntl', 'pre': None, 'regsub': 're', 'statcache': 'os.stat()', 'stringold': None, 'tzparse': None, 'TERMIOS': 'termios', 'whrandom':'random', 'xmllib': 'xml.sax', # C Modules 'mpz': None, 'pcre': None, 'pypcre': None, 'rgbimg': None, 'strop': None, 'xreadlines': 'file', } DEPRECATED_ATTRS = { 'array.read': None, 'array.write': None, 'operator.isCallable': None, 'operator.sequenceIncludes': None, 'pty.master_open': None, 'pty.slave_open': None, 'random.stdgamma': 'random.gammavariate', 'rfc822.AddrlistClass': 'rfc822.AddressList', 'string.atof': None, 'string.atoi': None, 'string.atol': None, 'string.zfill': None, 'sys.exc_traceback': None, 'sys.exit_thread': None, 'tempfile.mktemp': None, 'tempfile.template': None, } # FIXME: can't check these right now, maybe later DEPRECATED_METHODS = { 'email.Message.get_type': 'email.Message.get_content_type', 'email.Message.get_subtype': 'email.Message.get_content_subtype', 'email.Message.get_main_type': 'email.Message.get_content_maintype', 'htmllib.HTMLParser.do_nextid': None, 'pstats.Stats.ignore': None, 'random.Random.cunifvariate': None, 'random.Random.stdgamma': 'Random.gammavariate', } _OS_AND_POSIX_FUNCS = { 'tempnam': None, 'tmpnam': None } SECURITY_FUNCS = { 'os' : _OS_AND_POSIX_FUNCS, 'posix': _OS_AND_POSIX_FUNCS } SPECIAL_METHODS = { '__call__': None, # any number > 1 '__cmp__': 2, '__coerce__': 2, '__contains__': 2, '__del__': 1, '__hash__': 1, '__iter__': 1, '__len__': 1, '__new__': None, # new-style class constructor '__nonzero__': 1, '__reduce__': 1, '__hex__': 1, '__oct__': 1, '__repr__': 1, '__str__': 1, '__invert__': 1, '__neg__': 1, '__pos__': 1, '__abs__': 1, '__complex__': 1, '__int__': 1, '__long__': 1, '__float__': 1, '__eq__': 2, '__ne__': 2, '__ge__': 2, '__gt__': 2, '__le__': 2, '__lt__': 2, '__getattribute__': 2, # only in new-style classes '__getattr__': 2, '__setattr__': 3, '__delattr__': 2, '__getitem__': 2, '__setitem__': 3, '__delitem__': 2, '__getslice__': 3, '__setslice__': 4, '__delslice__': 3, # getslice is deprecated '__add__': 2, '__radd__': 2, '__iadd__': 2, '__sub__': 2, '__rsub__': 2, '__isub__': 2, '__mul__': 2, '__rmul__': 2, '__imul__': 2, '__div__': 2, '__rdiv__': 2, '__idiv__': 2, # __pow__: 2 or 3 __ipow__: 2 or 3 '__pow__': 3, '__rpow__': 2, '__ipow__': 3, '__truediv__': 2, '__rtruediv__': 2, '__itruediv__': 2, '__floordiv__': 2, '__rfloordiv__': 2, '__ifloordiv__': 2, '__mod__': 2, '__rmod__': 2, '__imod__': 2, '__divmod__': 2, '__rdivmod__': 2, # no inplace op for divmod() '__lshift__': 2, '__rlshift__': 2, '__ilshift__': 2, '__rshift__': 2, '__rrshift__': 2, '__irshift__': 2, '__and__': 2, '__rand__': 2, '__iand__': 2, '__xor__': 2, '__rxor__': 2, '__ixor__': 2, '__or__': 2, '__ror__': 2, '__ior__': 2, # these are related to pickling '__getstate__': 1, '__setstate__': 2, '__copy__': 1, '__deepcopy__': 2, '__getinitargs__': 1, } spe-0.8.4.h/_spe/plugins/pychecker/CodeChecks.py0000755000175000017500000021472311002645341020517 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2006, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Find warnings in byte code from Python source files. """ import string import types from pychecker import msgs from pychecker import utils from pychecker import Warning from pychecker import OP from pychecker import Stack from pychecker import python __pychecker__ = 'no-argsused' def cfg() : return utils.cfg() def getFunctionArgErr(func_name, argCount, minArgs, maxArgs): err = None if maxArgs == None: if argCount < minArgs : err = msgs.INVALID_ARG_COUNT2 % (func_name, argCount, minArgs) elif argCount < minArgs or argCount > maxArgs: if minArgs == maxArgs: err = msgs.INVALID_ARG_COUNT1 % (func_name, argCount, minArgs) else: err = msgs.INVALID_ARG_COUNT3 % (func_name, argCount, minArgs, maxArgs) return err def _checkFunctionArgCount(code, func_name, argCount, minArgs, maxArgs, objectReference = 0) : # there is an implied argument for object creation and self.xxx() if objectReference : minArgs = minArgs - 1 if maxArgs is not None : maxArgs = maxArgs - 1 err = getFunctionArgErr(func_name, argCount, minArgs, maxArgs) if err : code.addWarning(err) def _checkFunctionArgs(code, func, objectReference, argCount, kwArgs, check_arg_count = 1) : func_name = func.function.func_code.co_name if kwArgs : args_len = func.function.func_code.co_argcount arg_names = func.function.func_code.co_varnames[argCount:args_len] if argCount < args_len and kwArgs[0] in arg_names: if cfg().namedArgs : code.addWarning(msgs.FUNC_USES_NAMED_ARGS % func_name) # convert the named args into regular params, and really check while argCount < args_len and kwArgs and kwArgs[0] in arg_names: argCount = argCount + 1 kwArgs = kwArgs[1:] _checkFunctionArgs(code, func, objectReference, argCount, kwArgs, check_arg_count) return if not func.supportsKW : code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW % func_name) if check_arg_count : _checkFunctionArgCount(code, func_name, argCount, func.minArgs, func.maxArgs, objectReference) def _getReferenceFromModule(module, identifier) : func = module.functions.get(identifier, None) if func is not None : return func, None, 0 create = 0 c = module.classes.get(identifier, None) if c is not None : func = c.methods.get(utils.INIT, None) create = 1 return func, c, create def _getFunction(module, stackValue) : 'Return (function, class) from the stack value' identifier = stackValue.data if type(identifier) == types.StringType : return _getReferenceFromModule(module, identifier) # find the module this references i, maxLen = 0, len(identifier) while i < maxLen : id = utils.safestr(identifier[i]) if module.classes.has_key(id) or module.functions.has_key(id) : break refModule = module.modules.get(id, None) if refModule is not None : module = refModule else : return None, None, 0 i = i + 1 # if we got to the end, there is only modules, nothing we can do # we also can't handle if there is more than 2 items left if i >= maxLen or (i+2) < maxLen : return None, None, 0 if (i+1) == maxLen : return _getReferenceFromModule(module, identifier[-1]) # we can't handle self.x.y if (i+2) == maxLen and identifier[0] == cfg().methodArgName: return None, None, 0 c = module.classes.get(identifier[-2], None) if c is None : return None, None, 0 return c.methods.get(identifier[-1], None), c, 0 def _validateKwArgs(code, info, func_name, kwArgs): if len(info) < 4: code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW % func_name) elif not info[3]: return for arg in kwArgs: if arg not in info[3]: code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW_ARG % (func_name, arg)) def _checkBuiltin(code, loadValue, argCount, kwArgs, check_arg_count = 1) : returnValue = Stack.makeFuncReturnValue(loadValue, argCount) func_name = loadValue.data if loadValue.type == Stack.TYPE_GLOBAL : info = python.GLOBAL_FUNC_INFO.get(func_name, None) if info is not None : if func_name == 'input' and cfg().usesInput: code.addWarning(msgs.USES_INPUT) if cfg().constAttr and \ ((func_name == 'setattr' and argCount >= 2) or (func_name == 'getattr' and argCount == 2)): arg2 = code.stack[-argCount + 1] if arg2.const: code.addWarning(msgs.USES_CONST_ATTR % func_name) if kwArgs: _validateKwArgs(code, info, func_name, kwArgs) elif check_arg_count : _checkFunctionArgCount(code, func_name, argCount, info[1], info[2]) returnValue = Stack.Item(returnValue.data, info[0]) returnValue.setStringType(info[0]) elif type(func_name) == types.TupleType and len(func_name) <= 2 : objType = code.typeMap.get(utils.safestr(func_name[0]), []) if types.ListType in objType : try : if func_name[1] == 'append' and argCount > 1 : code.addWarning(msgs.LIST_APPEND_ARGS % func_name[0]) check_arg_count = 0 except AttributeError : # FIXME: why do we need to catch AttributeError??? pass if len(objType) == 1 : # if it's a builtin, check method builtinType = python.BUILTIN_METHODS.get(objType[0]) if builtinType is not None : methodInfo = builtinType.get(func_name[1]) # set func properly if kwArgs : _validateKwArgs(code, methodInfo, func_name[1], kwArgs) elif methodInfo : returnValue = Stack.Item(func_name[1], methodInfo[0]) returnValue.setStringType(methodInfo[0]) if check_arg_count and methodInfo is not None : _checkFunctionArgCount(code, func_name[1], argCount, methodInfo[1], methodInfo[2]) return returnValue _IMMUTABLE_LIST_METHODS = ('count', 'index',) _IMMUTABLE_DICT_METHODS = ('copy', 'get', 'has_key', 'items', 'keys', 'values', 'iteritems', 'iterkeys', 'itervalues') def _checkModifyDefaultArg(code, objectName, methodName=None) : try : value = code.func.defaultValue(objectName) objectType = type(value) if objectType in python.MUTABLE_TYPES : if objectType == types.DictType and \ methodName in _IMMUTABLE_DICT_METHODS : return if objectType == types.ListType and \ methodName in _IMMUTABLE_LIST_METHODS : return code.addWarning(msgs.MODIFYING_DEFAULT_ARG % objectName) except ValueError : pass def _isexception(object) : # FIXME: i have no idea why this function is necessary # it seems that the issubclass() should work, but it doesn't always if hasattr(object, 'type'): if object.type == types.TupleType: # if we have a tuple, we can't check the contents (not enough info) ## for item in object.value: ## if not _isexception(item): ## return 0 return 1 try: # try/except is necessary for globals like NotImplemented if issubclass(object, Exception) : return 1 except TypeError: return 0 for c in object.__bases__ : if utils.startswith(utils.safestr(c), 'exceptions.') : return 1 if len(c.__bases__) > 0 and _isexception(c) : return 1 return 0 def _checkStringFind(code, loadValue): if len(loadValue.data) == 2 and loadValue.data[1] == 'find': try: if types.StringType in code.typeMap.get(loadValue.data[0], []): op = code.nextOpInfo()[0] if OP.IS_CONDITIONAL_JUMP(op) or OP.IS_NOT(op): code.addWarning(msgs.BAD_STRING_FIND) except TypeError: # we don't care if loadValue.data[0] is not hashable pass def _checkAbstract(refClass, code, name): name_list = refClass.isAbstract() if name_list: name_list.sort() names = string.join(name_list, ", ") code.addWarning(msgs.METHODS_NEED_OVERRIDE % (names, name)) _SEQUENCE_TYPES = (types.TupleType, types.ListType, types.StringType) try: _SEQUENCE_TYPES = _SEQUENCE_TYPES + (types.UnicodeType,) except AttributeError: pass # FIXME: this is not complete. errors will be caught only sometimes, # depending on the order the functions/methods are processed # in the dict. Need to be able to run through all functions # twice, but because the code sucks, this is not possible. def _checkReturnValueUse(code, func): if func.returnValues is None: return err = None opInfo = code.nextOpInfo() if func.returnsNoValue(): # make sure we really know how to check for all the return types for rv in func.returnValues: if rv[1].type in _UNCHECKABLE_STACK_TYPES: return if not OP.POP_TOP(opInfo[0]): err = msgs.USING_NONE_RETURN_VALUE % utils.safestr(func) elif OP.UNPACK_SEQUENCE(opInfo[0]): # verify unpacking into proper # of vars varCount = opInfo[1] stackRV = func.returnValues[0][1] returnType = stackRV.getType({}) funcCount = stackRV.length if returnType in _SEQUENCE_TYPES: if varCount != funcCount and funcCount > 0: err = msgs.WRONG_UNPACK_FUNCTION % (utils.safestr(func), funcCount, varCount) elif returnType not in _UNCHECKABLE_STACK_TYPES: err = msgs.UNPACK_NON_SEQUENCE % (utils.safestr(func), _getTypeStr(returnType)) if err: code.addWarning(err) def _handleFunctionCall(codeSource, code, argCount, indexOffset = 0, check_arg_count = 1) : 'Checks for warnings, returns function called (may be None)' if not code.stack : return kwArgCount = argCount >> utils.VAR_ARGS_BITS argCount = argCount & utils.MAX_ARGS_MASK # function call on stack is before the args, and keyword args funcIndex = argCount + 2 * kwArgCount + 1 + indexOffset if funcIndex > len(code.stack) : funcIndex = 0 # to find on stack, we have to look backwards from top of stack (end) funcIndex = -funcIndex # store the keyword names/keys to check if using named arguments kwArgs = [] if kwArgCount > 0 : # loop backwards by 2 (keyword, value) in stack to find keyword args for i in range(-2 - indexOffset, (-2 * kwArgCount - 1), -2) : kwArgs.append(code.stack[i].data) kwArgs.reverse() loadValue = code.stack[funcIndex] funcName = loadValue.getName() returnValue = Stack.makeFuncReturnValue(loadValue, argCount) if loadValue.isMethodCall(codeSource.classObject, cfg().methodArgName): methodName = loadValue.data[1] try : m = codeSource.classObject.methods[methodName] if m != None : objRef = not m.isStaticMethod() _checkFunctionArgs(code, m, objRef, argCount, kwArgs, check_arg_count) except KeyError : sattr = codeSource.classObject.statics.get(methodName) if sattr is not None : funcName = sattr.getName() if sattr is None and cfg().callingAttribute : code.addWarning(msgs.INVALID_METHOD % methodName) elif loadValue.type in (Stack.TYPE_ATTRIBUTE, Stack.TYPE_GLOBAL) and \ type(loadValue.data) in (types.StringType, types.TupleType) : # apply(func, (args)), can't check # of args, so just return func if loadValue.data == 'apply' : loadValue = code.stack[funcIndex+1] funcName = loadValue.getName() else : if cfg().modifyDefaultValue and \ type(loadValue.data) == types.TupleType : _checkModifyDefaultArg(code, loadValue.data[0], loadValue.data[1]) func, refClass, method = _getFunction(codeSource.module, loadValue) if func == None and type(loadValue.data) == types.TupleType and \ len(loadValue.data) == 2 : # looks like we are making a method call data = loadValue.data if type(data[0]) == types.StringType : # do we know the type of the local variable? varType = code.typeMap.get(data[0]) if varType is not None and len(varType) == 1 : if hasattr(varType[0], 'methods') : # it's a class & we know the type, get the method func = varType[0].methods.get(data[1]) if func is not None : method = 1 if cfg().abstractClasses and refClass and method: _checkAbstract(refClass, code, funcName) if cfg().stringFind: _checkStringFind(code, loadValue) if func != None : if refClass and func.isClassMethod(): argCount = argCount + 1 _checkFunctionArgs(code, func, method, argCount, kwArgs, check_arg_count) # if this isn't a c'tor, we should check if not (refClass and method) and cfg().checkReturnValues: _checkReturnValueUse(code, func) if refClass : if method : # c'tor, return the class as the type returnValue = Stack.Item(loadValue, refClass) elif func.isClassMethod(): # FIXME: do anything here? pass elif argCount > 0 and cfg().methodArgName and \ not func.isStaticMethod() and \ code.stack[funcIndex].type == Stack.TYPE_ATTRIBUTE and \ code.stack[funcIndex+1].data != cfg().methodArgName: e = msgs.SELF_NOT_FIRST_ARG % (cfg().methodArgName, '') code.addWarning(e) elif refClass and method : returnValue = Stack.Item(loadValue, refClass) if (argCount > 0 or len(kwArgs) > 0) and \ not refClass.ignoreAttrs and \ not refClass.methods.has_key(utils.INIT) and \ not _isexception(refClass.classObject) : code.addWarning(msgs.NO_CTOR_ARGS) else : returnValue = _checkBuiltin(code, loadValue, argCount, kwArgs, check_arg_count) if returnValue.type is types.NoneType and \ not OP.POP_TOP(code.nextOpInfo()[0]) : name = utils.safestr(loadValue.data) if type(loadValue.data) == types.TupleType : name = string.join(loadValue.data, '.') code.addWarning(msgs.USING_NONE_RETURN_VALUE % name) code.stack = code.stack[:funcIndex] + [ returnValue ] code.functionsCalled[funcName] = loadValue def _classHasAttribute(c, attr) : return (c.methods.has_key(attr) or c.members.has_key(attr) or hasattr(c.classObject, attr)) def _checkClassAttribute(attr, c, code) : if _classHasAttribute(c, attr) : try : del c.memberRefs[attr] except KeyError : pass elif cfg().classAttrExists : code.addWarning(msgs.INVALID_CLASS_ATTR % attr) def _checkModuleAttribute(attr, module, code, ref) : try: if attr not in module.modules[ref].attributes and \ not utils.endswith(ref, '.' + attr) : code.addWarning(msgs.INVALID_MODULE_ATTR % attr) except (KeyError, TypeError): # if ref isn't found, or ref isn't even hashable, we don't care # we may not know, or ref could be something funky [e for e].method() pass try: _checkClassAttribute(attr, module.classes[ref], code) except (KeyError, TypeError): # if ref isn't found, or ref isn't even hashable, we don't care # we may not know, or ref could be something funky [e for e].method() pass def _getGlobalName(name, func) : # get the right name of global refs (for from XXX import YYY) opModule = func.function.func_globals.get(name) try : if opModule and isinstance(opModule, types.ModuleType) : name = opModule.__name__ except : # we have to do this in case the class raises an access exception # due to overriding __special__() methods pass return name def _checkNoEffect(code, ignoreStmtWithNoEffect=0): if (not ignoreStmtWithNoEffect and OP.POP_TOP(code.nextOpInfo()[0]) and cfg().noEffect): code.addWarning(msgs.POSSIBLE_STMT_WITH_NO_EFFECT) def _makeConstant(code, index, factoryFunction) : "Build a constant on the stack ((), [], or {})" if index > 0 : code.stack[-index:] = [ factoryFunction(code.stack[-index:]) ] _checkNoEffect(code) else : code.pushStack(factoryFunction()) def _hasGlobal(operand, module, func, main) : return (func.function.func_globals.has_key(operand) or main or module.moduleLineNums.has_key(operand) or __builtins__.has_key(operand)) def _checkGlobal(operand, module, func, code, err, main = 0) : if not _hasGlobal(operand, module, func, main) : code.addWarning(err % operand) if not cfg().reportAllGlobals : func.function.func_globals[operand] = operand def _handleComparison(stack, operand) : num_ops = 2 if operand == 'exception match': num_ops = 1 si = min(len(stack), num_ops) compareValues = stack[-si:] for _ in range(si, 2) : compareValues.append(Stack.Item(None, None)) stack[-si:] = [ Stack.makeComparison(compareValues, operand) ] return compareValues def _handleImport(code, operand, module, main, fromName) : # FIXME: this function should be refactored/cleaned up key = operand tmpOperand = tmpFromName = operand if fromName is not None : tmpOperand = tmpFromName = fromName key = (fromName, operand) if cfg().deprecated: try: undeprecated = python.DEPRECATED_MODULES[tmpFromName] except KeyError: pass else: msg = msgs.USING_DEPRECATED_MODULE % tmpFromName if undeprecated: msg.data = msg.data + msgs.USE_INSTEAD % undeprecated code.addWarning(msg) if cfg().reimportSelf and tmpOperand == module.module.__name__ : code.addWarning(msgs.IMPORT_SELF % tmpOperand) modline1 = module.moduleLineNums.get(tmpOperand, None) modline2 = module.moduleLineNums.get((tmpFromName, '*'), None) key2 = (tmpFromName,) if fromName is not None and operand != '*' : key2 = (tmpFromName, operand) modline3 = module.moduleLineNums.get(key2, None) if modline1 is not None or modline2 is not None or modline3 is not None : err = None if fromName is None : if modline1 is not None : err = msgs.MODULE_IMPORTED_AGAIN % operand elif cfg().mixImport : err = msgs.MIX_IMPORT_AND_FROM_IMPORT % tmpFromName else : if modline3 is not None and operand != '*' : err = 'from %s import %s' % (tmpFromName, operand) err = msgs.MODULE_MEMBER_IMPORTED_AGAIN % err elif modline1 is not None : if cfg().mixImport and code.getLineNum() != modline1[1] : err = msgs.MIX_IMPORT_AND_FROM_IMPORT % tmpFromName else : err = msgs.MODULE_MEMBER_ALSO_STAR_IMPORTED % fromName # filter out warnings when files are different (ie, from X import ...) if err is not None and cfg().moduleImportErrors : bytes = module.main_code if bytes is None or \ bytes.function.func_code.co_filename == code.func_code.co_filename : code.addWarning(err) if main : fileline = (code.func_code.co_filename, code.getLineNum()) module.moduleLineNums[key] = fileline if fromName is not None : module.moduleLineNums[(fromName,)] = fileline def _handleImportFrom(code, operand, module, main) : fromName = code.stack[-1].data if utils.pythonVersion() < utils.PYTHON_2_0 and \ OP.POP_TOP(code.nextOpInfo()[0]): code.popNextOp() code.pushStack(Stack.Item(operand, types.ModuleType)) _handleImport(code, operand, module, main, fromName) # http://www.python.org/doc/current/lib/typesseq-strings.html _FORMAT_CONVERTERS = 'diouxXeEfFgGcrs' # NOTE: lLh are legal in the flags, but are ignored by python, we warn _FORMAT_FLAGS = '*#- +.' + string.digits def _getFormatInfo(format, code) : vars = [] # first get rid of all the instances of %% in the string, they don't count format = string.replace(format, "%%", "") sections = string.split(format, '%') percentFormatCount = formatCount = string.count(format, '%') mappingFormatCount = 0 # skip the first item in the list, it's always empty for section in sections[1:] : orig_section = section if not section: w = msgs.INVALID_FORMAT % orig_section w.data = w.data + ' (end of format string)' code.addWarning(w) continue # handle dictionary formats if section[0] == '(' : mappingFormatCount = mappingFormatCount + 1 varname = string.split(section, ')') if varname[1] == '' : code.addWarning(msgs.INVALID_FORMAT % section) vars.append(varname[0][1:]) section = varname[1] if not section : # no format data to check continue # FIXME: we ought to just define a regular expression to check # formatRE = '[ #+-]*([0-9]*|*)(|.(|*|[0-9]*)[diouxXeEfFgGcrs].*' stars = 0 for i in range(0, len(section)) : if section[i] in _FORMAT_CONVERTERS : break if section[i] in _FORMAT_FLAGS : if section[i] == '*' : stars = stars + 1 if mappingFormatCount > 0 : code.addWarning(msgs.USING_STAR_IN_FORMAT_MAPPING % section) if stars > 2 : code.addWarning(msgs.TOO_MANY_STARS_IN_FORMAT) formatCount = formatCount + stars if section[i] not in _FORMAT_CONVERTERS : code.addWarning(msgs.INVALID_FORMAT % orig_section) if mappingFormatCount > 0 and mappingFormatCount != percentFormatCount : code.addWarning(msgs.CANT_MIX_MAPPING_IN_FORMATS) return formatCount, vars def _getConstant(code, module, data) : data = utils.safestr(data.data) format = code.constants.get(data) if format is not None : return format format = module.variables.get(data) if format is not None and format.value is not None : return format.value return None _UNCHECKABLE_FORMAT_STACK_TYPES = \ (Stack.TYPE_UNKNOWN, Stack.TYPE_FUNC_RETURN, Stack.TYPE_ATTRIBUTE, Stack.TYPE_GLOBAL, Stack.TYPE_EXCEPT) _UNCHECKABLE_STACK_TYPES = _UNCHECKABLE_FORMAT_STACK_TYPES + (types.NoneType,) def _getFormatString(code, codeSource) : if len(code.stack) <= 1 : return '' format = code.stack[-2] if format.type != types.StringType or not format.const : format = _getConstant(code, codeSource.module, format) if format is None or type(format) != types.StringType : return '' return format return format.data def _getFormatWarnings(code, codeSource) : format = _getFormatString(code, codeSource) if not format : return args = 0 count, vars = _getFormatInfo(format, code) topOfStack = code.stack[-1] if topOfStack.isLocals() : for varname in vars : if not code.unusedLocals.has_key(varname) : code.addWarning(msgs.NO_LOCAL_VAR % varname) else : code.unusedLocals[varname] = None else : stackItemType = topOfStack.getType(code.typeMap) if ((stackItemType == types.DictType and len(vars) > 0) or codeSource.func.isParam(topOfStack.data) or stackItemType in _UNCHECKABLE_FORMAT_STACK_TYPES) : return if topOfStack.type == types.TupleType : args = topOfStack.length elif stackItemType == types.TupleType : args = len(code.constants.get(topOfStack.data, (0,))) else : args = 1 if args and count != args : code.addWarning(msgs.INVALID_FORMAT_COUNT % (count, args)) def _checkAttributeType(code, stackValue, attr) : if not cfg().checkObjectAttrs : return varTypes = code.typeMap.get(utils.safestr(stackValue.data), None) if not varTypes : return # the value may have been converted on stack (`v`) other_types = [] if stackValue.type not in varTypes : other_types = [stackValue.type] for varType in varTypes + other_types : # ignore built-in types that have no attributes if python.METHODLESS_OBJECTS.has_key(varType) : continue attrs = python.BUILTIN_ATTRS.get(varType, None) if attrs is not None : if attr in attrs : return continue if hasattr(varType, 'ignoreAttrs') : if varType.ignoreAttrs or _classHasAttribute(varType, attr) : return elif not hasattr(varType, 'attributes') or attr in varType.attributes : return code.addWarning(msgs.OBJECT_HAS_NO_ATTR % (stackValue.data, attr)) def _getTypeStr(t): returnStr = utils.safestr(t) strs = string.split(returnStr, "'") try: if len(strs) == 3: returnStr = strs[-2] except IndexError: pass return returnStr def _getLineNum(co, instr_index): co_lnotab = co.co_lnotab lineno = co.co_firstlineno addr = 0 for lnotab_index in range(0, len(co_lnotab), 2): addr = addr + ord(co_lnotab[lnotab_index]) if addr > instr_index: return lineno lineno = lineno + ord(co_lnotab[lnotab_index+1]) return lineno class Code : 'Hold all the code state information necessary to find warnings' def __init__(self) : self.bytes = None self.func = None self.func_code = None self.index = 0 self.indexList = [] self.extended_arg = 0 self.lastLineNum = 0 self.maxCode = 0 self.has_except = 0 self.try_finally_first = 0 self.starts_and_ends_with_finally = 0 self.returnValues = [] self.raiseValues = [] self.stack = [] self.unpackCount = 0 self.loops = 0 self.branches = {} self.warnings = [] self.globalRefs = {} self.unusedLocals = {} self.deletedLocals = {} self.functionsCalled = {} self.typeMap = {} self.constants = {} self.codeObjects = {} def init(self, func) : self.func = func self.func_code, self.bytes, self.index, self.maxCode, self.extended_arg = \ OP.initFuncCode(func.function) self.lastLineNum = self.func_code.co_firstlineno self.returnValues = [] # initialize the arguments to unused for arg in func.arguments() : self.unusedLocals[arg] = 0 self.typeMap[arg] = [ Stack.TYPE_UNKNOWN ] def getLineNum(self): line = self.lastLineNum # if we don't have linenum info, calc it from co_lntab & index if line == self.func_code.co_firstlineno: # FIXME: this could be optimized, if we kept last line info line = _getLineNum(self.func_code, self.index - 1) return line def getWarning(self, err, line = None) : if line is None : line = self.getLineNum() return Warning.Warning(self.func_code, line, err) def addWarning(self, err, line = None) : w = err if not isinstance(w, Warning.Warning): w = self.getWarning(err, line) self.warnings.append(w) def popNextOp(self) : self.indexList.append(self.index) info = OP.getInfo(self.bytes, self.index, self.extended_arg) op, oparg, self.index, self.extended_arg = info if op < OP.HAVE_ARGUMENT : utils.debug(" %d %s" % (self.indexList[-1], OP.name[op])) operand = None else : operand = OP.getOperand(op, self.func_code, oparg) self.label = label = OP.getLabel(op, oparg, self.index) utils.debug(" %d %s" % (self.indexList[-1], OP.name[op]), oparg, operand) if label != None : self.addBranch(label) return op, oparg, operand def nextOpInfo(self, offset = 0) : try : return OP.getInfo(self.bytes, self.index + offset, 0)[0:3] except IndexError : return -1, 0, -1 def getFirstOp(self) : # find the first real op, maybe we should not check if params are used i = extended_arg = 0 while i < self.maxCode : op, oparg, i, extended_arg = OP.getInfo(self.bytes, i, extended_arg) if not OP.LINE_NUM(op) : if not (OP.LOAD_CONST(op) or OP.LOAD_GLOBAL(op)) : return op raise RuntimeError('Could not find first opcode in function') def pushStack(self, item, ignoreStmtWithNoEffect=0): self.stack.append(item) _checkNoEffect(self, ignoreStmtWithNoEffect) def popStack(self) : if self.stack : del self.stack[-1] def popStackItems(self, count) : stackLen = len(self.stack) if stackLen > 0 : count = min(count, stackLen) del self.stack[-count:] def unpack(self) : if self.unpackCount : self.unpackCount = self.unpackCount - 1 else : self.popStack() def __getStringStackType(self, data) : try : return data.getType({}) except AttributeError : return Stack.TYPE_UNKNOWN def __getStackType(self) : if not self.stack : return Stack.TYPE_UNKNOWN if not self.unpackCount : return self.__getStringStackType(self.stack[-1]) data = self.stack[-1].data if type(data) == types.TupleType : try : return self.__getStringStackType(data[len(data)-self.unpackCount]) except IndexError : # happens when unpacking a var for which we don't know the size pass return Stack.TYPE_UNKNOWN def setType(self, name) : valueList = self.typeMap.get(name, []) newType = self.__getStackType() # longs are being merged with ints, assume they are the same # comparisons are really ints anyways if newType in (types.LongType, Stack.TYPE_COMPARISON): newType = types.IntType if newType not in valueList : valueList.append(newType) # need to ignore various types (Unknown, Func return values, etc) # also ignore None, don't care if they use it and a real type if valueList and newType not in _UNCHECKABLE_STACK_TYPES and \ cfg().inconsistentTypes: oldTypes = [] # only add types to the value list that are "interesting" for typeToAdd in valueList: if typeToAdd not in _UNCHECKABLE_STACK_TYPES and \ typeToAdd != newType: oldTypes.append(_getTypeStr(typeToAdd)) # do we have any "interesting" old types? if so, warn if oldTypes: self.addWarning(msgs.INCONSISTENT_TYPE % \ (name, oldTypes, _getTypeStr(newType))) self.typeMap[name] = valueList def addReturn(self) : if len(self.stack) > 0 : value = (self.getLineNum(), self.stack[-1], self.nextOpInfo()[2]) self.returnValues.append(value) self.popStack() def addRaise(self) : self.raiseValues.append((self.getLineNum(), None, self.nextOpInfo()[2])) def addBranch(self, label) : if label is not None : self.branches[label] = self.branches.get(label, 0) + 1 def removeBranch(self, label) : branch = self.branches.get(label, None) if branch is not None : if branch == 1 : del self.branches[label] else : self.branches[label] = branch - 1 def remove_unreachable_code(self, label) : if len(self.indexList) >= 2 : index = self.indexList[-2] if index >= 0 and OP.POP_BLOCK(ord(self.bytes[index])) : index = self.indexList[-3] if index >= 0 : op = ord(self.bytes[index]) if OP.RETURN_VALUE(op) or OP.RAISE_VARARGS(op) or \ OP.END_FINALLY(ord(self.bytes[label-1])) : self.removeBranch(label) def updateCheckerArgs(self, operand) : rc = utils.shouldUpdateArgs(operand) if rc : utils.updateCheckerArgs(self.stack[-1].data, self.func_code, self.getLineNum(), self.warnings) return rc def updateModuleLineNums(self, module, operand) : filelist = (self.func_code.co_filename, self.getLineNum()) module.moduleLineNums[operand] = filelist class CodeSource : 'Holds source information about a code block (module, class, func, etc)' def __init__(self, module, func, c, main, in_class, code) : self.module = module self.func = func self.classObject = c self.main = main self.in_class = in_class self.code = code self.calling_code = [] def _checkException(code, name) : if code.stack and code.stack[-1].type == Stack.TYPE_EXCEPT : if __builtins__.has_key(name) : code.addWarning(msgs.SET_EXCEPT_TO_BUILTIN % name) def _checkAssign(code, name): if name in _BAD_ASSIGN_NAMES: code.addWarning(msgs.SHOULDNT_ASSIGN_BUILTIN % name) else: cap = string.capitalize(name) if cap in _BAD_ASSIGN_NAMES: code.addWarning(msgs.SHOULDNT_ASSIGN_NAME % (name, cap)) def _checkVariableOperationOnItself(code, lname, msg): if code.stack and code.stack[-1].getName() == lname: code.addWarning(msg % lname) def _checkFutureKeywords(code, varname) : kw = python.FUTURE_KEYWORDS.get(varname) if kw is not None : code.addWarning(msgs.USING_KEYWORD % (varname, kw)) def _STORE_NAME(oparg, operand, codeSource, code) : if not code.updateCheckerArgs(operand) : _checkFutureKeywords(code, operand) module = codeSource.module if not codeSource.in_class : _checkShadowBuiltin(code, operand) if not codeSource.calling_code : _checkGlobal(operand, module, codeSource.func, code, msgs.GLOBAL_DEFINED_NOT_DECLARED, codeSource.main) else : if code.stack : codeSource.classObject.statics[operand] = code.stack[-1] codeSource.classObject.lineNums[operand] = code.getLineNum() var = module.variables.get(operand) if var is not None and code.stack and code.stack[-1].const : var.value = code.stack[-1].data if code.unpackCount : code.unpackCount = code.unpackCount - 1 else: _checkAssign(code, operand) _checkException(code, operand) code.popStack() if not module.moduleLineNums.has_key(operand) and codeSource.main : code.updateModuleLineNums(module, operand) _STORE_GLOBAL = _STORE_NAME def _checkLoadGlobal(codeSource, code, varname) : _checkFutureKeywords(code, varname) should_check = 1 if code.func_code.co_name == utils.LAMBDA : # this could really be a local reference, check first if not codeSource.main and codeSource.calling_code: func = getattr(codeSource.calling_code[-1], 'function', None) if func is not None and varname in func.func_code.co_varnames : _handleLoadLocal(code, codeSource, varname) should_check = 0 if should_check : # if a global var starts w/__ and the global is referenced in a class # we have to strip off the _class-name, to get the original name if codeSource.classObject and \ utils.startswith(varname, '_' + codeSource.classObject.name + '__'): varname = varname[len(codeSource.classObject.name)+1:] # make sure we remember each global ref to check for unused code.globalRefs[_getGlobalName(varname, codeSource.func)] = varname if not codeSource.in_class : _checkGlobal(varname, codeSource.module, codeSource.func, code, msgs.INVALID_GLOBAL) def _LOAD_NAME(oparg, operand, codeSource, code) : _checkLoadGlobal(codeSource, code, operand) # if there was from XXX import *, _* names aren't imported if codeSource.module.modules.has_key(operand) and \ hasattr(codeSource.module.module, operand) : operand = getattr(codeSource.module.module, operand).__name__ opType, const = Stack.TYPE_GLOBAL, 0 if operand == 'None' : opType, const = types.NoneType, 0 elif operand == 'Ellipsis' : opType, const = types.EllipsisType, 1 code.pushStack(Stack.Item(operand, opType, const)) _LOAD_GLOBAL = _LOAD_NAME def _LOAD_DEREF(oparg, operand, codeSource, code) : if type(oparg) == types.IntType : func_code = code.func_code try: argname = func_code.co_cellvars[oparg] except IndexError: argname = func_code.co_freevars[oparg - len(func_code.co_cellvars)] code.pushStack(Stack.Item(argname, types.StringType)) if code.func_code.co_name != utils.LAMBDA : code.unusedLocals[argname] = None else : _LOAD_GLOBAL(oparg, operand, codeSource, code) _LOAD_CLOSURE = _LOAD_DEREF def _DELETE_NAME(oparg, operand, codeSource, code) : _checkLoadGlobal(codeSource, code, operand) # FIXME: handle deleting global multiple times _DELETE_GLOBAL = _DELETE_NAME def _make_const(value): if type(value) == types.TupleType: return Stack.makeTuple(map(_make_const, value)) return Stack.Item(value, type(value), 1) def _LOAD_CONST(oparg, operand, codeSource, code) : code.pushStack(_make_const(operand)) if type(operand) == types.CodeType : name = operand.co_name obj = code.codeObjects.get(name, None) if name == utils.LAMBDA : # use a unique key, so we can have multiple lambdas code.codeObjects[code.index] = operand elif obj is None : code.codeObjects[name] = operand elif cfg().redefiningFunction : code.addWarning(msgs.REDEFINING_ATTR % (name, obj.co_firstlineno)) def _checkLocalShadow(code, module, varname) : if module.variables.has_key(varname) and cfg().shadows : line = module.moduleLineNums.get(varname, ('', 0)) w = code.getWarning(msgs.LOCAL_SHADOWS_GLOBAL % (varname, line[1])) if line[0] != w.file: w.err = '%s in file %s' % (w.err, line[0]) code.addWarning(w) def _checkShadowBuiltin(code, varname) : if __builtins__.has_key(varname) and varname[0] != '_' and \ cfg().shadowBuiltins: code.addWarning(msgs.VARIABLE_SHADOWS_BUILTIN % varname) def _checkLoadLocal(code, codeSource, varname, deletedWarn, usedBeforeSetWarn) : _checkFutureKeywords(code, varname) deletedLine = code.deletedLocals.get(varname) if deletedLine : code.addWarning(deletedWarn % (varname, deletedLine)) elif not code.unusedLocals.has_key(varname) and \ not codeSource.func.isParam(varname) : code.addWarning(usedBeforeSetWarn % varname) code.unusedLocals[varname] = None _checkLocalShadow(code, codeSource.module, varname) def _handleLoadLocal(code, codeSource, varname) : _checkLoadLocal(code, codeSource, varname, msgs.LOCAL_DELETED, msgs.VAR_USED_BEFORE_SET) def _LOAD_FAST(oparg, operand, codeSource, code) : code.pushStack(Stack.Item(operand, type(operand))) _handleLoadLocal(code, codeSource, operand) def _STORE_FAST(oparg, operand, codeSource, code) : if not code.updateCheckerArgs(operand) : _checkFutureKeywords(code, operand) if code.stack and code.stack[-1].type == types.StringType and \ not code.stack[-1].const: _checkVariableOperationOnItself(code, operand, msgs.SET_VAR_TO_ITSELF) code.setType(operand) if not code.unpackCount and code.stack and \ (code.stack[-1].const or code.stack[-1].type == types.TupleType) : if code.constants.has_key(operand) : del code.constants[operand] else : code.constants[operand] = code.stack[-1].data _checkLocalShadow(code, codeSource.module, operand) _checkShadowBuiltin(code, operand) _checkAssign(code, operand) _checkException(code, operand) if code.deletedLocals.has_key(operand) : del code.deletedLocals[operand] if not code.unusedLocals.has_key(operand) : errLine = code.getLineNum() if code.unpackCount and not cfg().unusedLocalTuple : errLine = -errLine code.unusedLocals[operand] = errLine code.unpack() def _DELETE_FAST(oparg, operand, codeSource, code) : _checkLoadLocal(code, codeSource, operand, msgs.LOCAL_ALREADY_DELETED, msgs.VAR_DELETED_BEFORE_SET) code.deletedLocals[operand] = code.getLineNum() def _checkAttribute(top, operand, codeSource, code) : if top.data == cfg().methodArgName and codeSource.classObject != None : _checkClassAttribute(operand, codeSource.classObject, code) elif type(top.type) == types.StringType or top.type == types.ModuleType : _checkModuleAttribute(operand, codeSource.module, code, top.data) else : _checkAttributeType(code, top, operand) def _checkExcessiveReferences(code, top, extraAttr = None) : if cfg().maxReferences <= 0 : return try : data = top.data if extraAttr is not None : data = data + (extraAttr,) maxReferences = cfg().maxReferences if data[0] == cfg().methodArgName: maxReferences = maxReferences + 1 if len(data) > maxReferences : name = string.join(top.data, '.') code.addWarning(msgs.TOO_MANY_REFERENCES % (maxReferences, name)) except TypeError : pass def _checkDeprecated(code, identifierTuple): # check deprecated module.function try: name = string.join(identifierTuple, '.') undeprecated = python.DEPRECATED_ATTRS[name] except (KeyError, TypeError): pass else: msg = msgs.USING_DEPRECATED_ATTR % name if undeprecated: msg.data = msg.data + msgs.USE_INSTEAD % undeprecated code.addWarning(msg) def _LOAD_ATTR(oparg, operand, codeSource, code) : if len(code.stack) > 0 : top = code.stack[-1] _checkAttribute(top, operand, codeSource, code) top.addAttribute(operand) if len(top.data) == 2: if cfg().deprecated: _checkDeprecated(code, top.data) try: insecure = python.SECURITY_FUNCS.get(top.data[0]) except TypeError: pass else: if insecure and insecure.has_key(operand): func = string.join(top.data, '.') code.addWarning(msgs.USING_INSECURE_FUNC % func) nextOp = code.nextOpInfo()[0] if not OP.LOAD_ATTR(nextOp) : if OP.POP_TOP(nextOp) and cfg().noEffect: code.addWarning(msgs.POSSIBLE_STMT_WITH_NO_EFFECT) else : _checkExcessiveReferences(code, top) def _ok_to_set_attr(classObject, basename, attr) : return (cfg().onlyCheckInitForMembers and classObject != None and basename == cfg().methodArgName and not _classHasAttribute(classObject, attr)) def _STORE_ATTR(oparg, operand, codeSource, code) : if code.stack : top = code.stack.pop() top_name = '%s.%s' % (top.getName(), operand) try: # FIXME: this is a hack to handle code like: # a.a = [x for x in range(2) if x > 1] previous = code.stack[-1] except IndexError: previous = None if top.type in (types.StringType, Stack.TYPE_ATTRIBUTE) and \ previous and previous.type == Stack.TYPE_ATTRIBUTE: _checkVariableOperationOnItself(code, top_name, msgs.SET_VAR_TO_ITSELF) _checkExcessiveReferences(code, top, operand) if _ok_to_set_attr(codeSource.classObject, top.data, operand) : code.addWarning(msgs.INVALID_SET_CLASS_ATTR % operand) code.unpack() def _DELETE_ATTR(oparg, operand, codeSource, code) : if len(code.stack) > 0 : _checkAttribute(code.stack[-1], operand, codeSource, code) def _getExceptionInfo(codeSource, item): # FIXME: probably ought to try to handle raise module.Error if item.type is types.StringType and item.const == 1: return item.data, 1 e = None if item.type is Stack.TYPE_GLOBAL: try: e = eval(item.data) except NameError: pass if not e: try: c = codeSource.module.classes.get(item.data) except TypeError: # item.data may not be hashable (e.g., list) return e, 0 if c is not None: e = c.classObject else: v = codeSource.module.variables.get(item.data) if v is not None: return v, (v.type == types.StringType) return e, 0 _UNCHECKABLE_CATCH_TYPES = (Stack.TYPE_UNKNOWN, Stack.TYPE_ATTRIBUTE) def _checkCatchException(codeSource, code, item): if not cfg().badExceptions: return if item.data is None or item.type in _UNCHECKABLE_CATCH_TYPES: return e, is_str = _getExceptionInfo(codeSource, item) if is_str: code.addWarning(msgs.CATCH_STR_EXCEPTION % item.data) elif e is not None and not _isexception(e): code.addWarning(msgs.CATCH_BAD_EXCEPTION % item.data) def _handleExceptionChecks(codeSource, code, checks): for item in checks: if item is not None: if item.type is not types.TupleType: _checkCatchException(codeSource, code, item) else: for ti in item.data: if isinstance(ti, Stack.Item): _checkCatchException(codeSource, code, ti) _BOOL_NAMES = ('True', 'False') _BAD_ASSIGN_NAMES = _BOOL_NAMES + ('None',) def _checkBoolean(code, checks): for item in checks: try: data = string.capitalize(item.data) if item.type is Stack.TYPE_GLOBAL and data in _BOOL_NAMES: code.addWarning(msgs.BOOL_COMPARE % item.data) except (AttributeError, TypeError): # TypeError is necessary for Python 1.5.2 pass # ignore items that are not a StackItem or a string def _COMPARE_OP(oparg, operand, codeSource, code) : compareValues = _handleComparison(code.stack, operand) if oparg == OP.EXCEPT_COMPARISON: _handleExceptionChecks(codeSource, code, compareValues) elif oparg < OP.IS_COMPARISON: _checkBoolean(code, compareValues) elif cfg().isLiteral: # X is Y or X is not Y comparison second_arg = code.stack[-1].data[2] # FIXME: how should booleans be handled, need to think about it ## if second_arg.const or (second_arg.type == Stack.TYPE_GLOBAL and ## second_arg.data in ['True', 'False']): if second_arg.const and second_arg.data is not None: data = second_arg.data if second_arg.type is types.DictType: data = {} not_str = '' if oparg != OP.IS_COMPARISON: not_str = ' not' code.addWarning(msgs.IS_LITERAL % (not_str, data)) _checkNoEffect(code) def _IMPORT_NAME(oparg, operand, codeSource, code) : code.pushStack(Stack.Item(operand, types.ModuleType)) nextOp = code.nextOpInfo()[0] if not OP.IMPORT_FROM(nextOp) and not OP.IMPORT_STAR(nextOp) : _handleImport(code, operand, codeSource.module, codeSource.main, None) def _IMPORT_FROM(oparg, operand, codeSource, code) : _handleImportFrom(code, operand, codeSource.module, codeSource.main) # this is necessary for python 1.5 (see STORE_GLOBAL/NAME) if utils.pythonVersion() < utils.PYTHON_2_0 : code.popStack() if not codeSource.main : code.unusedLocals[operand] = None elif not codeSource.module.moduleLineNums.has_key(operand) : code.updateModuleLineNums(codeSource.module, operand) def _IMPORT_STAR(oparg, operand, codeSource, code) : _handleImportFrom(code, '*', codeSource.module, codeSource.main) # Python 2.3 introduced some optimizations that create problems # this is a utility for ignoring these cases def _shouldIgnoreCodeOptimizations(code, bytecodes, offset, length=None): if utils.pythonVersion() < utils.PYTHON_2_3: return 0 if length is None: length = offset - 1 try: start = code.index - offset return bytecodes == code.bytes[start:start+length] except IndexError: return 0 # In Python 2.3, a, b = 1,2 generates this code: # ... # ROT_TWO # JUMP_FORWARD 2 # DUP_TOP # POP_TOP # # which generates a Possible stmt w/no effect # ROT_TWO = 2; JUMP_FORWARD = 110; 2, 0 is the offset (2) _IGNORE_SEQ = '%c%c%c%c' % (2, 110, 2, 0) def _shouldIgnoreNoEffectWarning(code): return _shouldIgnoreCodeOptimizations(code, _IGNORE_SEQ, 5) def _DUP_TOP(oparg, operand, codeSource, code) : if len(code.stack) > 0 : code.pushStack(code.stack[-1], _shouldIgnoreNoEffectWarning(code)) def _popn(code, n) : if len(code.stack) >= 2 : loadValue = code.stack[-2] if cfg().modifyDefaultValue and loadValue.type == types.StringType : _checkModifyDefaultArg(code, loadValue.data) code.popStackItems(n) def _DELETE_SUBSCR(oparg, operand, codeSource, code) : _popn(code, 2) def _STORE_SUBSCR(oparg, operand, codeSource, code) : _popn(code, 3) def _CALL_FUNCTION(oparg, operand, codeSource, code) : _handleFunctionCall(codeSource, code, oparg) def _CALL_FUNCTION_VAR(oparg, operand, codeSource, code) : _handleFunctionCall(codeSource, code, oparg, 1, 0) def _CALL_FUNCTION_KW(oparg, operand, codeSource, code) : _handleFunctionCall(codeSource, code, oparg, 1) def _CALL_FUNCTION_VAR_KW(oparg, operand, codeSource, code) : _handleFunctionCall(codeSource, code, oparg, 2, 0) def _MAKE_FUNCTION(oparg, operand, codeSource, code) : newValue = Stack.makeFuncReturnValue(code.stack[-1], oparg) code.popStackItems(oparg+1) code.pushStack(newValue) def _MAKE_CLOSURE(oparg, operand, codeSource, code) : _MAKE_FUNCTION(max(0, oparg - 1), operand, codeSource, code) def _BUILD_MAP(oparg, operand, codeSource, code) : _makeConstant(code, oparg, Stack.makeDict) def _BUILD_TUPLE(oparg, operand, codeSource, code) : _makeConstant(code, oparg, Stack.makeTuple) def _BUILD_LIST(oparg, operand, codeSource, code) : _makeConstant(code, oparg, Stack.makeList) def _BUILD_CLASS(oparg, operand, codeSource, code) : newValue = Stack.makeFuncReturnValue(code.stack[-1], types.ClassType) code.popStackItems(3) code.pushStack(newValue) def _LIST_APPEND(oparg, operand, codeSource, code): code.popStackItems(2) def _modifyStackName(code, suffix): if code.stack: tos = code.stack[-1] tos_type = type(tos.data) if tos_type == types.StringType: tos.data = tos.data + suffix elif tos_type == types.TupleType and \ type(tos.data[-1]) == types.StringType: tos.data = tos.data[:-1] + (tos.data[-1] + suffix,) def _UNARY_CONVERT(oparg, operand, codeSource, code) : if code.stack: stackValue = code.stack[-1] if stackValue.data == cfg().methodArgName and \ stackValue.const == 0 and codeSource.classObject is not None and \ codeSource.func.function.func_name == '__repr__' : code.addWarning(msgs.USING_SELF_IN_REPR) stackValue.data = utils.safestr(stackValue.data) stackValue.type = types.StringType _modifyStackName(code, '-repr') def _UNARY_POSITIVE(oparg, operand, codeSource, code) : if OP.UNARY_POSITIVE(code.nextOpInfo()[0]) : code.addWarning(msgs.STMT_WITH_NO_EFFECT % '++') code.popNextOp() elif cfg().unaryPositive and code.stack and not code.stack[-1].const : code.addWarning(msgs.UNARY_POSITIVE_HAS_NO_EFFECT) _modifyStackName(code, '-pos') def _UNARY_NEGATIVE(oparg, operand, codeSource, code) : if OP.UNARY_NEGATIVE(code.nextOpInfo()[0]) : code.addWarning(msgs.STMT_WITH_NO_EFFECT % '--') _modifyStackName(code, '-neg') def _UNARY_NOT(oparg, operand, codeSource, code) : _modifyStackName(code, '-not') def _UNARY_INVERT(oparg, operand, codeSource, code) : if OP.UNARY_INVERT(code.nextOpInfo()[0]) : code.addWarning(msgs.STMT_WITH_NO_EFFECT % '~~') _modifyStackName(code, '-invert') def _popStackRef(code, operand, count = 2) : code.popStackItems(count) code.pushStack(Stack.Item(operand, Stack.TYPE_UNKNOWN)) def _popModifiedStack(code, suffix=' '): code.popStack() _modifyStackName(code, suffix) def _pop(oparg, operand, codeSource, code) : code.popStack() _POP_TOP = _PRINT_ITEM = _pop def _popModified(oparg, operand, codeSource, code): _popModifiedStack(code) def _BINARY_RSHIFT(oparg, operand, codeSource, code): _coerce_type(code) _popModified(oparg, operand, codeSource, code) _BINARY_LSHIFT = _BINARY_RSHIFT def _checkModifyNoOp(code, op, msg=msgs.MODIFY_VAR_NOOP, modifyStack=1): stack = code.stack if len(stack) >= 2: if (stack[-1].type != Stack.TYPE_UNKNOWN and stack[-2].type != Stack.TYPE_UNKNOWN): name = stack[-1].getName() if name != Stack.TYPE_UNKNOWN and name == stack[-2].getName(): code.addWarning(msg % (name, op, name)) if modifyStack: code.popStack() stack[-1].const = 0 _modifyStackName(code, op) def _BINARY_AND(oparg, operand, codeSource, code): _checkModifyNoOp(code, '&') _coerce_type(code) def _BINARY_OR(oparg, operand, codeSource, code): _checkModifyNoOp(code, '|') _coerce_type(code) def _BINARY_XOR(oparg, operand, codeSource, code): _checkModifyNoOp(code, '^', msgs.XOR_VAR_WITH_ITSELF) _coerce_type(code) def _PRINT_ITEM_TO(oparg, operand, codeSource, code) : code.popStackItems(2) try: ComplexType = types.ComplexType except NameError: ComplexType = types.FloatType # need some numeric type here _NUMERIC_TYPES = (types.IntType, types.FloatType, ComplexType) # FIXME: This is pathetically weak, need to handle more types def _coerce_type(code) : _checkNoEffect(code) newItem = Stack.Item('', Stack.TYPE_UNKNOWN) if len(code.stack) >= 2 : s1, s2 = code.stack[-2:] s1type = s1.getType(code.typeMap) s2type = s2.getType(code.typeMap) if s1type != s2type : if s1type in _NUMERIC_TYPES and s2type in _NUMERIC_TYPES : newType = types.FloatType if s1type == ComplexType or s2type == ComplexType: newType = ComplexType newItem.type = newType code.popStackItems(2) code.pushStack(newItem) def _BINARY_ADD(oparg, operand, codeSource, code) : stack = code.stack if len(stack) >= 2 and (stack[-1].const and stack[-2].const and stack[-1].type == stack[-2].type) : value = stack[-2].data + stack[-1].data code.popStackItems(2) code.pushStack(Stack.Item(value, type(value), 1)) else : _coerce_type(code) def _BINARY_SUBTRACT(oparg, operand, codeSource, code) : _coerce_type(code) _BINARY_POWER = _BINARY_SUBTRACT def _BINARY_SUBSCR(oparg, operand, codeSource, code) : _checkNoEffect(code) if len(code.stack) >= 2 : stack = code.stack varType = code.typeMap.get(utils.safestr(stack[-2].data), []) if types.ListType in varType and stack[-1].type == types.TupleType : code.addWarning(msgs.USING_TUPLE_ACCESS_TO_LIST % stack[-2].data) _popStackRef(code, operand) def _isint(stackItem, code) : if type(stackItem.data) == types.IntType : return 1 stackTypes = code.typeMap.get(stackItem.data, []) if len(stackTypes) != 1 : return 0 return types.IntType in stackTypes def _BINARY_DIVIDE(oparg, operand, codeSource, code) : _checkNoEffect(code) _checkModifyNoOp(code, '/', msgs.DIVIDE_VAR_BY_ITSELF, 0) if cfg().intDivide and len(code.stack) >= 2 : if _isint(code.stack[-1], code) and _isint(code.stack[-2], code) : # don't warn if we are going to convert the result to an int if not (len(code.stack) >= 3 and code.stack[-3].data == 'int' and OP.CALL_FUNCTION(code.nextOpInfo()[0])): code.addWarning(msgs.INTEGER_DIVISION % tuple(code.stack[-2:])) _popModifiedStack(code, '/') def _BINARY_TRUE_DIVIDE(oparg, operand, codeSource, code) : _checkNoEffect(code) _checkVariableOperationOnItself(code, operand, msgs.DIVIDE_VAR_BY_ITSELF) _popModifiedStack(code, '/') _BINARY_FLOOR_DIVIDE = _BINARY_TRUE_DIVIDE def _BINARY_MULTIPLY(oparg, operand, codeSource, code) : if len(code.stack) >= 2 : format = _getFormatString(code, codeSource) if format and type(code.stack[-1].data) == types.IntType : code.stack[-2].data = format * code.stack[-1].data code.popStack() else: _coerce_type(code) else: _popModifiedStack(code, '*') def _BINARY_MODULO(oparg, operand, codeSource, code) : _checkNoEffect(code) if cfg().modulo1 and code.stack and code.stack[-1].data == 1: if len(code.stack) < 2 or \ code.stack[-2].getType(code.typeMap) != types.FloatType: code.addWarning(msgs.MODULO_1) _getFormatWarnings(code, codeSource) _popModifiedStack(code, '%') if code.stack: code.stack[-1].const = 0 def _ROT_TWO(oparg, operand, codeSource, code) : if len(code.stack) >= 2 : tmp = code.stack[-2] code.stack[-2] = code.stack[-1] code.stack[-1] = tmp def _ROT_THREE(oparg, operand, codeSource, code) : """Lifts second and third stack item one position up, moves top down to position three.""" if len(code.stack) >= 3 : second = code.stack[-2] third = code.stack[-3] code.stack[-3] = code.stack[-1] code.stack[-2] = third code.stack[-1] = second def _ROT_FOUR(oparg, operand, codeSource, code) : """Lifts second, third and forth stack item one position up, moves top down to position four.""" if len(code.stack) >= 4 : second = code.stack[-2] third = code.stack[-3] fourth = code.stack[-4] code.stack[-4] = code.stack[-1] code.stack[-3] = fourth code.stack[-2] = third code.stack[-1] = second def _SETUP_EXCEPT(oparg, operand, codeSource, code) : code.has_except = 1 code.pushStack(Stack.Item(None, Stack.TYPE_EXCEPT)) code.pushStack(Stack.Item(None, Stack.TYPE_EXCEPT)) def _SETUP_FINALLY(oparg, operand, codeSource, code) : if not code.has_except : code.try_finally_first = 1 def _END_FINALLY(oparg, operand, codeSource, code) : if code.try_finally_first and code.index == (len(code.bytes) - 4) : code.starts_and_ends_with_finally = 1 def _LINE_NUM(oparg, operand, codeSource, code) : code.lastLineNum = oparg def _UNPACK_SEQUENCE(oparg, operand, codeSource, code) : code.unpackCount = oparg if code.stack: top = code.stack[-1] # if we know we have a tuple, make sure we unpack it into the # right # of variables topType = top.getType(code.typeMap) if topType in _SEQUENCE_TYPES: length = top.length # we don't know the length, maybe it's constant and we can find out if length == 0: value = code.constants.get(utils.safestr(top.data)) if type(value) in _SEQUENCE_TYPES: length = len(value) if length > 0 and length != oparg: if cfg().unpackLength: code.addWarning(msgs.WRONG_UNPACK_SIZE % (length, oparg)) elif topType not in _UNCHECKABLE_STACK_TYPES: if cfg().unpackNonSequence: code.addWarning(msgs.UNPACK_NON_SEQUENCE % (top.data, _getTypeStr(topType))) _modifyStackName(code, '-unpack') def _SLICE_1_ARG(oparg, operand, codeSource, code) : _popStackRef(code, operand) _SLICE1 = _SLICE2 = _SLICE_1_ARG def _SLICE3(oparg, operand, codeSource, code) : _popStackRef(code, operand, 3) def _check_string_iteration(code, index): try: item = code.stack[index] except IndexError: return if item.getType(code.typeMap) == types.StringType and \ cfg().stringIteration: code.addWarning(msgs.STRING_ITERATION % item.data) def _FOR_LOOP(oparg, operand, codeSource, code) : code.loops = code.loops + 1 _check_string_iteration(code, -2) _popStackRef(code, '', 2) def _GET_ITER(oparg, operand, codeSource, code) : _check_string_iteration(code, -1) def _FOR_ITER(oparg, operand, codeSource, code) : code.loops = code.loops + 1 _popStackRef(code, '', 1) def _jump(oparg, operand, codeSource, code) : if len(code.stack) > 0 : topOfStack = code.stack[-1] if topOfStack.isMethodCall(codeSource.classObject, cfg().methodArgName): name = topOfStack.data[-1] if codeSource.classObject.methods.has_key(name) : code.addWarning(msgs.USING_METHOD_AS_ATTR % name) _JUMP_ABSOLUTE = _jump def _skip_loops(bytes, i, lastLineNum, max) : extended_arg = 0 blockCount = 1 while i < max : op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg) if OP.LINE_NUM(op) : lastLineNum = oparg elif OP.FOR_LOOP(op) or OP.FOR_ITER(op) or OP.SETUP_LOOP(op) : blockCount = blockCount + 1 elif OP.POP_BLOCK(op) : blockCount = blockCount - 1 if blockCount <= 0 : break return lastLineNum, i def _is_unreachable(code, topOfStack, branch, if_false) : # Are we are checking exceptions, but we not catching all exceptions? if (topOfStack.type == Stack.TYPE_COMPARISON and topOfStack.data[1] == 'exception match' and topOfStack.data[2] is not Exception) : return 1 # do we possibly have while 1: ? if not (topOfStack.const and topOfStack.data == 1 and if_false) : return 0 # get the op just before the branch (ie, -3) op, oparg, i, extended_arg = OP.getInfo(code.bytes, branch - 3, 0) # are we are jumping to before the while 1: (LOAD_CONST, JUMP_IF_FALSE) if not (OP.JUMP_ABSOLUTE(op) and oparg == (code.index - 3*3)) : return 0 # check if we break out of the loop i = code.index lastLineNum = code.getLineNum() while i < branch : op, oparg, i, extended_arg = OP.getInfo(code.bytes, i, extended_arg) if OP.LINE_NUM(op) : lastLineNum = oparg elif OP.BREAK_LOOP(op) : return 0 elif OP.FOR_LOOP(op) or OP.FOR_ITER(op) or OP.SETUP_LOOP(op) : lastLineNum, i = _skip_loops(code.bytes, i, lastLineNum, branch) i = code.index - 3*4 op, oparg, i, extended_arg = OP.getInfo(code.bytes, i, 0) if OP.SETUP_LOOP(op) : # a little lie to pretend we have a raise after a while 1: code.removeBranch(i + oparg) code.raiseValues.append((lastLineNum, None, i + oparg)) return 1 # In Python 2.3, while/if 1: gets optimized to # ... # JUMP_FORWARD 4 # JUMP_IF_FALSE ? # POP_TOP # # which generates a Using a conditional statement with a constant value # JUMP_FORWARD = 110; 4, 0 is the offset (4) _IGNORE_BOGUS_JUMP = '%c%c%c' % (110, 4, 0) def _shouldIgnoreBogusJumps(code): return _shouldIgnoreCodeOptimizations(code, _IGNORE_BOGUS_JUMP, 6, 3) def _checkConstantCondition(code, topOfStack, if_false): # don't warn when doing (test and 'true' or 'false') # still warn when doing (test and None or 'false') if if_false or not OP.LOAD_CONST(code.nextOpInfo(1)[0]) or \ not topOfStack.data or topOfStack.type is types.NoneType: if not _shouldIgnoreBogusJumps(code): code.addWarning(msgs.CONSTANT_CONDITION % utils.safestr(topOfStack)) def _jump_conditional(oparg, operand, codeSource, code, if_false) : # FIXME: this doesn't work in 2.3+ since constant conditions # are optimized away by the compiler. if code.stack : topOfStack = code.stack[-1] if (topOfStack.const or topOfStack.type is types.NoneType) and \ cfg().constantConditions and \ (topOfStack.data != 1 or cfg().constant1): _checkConstantCondition(code, topOfStack, if_false) if _is_unreachable(code, topOfStack, code.label, if_false) : code.removeBranch(code.label) _jump(oparg, operand, codeSource, code) def _JUMP_IF_FALSE(oparg, operand, codeSource, code) : _jump_conditional(oparg, operand, codeSource, code, 1) def _JUMP_IF_TRUE(oparg, operand, codeSource, code) : _jump_conditional(oparg, operand, codeSource, code, 0) def _JUMP_FORWARD(oparg, operand, codeSource, code) : _jump(oparg, operand, codeSource, code) code.remove_unreachable_code(code.label) def _RETURN_VALUE(oparg, operand, codeSource, code) : if not codeSource.calling_code : code.addReturn() def _EXEC_STMT(oparg, operand, codeSource, code) : if cfg().usesExec : if code.stack and code.stack[-1].isNone() : code.addWarning(msgs.USES_GLOBAL_EXEC) else : code.addWarning(msgs.USES_EXEC) def _checkStrException(code, varType, item): if varType is types.StringType: code.addWarning(msgs.RAISE_STR_EXCEPTION % item.data) def _RAISE_VARARGS(oparg, operand, codeSource, code) : code.addRaise() if not cfg().badExceptions: return if oparg > 0 and len(code.stack) >= oparg: item = code.stack[-oparg] if item.type not in (Stack.TYPE_FUNC_RETURN, Stack.TYPE_UNKNOWN): if item.type is Stack.TYPE_GLOBAL: e, is_str = _getExceptionInfo(codeSource, item) if is_str: _checkStrException(code, e.type, item) elif e is not None and not _isexception(e): code.addWarning(msgs.RAISE_BAD_EXCEPTION % item.data) else: _checkStrException(code, item.getType(code.typeMap), item) DISPATCH = [ None ] * 256 DISPATCH[ 1] = _POP_TOP DISPATCH[ 2] = _ROT_TWO DISPATCH[ 3] = _ROT_THREE DISPATCH[ 4] = _DUP_TOP DISPATCH[ 5] = _ROT_FOUR DISPATCH[ 10] = _UNARY_POSITIVE DISPATCH[ 11] = _UNARY_NEGATIVE DISPATCH[ 12] = _UNARY_NOT DISPATCH[ 13] = _UNARY_CONVERT DISPATCH[ 15] = _UNARY_INVERT DISPATCH[ 18] = _LIST_APPEND DISPATCH[ 19] = _BINARY_POWER DISPATCH[ 20] = _BINARY_MULTIPLY DISPATCH[ 21] = _BINARY_DIVIDE DISPATCH[ 22] = _BINARY_MODULO DISPATCH[ 23] = _BINARY_ADD DISPATCH[ 24] = _BINARY_SUBTRACT DISPATCH[ 25] = _BINARY_SUBSCR DISPATCH[ 26] = _BINARY_FLOOR_DIVIDE DISPATCH[ 27] = _BINARY_TRUE_DIVIDE # FIXME: add INPLACE FLOOR/TRUE DIVIDE: 28/29 DISPATCH[ 31] = _SLICE1 DISPATCH[ 32] = _SLICE2 DISPATCH[ 33] = _SLICE3 DISPATCH[ 55] = _BINARY_ADD # INPLACE DISPATCH[ 56] = _BINARY_SUBTRACT # INPLACE DISPATCH[ 57] = _BINARY_MULTIPLY # INPLACE DISPATCH[ 58] = _BINARY_DIVIDE # INPLACE DISPATCH[ 59] = _BINARY_MODULO # INPLACE DISPATCH[ 60] = _STORE_SUBSCR DISPATCH[ 61] = _DELETE_SUBSCR DISPATCH[ 62] = _BINARY_LSHIFT DISPATCH[ 63] = _BINARY_RSHIFT DISPATCH[ 64] = _BINARY_AND DISPATCH[ 65] = _BINARY_XOR DISPATCH[ 66] = _BINARY_OR DISPATCH[ 67] = _BINARY_POWER # INPLACE DISPATCH[ 68] = _GET_ITER DISPATCH[ 71] = _PRINT_ITEM DISPATCH[ 73] = _PRINT_ITEM_TO DISPATCH[ 75] = _BINARY_LSHIFT # INPLACE DISPATCH[ 76] = _BINARY_RSHIFT # INPLACE DISPATCH[ 77] = _BINARY_AND # INPLACE DISPATCH[ 78] = _BINARY_XOR # INPLACE DISPATCH[ 79] = _BINARY_OR # INPLACE DISPATCH[ 83] = _RETURN_VALUE DISPATCH[ 84] = _IMPORT_STAR DISPATCH[ 85] = _EXEC_STMT DISPATCH[ 88] = _END_FINALLY DISPATCH[ 89] = _BUILD_CLASS DISPATCH[ 90] = _STORE_NAME DISPATCH[ 91] = _DELETE_NAME DISPATCH[ 92] = _UNPACK_SEQUENCE DISPATCH[ 93] = _FOR_ITER DISPATCH[ 95] = _STORE_ATTR DISPATCH[ 96] = _DELETE_ATTR DISPATCH[ 97] = _STORE_GLOBAL DISPATCH[ 98] = _DELETE_GLOBAL DISPATCH[100] = _LOAD_CONST DISPATCH[101] = _LOAD_NAME DISPATCH[102] = _BUILD_TUPLE DISPATCH[103] = _BUILD_LIST DISPATCH[104] = _BUILD_MAP DISPATCH[105] = _LOAD_ATTR DISPATCH[106] = _COMPARE_OP DISPATCH[107] = _IMPORT_NAME DISPATCH[108] = _IMPORT_FROM DISPATCH[110] = _JUMP_FORWARD DISPATCH[111] = _JUMP_IF_FALSE DISPATCH[112] = _JUMP_IF_TRUE DISPATCH[113] = _JUMP_ABSOLUTE DISPATCH[114] = _FOR_LOOP DISPATCH[116] = _LOAD_GLOBAL DISPATCH[121] = _SETUP_EXCEPT DISPATCH[122] = _SETUP_FINALLY DISPATCH[124] = _LOAD_FAST DISPATCH[125] = _STORE_FAST DISPATCH[126] = _DELETE_FAST DISPATCH[127] = _LINE_NUM DISPATCH[130] = _RAISE_VARARGS DISPATCH[131] = _CALL_FUNCTION DISPATCH[132] = _MAKE_FUNCTION DISPATCH[134] = _MAKE_CLOSURE DISPATCH[135] = _LOAD_CLOSURE DISPATCH[136] = _LOAD_DEREF DISPATCH[140] = _CALL_FUNCTION_VAR DISPATCH[141] = _CALL_FUNCTION_KW DISPATCH[142] = _CALL_FUNCTION_VAR_KW spe-0.8.4.h/_spe/plugins/pychecker/warn.py0000755000175000017500000006602511002645341017473 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2002, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Print out warnings from Python source files. """ import os.path import sys import string import types import traceback import imp import re from pychecker import OP from pychecker import Stack from pychecker import function from pychecker import python from pychecker import msgs from pychecker import utils from pychecker import CodeChecks from pychecker.Warning import Warning def cfg() : return utils.cfg() def _checkSelfArg(method, warnings) : """Return a Warning if there is no self parameter or the first parameter to a method is not self.""" if not cfg().methodArgName: return code = method.function.func_code err = None if method.isStaticMethod(): if code.co_argcount > 0 and cfg().methodArgName == code.co_varnames[0]: err = msgs.SELF_IS_ARG % 'staticmethod' elif code.co_argcount < 1: err = msgs.NO_METHOD_ARGS % cfg().methodArgName else: if method.isClassMethod(): if code.co_varnames[0] not in cfg().classmethodArgNames: err = msgs.SELF_NOT_FIRST_ARG % \ (cfg().classmethodArgNames, 'class') elif code.co_varnames[0] != cfg().methodArgName: err = msgs.SELF_NOT_FIRST_ARG % (cfg().methodArgName, '') if err is not None : warnings.append(Warning(code, code, err)) def _checkNoSelfArg(func, warnings) : "Return a Warning if there is a self parameter to a function." code = func.function.func_code if code.co_argcount > 0 and cfg().methodArgName in code.co_varnames: warnings.append(Warning(code, code, msgs.SELF_IS_ARG % 'function')) def _checkSubclass(c1, c2): try: return issubclass(c1.classObject, c2.classObject) except (TypeError, AttributeError): return 0 _IGNORE_RETURN_TYPES = ( Stack.TYPE_FUNC_RETURN, Stack.TYPE_ATTRIBUTE, Stack.TYPE_GLOBAL, Stack.TYPE_COMPARISON, Stack.TYPE_UNKNOWN) def _checkReturnWarnings(code) : is_getattr = code.func_code.co_name in ('__getattr__', '__getattribute__') if is_getattr : for line, retval, dummy in code.returnValues : if retval.isNone() : err = msgs.DONT_RETURN_NONE % code.func_code.co_name code.addWarning(err, line+1) # there must be at least 2 real return values to check for consistency returnValuesLen = len(code.returnValues) if returnValuesLen < 2 : return # if the last return is implicit, check if there are non None returns lastReturn = code.returnValues[-1] # Python 2.4 optimizes the dead implicit return out, so we can't # distinguish implicit and explicit "return None" if utils.pythonVersion() < utils.PYTHON_2_4 and \ not code.starts_and_ends_with_finally and \ cfg().checkImplicitReturns and lastReturn[1].isImplicitNone(): for line, retval, dummy in code.returnValues[:-1] : if not retval.isNone() : code.addWarning(msgs.IMPLICIT_AND_EXPLICIT_RETURNS, lastReturn[0]+1) break # __get*__ funcs can return different types, don't warn about inconsistency if utils.startswith(code.func_code.co_name, '__get') and \ utils.endswith(code.func_code.co_name, '__') : return returnType, returnData = None, None for line, value, dummy in code.returnValues : if not value.isNone() : valueType = value.getType(code.typeMap) if returnType is None and valueType not in _IGNORE_RETURN_TYPES : returnData = value returnType = valueType continue # always ignore None, None can be returned w/any other type # FIXME: if we stored func return values, we could do better if returnType is not None and not value.isNone() and \ valueType not in _IGNORE_RETURN_TYPES and \ returnData.type not in _IGNORE_RETURN_TYPES : ok = returnType in (type(value.data), valueType) if ok : if returnType == types.TupleType : # FIXME: this isn't perfect, if len == 0 # the length can really be 0 OR unknown # we shouldn't check the lengths for equality # ONLY IF one of the lengths is truly unknown if returnData.length > 0 and value.length > 0: ok = returnData.length == value.length else : ok = _checkSubclass(returnType, valueType) or \ _checkSubclass(valueType, returnType) if not ok : code.addWarning(msgs.INCONSISTENT_RETURN_TYPE, line) def _checkComplex(code, maxValue, value, func, err) : if maxValue and value > maxValue : line = func.function.func_code.co_firstlineno code.addWarning(err % (func.function.__name__, value), line) def _checkCode(code, codeSource) : while code.index < code.maxCode : op, oparg, operand = code.popNextOp() dispatch_func = CodeChecks.DISPATCH[op] if dispatch_func is not None : dispatch_func(oparg, operand, codeSource, code) def _name_unused(var) : if var in cfg().unusedNames : return 0 for name in cfg().unusedNames : if name != '_' and utils.startswith(var, name) : return 0 return 1 def _checkUnusedParam(var, line, func, code) : if line is not None and line == 0 and _name_unused(var) : if ((cfg().ignoreSelfUnused or var != cfg().methodArgName) and (cfg().varArgumentsUsed or func.varArgName() != var)) : code.addWarning(msgs.UNUSED_PARAMETER % var, code.func_code) def _handleNestedCode(func_code, code, codeSource): nested = not (codeSource.main or codeSource.in_class) if func_code.co_name == utils.LAMBDA or nested: utils.debug(' handling nested code') varnames = None if nested and func_code.co_name != utils.LAMBDA: varnames = func_code.co_varnames + \ codeSource.calling_code[-1].function.func_code.co_varnames # save the original return value and restore after checking returnValues = code.returnValues code.init(function.create_fake(func_code.co_name, func_code, {}, varnames)) _checkCode(code, codeSource) code.returnValues = returnValues def _findUnreachableCode(code) : # code after RETURN or RAISE is unreachable unless there's a branch to it unreachable = {} terminals = code.returnValues[:-1] + code.raiseValues terminals.sort(lambda a, b: cmp(a[2], b[2])) for line, dummy, i in terminals : if not code.branches.has_key(i) : unreachable[i] = line # find the index of the last return lastLine = lastItem = lastIndex = None if code.returnValues: lastLine, lastItem, lastIndex = code.returnValues[-1] if len(code.returnValues) >= 2 : lastIndex = code.returnValues[-2][2] if code.raiseValues : lastIndex = max(lastIndex, code.raiseValues[-1][2]) # remove last return if it's unreachable AND implicit if unreachable.get(lastIndex) == lastLine and lastItem and \ lastItem.isImplicitNone(): del code.returnValues[-1] del unreachable[lastIndex] if cfg().unreachableCode : for index in unreachable.keys() : try : if not OP.JUMP_FORWARD(ord(code.bytes[index])) : code.addWarning(msgs.CODE_UNREACHABLE, unreachable[index]) except IndexError : pass def _checkFunction(module, func, c = None, main = 0, in_class = 0) : "Return a list of Warnings found in a function/method." # always push a new config object, so we can pop at end of function utils.pushConfig() code = CodeChecks.Code() code.init(func) if main: for key in func.function.func_globals.keys(): code.unusedLocals[key] = -1 codeSource = CodeChecks.CodeSource(module, func, c, main, in_class, code) try : _checkCode(code, codeSource) if not in_class : _findUnreachableCode(code) # handle lambdas and nested functions codeSource.calling_code.append(func) for func_code in code.codeObjects.values() : _handleNestedCode(func_code, code, codeSource) del codeSource.calling_code[-1] except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : exc_type, exc_value, exc_tb = sys.exc_info() exc_list = traceback.format_exception(exc_type, exc_value, exc_tb) for index in range(0, len(exc_list)) : exc_list[index] = string.replace(exc_list[index], "\n", "\n\t") code.addWarning(msgs.CHECKER_BROKEN % string.join(exc_list, "")) if cfg().checkReturnValues : _checkReturnWarnings(code) if cfg().localVariablesUsed : for var, line in code.unusedLocals.items() : if line is not None and line > 0 and _name_unused(var) : code.addWarning(msgs.UNUSED_LOCAL % var, line) if cfg().argumentsUsed : op = code.getFirstOp() if not (OP.RAISE_VARARGS(op) or OP.RETURN_VALUE(op)) : for var, line in code.unusedLocals.items() : _checkUnusedParam(var, line, func, code) # Check code complexity: # loops should be counted as one branch, but there are typically 3 # branches in byte code to setup a loop, so subtract off 2/3's of them # / 2 to approximate real branches branches = (len(code.branches.keys()) - (2 * code.loops)) / 2 lines = (code.getLineNum() - code.func_code.co_firstlineno) returns = len(code.returnValues) if not main and not in_class : args = code.func_code.co_argcount locals = len(code.func_code.co_varnames) - args _checkComplex(code, cfg().maxArgs, args, func, msgs.TOO_MANY_ARGS) _checkComplex(code, cfg().maxLocals, locals, func, msgs.TOO_MANY_LOCALS) _checkComplex(code, cfg().maxLines, lines, func, msgs.FUNC_TOO_LONG) _checkComplex(code, cfg().maxReturns, returns, func, msgs.TOO_MANY_RETURNS) _checkComplex(code, cfg().maxBranches, branches, func, msgs.TOO_MANY_BRANCHES) if not (main or in_class) : utils.popConfig() func.returnValues = code.returnValues return (code.warnings, code.globalRefs, code.functionsCalled, code.codeObjects.values(), code.returnValues) def _getUnused(module, globalRefs, dict, msg, filterPrefix = None) : "Return a list of warnings for unused globals" warnings = [] for ref in dict.keys() : check = not filterPrefix or utils.startswith(ref, filterPrefix) if check and globalRefs.get(ref) == None : lineInfo = module.moduleLineNums.get(ref) if lineInfo: warnings.append(Warning(lineInfo[0], lineInfo[1], msg % ref)) return warnings def _get_func_info(method) : try: fc = getattr(method.im_func, 'func_code', None) if fc is not None : return fc.co_filename, fc.co_firstlineno except AttributeError: # if the object derives from any object in 2.2, # the builtin methods are wrapper_descriptors and # have no im_func attr pass return None, None _DOT_INIT = '.' + utils.INIT def _baseInitCalled(classInitInfo, base, functionsCalled) : baseInit = getattr(base, utils.INIT, None) if baseInit is None or _get_func_info(baseInit) == classInitInfo : return 1 initName = utils.safestr(base) + _DOT_INIT if functionsCalled.has_key(initName) : return 1 # ok, do this the hard way, there may be aliases, so check here names = string.split(initName, '.') try: # i think this can raise an exception if the module is a library (.so) obj = sys.modules[names[0]] except KeyError: return 1 for i in range(1, len(names)) : obj = getattr(obj, names[i], None) if obj is None: return 0 if functionsCalled.has_key(string.join(names[i:], '.')) : return 1 return 0 def _checkBaseClassInit(moduleFilename, c, func_code, funcInfo) : """Return a list of warnings that occur for each base class whose __init__() is not called""" warnings = [] functionsCalled, _, returnValues = funcInfo for line, stackItem, dummy in returnValues : if stackItem.data != None : if not stackItem.isNone() or cfg().returnNoneFromInit : warn = Warning(func_code, line, msgs.RETURN_FROM_INIT) warnings.append(warn) classInit = getattr(c.classObject, utils.INIT, None) if cfg().baseClassInitted and classInit is not None : classInitInfo = _get_func_info(classInit) for base in c.classObject.__bases__ : if not _baseInitCalled(classInitInfo, base, functionsCalled) : warn = Warning(moduleFilename, func_code, msgs.BASE_CLASS_NOT_INIT % utils.safestr(base)) warnings.append(warn) return warnings def _checkOverridenMethods(func, baseClasses, warnings) : for baseClass in baseClasses : if func.func_name != utils.INIT and \ not function.same_signature(func, baseClass) : err = msgs.METHOD_SIGNATURE_MISMATCH % (func.func_name, utils.safestr(baseClass)) warnings.append(Warning(func.func_code, func.func_code, err)) break def _updateFunctionWarnings(module, func, c, warnings, globalRefs, main = 0, in_class = 0) : "Update function warnings and global references" newWarnings, newGlobalRefs, funcs, codeObjects, returnValues = \ _checkFunction(module, func, c, main, in_class) warnings.extend(newWarnings) globalRefs.update(newGlobalRefs) return funcs, codeObjects, returnValues def getBlackList(moduleList) : blacklist = [] for badBoy in moduleList : if badBoy[-3:] == ".py": badBoy = badBoy[0:-3] try : file, path, flags = imp.find_module(badBoy) if file : file.close() blacklist.append(normalize_path(path)) except ImportError : pass return blacklist def getStandardLibrary() : if cfg().ignoreStandardLibrary : try : from distutils import sysconfig std_lib = sysconfig.get_python_lib() path = os.path.split(std_lib) if path[1] == 'site-packages' : std_lib = path[0] return std_lib except ImportError : return None def normalize_path(path): return os.path.normpath(os.path.normcase(path)) def removeWarnings(warnings, blacklist, std_lib, cfg): if std_lib is not None: std_lib = normalize_path(std_lib) for index in range(len(warnings)-1, -1, -1) : filename = normalize_path(warnings[index].file) if filename in blacklist or (std_lib is not None and utils.startswith(filename, std_lib)) : del warnings[index] elif cfg.only: # ignore files not specified on the cmd line if requested if os.path.abspath(filename) not in cfg.files: del warnings[index] # filter by warning/error level if requested if cfg.level and warnings[index].level < cfg.level: del warnings[index] if cfg.limit: # sort by severity first, then normal sort (by file/line) warnings.sort(lambda a, b: cmp(a.level, b.level) or cmp(a, b)) # strip duplicates lastWarning = None for index in range(len(warnings)-1, -1, -1): warning = warnings[index] # remove duplicate warnings if lastWarning is not None and cmp(lastWarning, warning) == 0: del warnings[index] else: lastWarning = warning num_ignored = len(warnings) - cfg.limit if num_ignored > 0: del warnings[:-cfg.limit] msg = msgs.TOO_MANY_WARNINGS % num_ignored warnings.append(Warning('', 0, msg)) return warnings class _SuppressionError(Exception) : pass def _updateSuppressions(suppress, warnings) : if not utils.updateCheckerArgs(suppress, 'suppressions', 0, warnings) : utils.popConfig() raise _SuppressionError _CLASS_NAME_RE = re.compile("(\\..+)?") def getSuppression(name, suppressions, warnings) : try : utils.pushConfig() # cheesy hack to deal with new-style classes. i don't see a # better way to get the name, '<' is an invalid identifier, so # we can reliably check it and extract name from: # [.identifier[.identifier]...] matches = _CLASS_NAME_RE.match(name) if matches: # pull out the names and make a complete identifier (ignore None) name = string.join(filter(None, matches.groups()), '') suppress = suppressions[0].get(name, None) if suppress is not None : _updateSuppressions(suppress, warnings) regexList = suppressions[1].keys() regexList.sort() for regex in regexList : match = regex.match(name) if match and match.group() == name : suppress = 1 _updateSuppressions(suppressions[1][regex], warnings) if not suppress : utils.popConfig() return suppress except _SuppressionError : return None def _findFunctionWarnings(module, globalRefs, warnings, suppressions) : for func in module.functions.values() : func_code = func.function.func_code utils.debug("function:", func_code) name = '%s.%s' % (module.moduleName, func.function.__name__) suppress = getSuppression(name, suppressions, warnings) if cfg().noDocFunc and func.function.__doc__ == None : err = msgs.NO_FUNC_DOC % func.function.__name__ warnings.append(Warning(module.filename(), func_code, err)) _checkNoSelfArg(func, warnings) _updateFunctionWarnings(module, func, None, warnings, globalRefs) if suppress is not None : utils.popConfig() def _getModuleFromFilename(module, filename): if module.filename() != filename: for m in module.modules.values(): if m.filename() == filename: return m return module # Create object for non-2.2 interpreters, any class object will do try: if object: pass except NameError: object = _SuppressionError # Create property for pre-2.2 interpreters try : if property: pass except NameError: property = None def _findClassWarnings(module, c, class_code, globalRefs, warnings, suppressions) : try: className = utils.safestr(c.classObject) except TypeError: # goofy __getattr__ return classSuppress = getSuppression(className, suppressions, warnings) baseClasses = c.allBaseClasses() for base in baseClasses : baseModule = utils.safestr(base) if '.' in baseModule : # make sure we handle import x.y.z packages = string.split(baseModule, '.') baseModuleDir = string.join(packages[:-1], '.') globalRefs[baseModuleDir] = baseModule # handle class variables if class_code is not None : func = function.create_fake(c.name, class_code) _updateFunctionWarnings(module, func, c, warnings, globalRefs, 0, 1) filename = module.filename() func_code = None for method in c.methods.values() : if method == None : continue func_code = method.function.func_code utils.debug("method:", func_code) try: name = utils.safestr(c.classObject) + '.' + method.function.func_name except AttributeError: # func_name may not exist continue methodSuppress = getSuppression(name, suppressions, warnings) if cfg().checkSpecialMethods: funcname = method.function.func_name if funcname[:2] == '__' == funcname[-2:] and \ funcname != '__init__': err = None argCount = python.SPECIAL_METHODS.get(funcname, -1) if argCount != -1: # if the args are None, it can be any # of args if argCount is not None: minArgs = maxArgs = argCount err = CodeChecks.getFunctionArgErr(funcname, func_code.co_argcount, minArgs, maxArgs) else: err = msgs.NOT_SPECIAL_METHOD % funcname if err is not None: warnings.append(Warning(filename, func_code, err)) if cfg().checkOverridenMethods : _checkOverridenMethods(method.function, baseClasses, warnings) if cfg().noDocFunc and method.function.__doc__ == None : err = msgs.NO_FUNC_DOC % method.function.__name__ warnings.append(Warning(filename, func_code, err)) _checkSelfArg(method, warnings) tmpModule = _getModuleFromFilename(module, func_code.co_filename) funcInfo = _updateFunctionWarnings(tmpModule, method, c, warnings, globalRefs) if func_code.co_name == utils.INIT : if utils.INIT in dir(c.classObject) : warns = _checkBaseClassInit(filename, c, func_code, funcInfo) warnings.extend(warns) elif cfg().initDefinedInSubclass : err = msgs.NO_INIT_IN_SUBCLASS % c.name warnings.append(Warning(filename, c.getFirstLine(), err)) if methodSuppress is not None : utils.popConfig() if c.memberRefs and cfg().membersUsed : memberList = c.memberRefs.keys() memberList.sort() err = msgs.UNUSED_MEMBERS % (string.join(memberList, ', '), c.name) warnings.append(Warning(filename, c.getFirstLine(), err)) try: newStyleClass = issubclass(c.classObject, object) except TypeError: # FIXME: perhaps this should warn b/c it may be a class??? newStyleClass = 0 slots = c.statics.get('__slots__') if slots is not None and cfg().slots: lineNum = c.lineNums['__slots__'] if not newStyleClass: err = msgs.USING_SLOTS_IN_CLASSIC_CLASS % c.name warnings.append(Warning(filename, lineNum, err)) elif cfg().emptySlots: try: if len(slots.data) == 0: err = msgs.EMPTY_SLOTS % c.name warnings.append(Warning(filename, lineNum, err)) except AttributeError: # happens when slots is an instance of a class w/o __len__ pass if not newStyleClass and property is not None and cfg().classicProperties: for static in c.statics.keys(): if type(getattr(c.classObject, static, None)) == property: err = msgs.USING_PROPERTIES_IN_CLASSIC_CLASS % (static, c.name) warnings.append(Warning(filename, c.lineNums[static], err)) coerceMethod = c.methods.get('__coerce__') if newStyleClass and coerceMethod: lineNum = coerceMethod.function.func_code.co_firstlineno err = msgs.USING_COERCE_IN_NEW_CLASS % c.name warnings.append(Warning(filename, lineNum, err)) gettroMethod = c.methods.get('__getattribute__') if not newStyleClass and gettroMethod: lineNum = gettroMethod.function.func_code.co_firstlineno err = msgs.USING_GETATTRIBUTE_IN_OLD_CLASS % c.name warnings.append(Warning(filename, lineNum, err)) if cfg().noDocClass and c.classObject.__doc__ == None : method = c.methods.get(utils.INIT, None) if method != None : func_code = method.function.func_code # FIXME: check to make sure this is in our file, # not a base class file??? err = msgs.NO_CLASS_DOC % c.classObject.__name__ warnings.append(Warning(filename, func_code, err)) # we have to do this here, b/c checkFunction doesn't popConfig for classes # this allows us to have __pychecker__ apply to all methods # when defined at class scope if class_code is not None : utils.popConfig() if classSuppress is not None : utils.popConfig() def find(moduleList, initialCfg, suppressions = None) : "Return a list of warnings found in the module list" if suppressions is None : suppressions = {}, {} utils.initConfig(initialCfg) warnings = [] for module in moduleList : if module.moduleName in cfg().blacklist : continue modSuppress = getSuppression(module.moduleName, suppressions, warnings) globalRefs, classCodes = {}, {} # main_code can be null if there was a syntax error if module.main_code != None : funcInfo = _updateFunctionWarnings(module, module.main_code, None, warnings, globalRefs, 1) for code in funcInfo[1] : classCodes[code.co_name] = code _findFunctionWarnings(module, globalRefs, warnings, suppressions) for c in module.classes.values() : _findClassWarnings(module, c, classCodes.get(c.name), globalRefs, warnings, suppressions) if cfg().noDocModule and \ module.module != None and module.module.__doc__ == None : warnings.append(Warning(module.filename(), 1, msgs.NO_MODULE_DOC)) if cfg().allVariablesUsed or cfg().privateVariableUsed : prefix = None if not cfg().allVariablesUsed : prefix = "_" for ignoreVar in cfg().variablesToIgnore + cfg().unusedNames : globalRefs[ignoreVar] = ignoreVar warnings.extend(_getUnused(module, globalRefs, module.variables, msgs.VAR_NOT_USED, prefix)) if cfg().importUsed : if module.moduleName != utils.INIT or cfg().packageImportUsed : # always ignore readline module, if [raw_]input() is used if globalRefs.has_key('input') or \ globalRefs.has_key('raw_input'): globalRefs['readline'] = 0 warnings.extend(_getUnused(module, globalRefs, module.modules, msgs.IMPORT_NOT_USED)) if module.main_code != None : utils.popConfig() if modSuppress is not None : utils.popConfig() std_lib = None if cfg().ignoreStandardLibrary : std_lib = getStandardLibrary() return removeWarnings(warnings, getBlackList(cfg().blacklist), std_lib, cfg()) if 0: # if you want to test w/psyco, include this import psyco psyco.bind(_checkCode) spe-0.8.4.h/_spe/plugins/pychecker/msgs.py0000755000175000017500000002124711002645341017472 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Warning Messages for PyChecker """ import UserString class WarningClass: level = 0 def __init__(self, msg): self.msg = msg def __mod__(self, args): result = UserString.UserString(self.msg % args) result.level = self.level return result def __str__(self): return self.msg class Internal(WarningClass): level = 100 class Error(WarningClass): level = 90 class Security(WarningClass): level = 90 class Warning(WarningClass): level = 70 class Unused(WarningClass): level = 50 class Deprecated(WarningClass): level = 40 class Style(WarningClass): level = 10 TOO_MANY_WARNINGS = WarningClass("%d errors suppressed, use -#/--limit to increase the number of errors displayed") CHECKER_BROKEN = Internal("INTERNAL ERROR -- STOPPED PROCESSING FUNCTION --\n\t%s") INVALID_CHECKER_ARGS = Internal("Invalid warning suppression arguments --\n\t%s") NO_MODULE_DOC = Style("No module doc string") NO_CLASS_DOC = Style("No doc string for class %s") NO_FUNC_DOC = Style("No doc string for function %s") VAR_NOT_USED = Unused("Variable (%s) not used") IMPORT_NOT_USED = Unused("Imported module (%s) not used") UNUSED_LOCAL = Unused("Local variable (%s) not used") UNUSED_PARAMETER = Unused("Parameter (%s) not used") UNUSED_MEMBERS = Unused("Members (%s) not used in class (%s)") NO_LOCAL_VAR = Unused("No local variable (%s)") VAR_USED_BEFORE_SET = Warning("Variable (%s) used before being set") REDEFINING_ATTR = Warning("Redefining attribute (%s) original line (%d)") MODULE_IMPORTED_AGAIN = Warning("Module (%s) re-imported") MODULE_MEMBER_IMPORTED_AGAIN = Warning("Module member (%s) re-imported") MODULE_MEMBER_ALSO_STAR_IMPORTED = Warning("Module member (%s) re-imported with *") MIX_IMPORT_AND_FROM_IMPORT = Warning("Using import and from ... import for (%s)") IMPORT_SELF = Warning("Module (%s) imports itself") NO_METHOD_ARGS = Error("No method arguments, should have %s as argument") SELF_NOT_FIRST_ARG = Error("%s is not first %smethod argument") SELF_IS_ARG = Error("self is argument in %s") RETURN_FROM_INIT = Error("Cannot return a value from __init__") NO_CTOR_ARGS = Error("Instantiating an object with arguments, but no constructor") GLOBAL_DEFINED_NOT_DECLARED = Warning("Global variable (%s) not defined in module scope") INVALID_GLOBAL = Error("No global (%s) found") INVALID_METHOD = Error("No method (%s) found") INVALID_CLASS_ATTR = Warning("No class attribute (%s) found") INVALID_SET_CLASS_ATTR = Warning("Setting class attribute (%s) not set in __init__") INVALID_MODULE_ATTR = Error("No module attribute (%s) found") LOCAL_SHADOWS_GLOBAL = Warning("Local variable (%s) shadows global defined on line %d") VARIABLE_SHADOWS_BUILTIN = Warning("(%s) shadows builtin") USING_METHOD_AS_ATTR = Warning("Using method (%s) as an attribute (not invoked)") OBJECT_HAS_NO_ATTR = Warning("Object (%s) has no attribute (%s)") METHOD_SIGNATURE_MISMATCH = Warning("Overridden method (%s) doesn't match signature in class (%s)") INVALID_ARG_COUNT1 = Error("Invalid arguments to (%s), got %d, expected %d") INVALID_ARG_COUNT2 = Error("Invalid arguments to (%s), got %d, expected at least %d") INVALID_ARG_COUNT3 = Error("Invalid arguments to (%s), got %d, expected between %d and %d") FUNC_DOESNT_SUPPORT_KW = Error("Function (%s) doesn't support **kwArgs") FUNC_DOESNT_SUPPORT_KW_ARG = Error("Function (%s) doesn't support **kwArgs for name (%s)") FUNC_USES_NAMED_ARGS = Warning("Function (%s) uses named arguments") BASE_CLASS_NOT_INIT = Warning("Base class (%s) __init__() not called") NO_INIT_IN_SUBCLASS = Warning("No __init__() in subclass (%s)") METHODS_NEED_OVERRIDE = Error("Methods (%s) in %s need to be overridden in a subclass") FUNC_TOO_LONG = Style("Function (%s) has too many lines (%d)") TOO_MANY_BRANCHES = Style("Function (%s) has too many branches (%d)") TOO_MANY_RETURNS = Style("Function (%s) has too many returns (%d)") TOO_MANY_ARGS = Style("Function (%s) has too many arguments (%d)") TOO_MANY_LOCALS = Style("Function (%s) has too many local variables (%d)") TOO_MANY_REFERENCES = Style('Law of Demeter violated, more than %d references for (%s)') IMPLICIT_AND_EXPLICIT_RETURNS = Warning("Function returns a value and also implicitly returns None") INCONSISTENT_RETURN_TYPE = Warning("Function return types are inconsistent") INCONSISTENT_TYPE = Warning("Variable (%s) already has types %s and set to %s") CODE_UNREACHABLE = Error("Code appears to be unreachable") CONSTANT_CONDITION = Warning("Using a conditional statement with a constant value (%s)") STRING_ITERATION = Warning("Iterating over a string (%s)") DONT_RETURN_NONE = Error("%s should not return None, raise an exception if not found") IS_LITERAL = Warning("Using is%s %s, may not always work") INVALID_FORMAT = Error("Invalid format string, problem starts near: '%s'") INVALID_FORMAT_COUNT = Error("Format string argument count (%d) doesn't match arguments (%d)") TOO_MANY_STARS_IN_FORMAT = Error("Too many *s in format flags") USING_STAR_IN_FORMAT_MAPPING = Error("Can't use * in formats when using a mapping (dictionary), near: '%s'") CANT_MIX_MAPPING_IN_FORMATS = Error("Can't mix tuple/mapping (dictionary) formats in same format string") INTEGER_DIVISION = Warning("Using integer division (%s / %s) may return integer or float") MODULO_1 = Warning("... % 1 may be constant") USING_TUPLE_ACCESS_TO_LIST = Error("Using a tuple instead of slice as list accessor for (%s)") BOOL_COMPARE = Warning("Comparisons with %s are not necessary and may not work as expected") SHOULDNT_ASSIGN_BUILTIN = Deprecated("Should not assign to %s, it is (or will be) a builtin") SHOULDNT_ASSIGN_NAME = Deprecated("Should not assign to %s, it is similar to builtin %s") SET_VAR_TO_ITSELF = Warning("Setting %s to itself has no effect") MODIFY_VAR_NOOP = Warning("%s %s %s has no effect") DIVIDE_VAR_BY_ITSELF = Warning("%s %s %s is always 1 or ZeroDivisionError") XOR_VAR_WITH_ITSELF = Warning("%s %s %s is always 0") STMT_WITH_NO_EFFECT = Error("Operator (%s) doesn't exist, statement has no effect") POSSIBLE_STMT_WITH_NO_EFFECT = Error("Statement appears to have no effect") UNARY_POSITIVE_HAS_NO_EFFECT = Error("Unary positive (+) usually has no effect") LIST_APPEND_ARGS = Error("[].append() only takes 1 argument in Python 1.6 and above for (%s)") LOCAL_DELETED = Error("(%s) cannot be used after being deleted on line %d") LOCAL_ALREADY_DELETED = Error("Local variable (%s) has already been deleted on line %d") VAR_DELETED_BEFORE_SET = Error("Variable (%s) deleted before being set") CATCH_BAD_EXCEPTION = Warning("Catching a non-Exception object (%s)") CATCH_STR_EXCEPTION = Deprecated("Catching string exceptions are deprecated (%s)") RAISE_BAD_EXCEPTION = Warning("Raising an exception on a non-Exception object (%s)") RAISE_STR_EXCEPTION = Deprecated("Raising string exceptions are deprecated (%s)") SET_EXCEPT_TO_BUILTIN = Error("Setting exception to builtin (%s), consider () around exceptions") USING_KEYWORD = Warning("Using identifier (%s) which will become a keyword in version %s") MODIFYING_DEFAULT_ARG = Warning("Modifying parameter (%s) with a default value may have unexpected consequences") USING_SELF_IN_REPR = Warning("Using `self` in __repr__ method") USING_NONE_RETURN_VALUE = Error("Using the return value from (%s) which is always None") WRONG_UNPACK_SIZE = Error("Unpacking %d values into %d variables") WRONG_UNPACK_FUNCTION = Error("Unpacking function (%s) which returns %d values into %d variables") UNPACK_NON_SEQUENCE = Error("Unpacking a non-sequence (%s) of type %s") NOT_SPECIAL_METHOD = Warning("%s is not a special method") USING_COERCE_IN_NEW_CLASS = Error("Using __coerce__ in new-style class (%s) will not work for binary operations") USING_GETATTRIBUTE_IN_OLD_CLASS = Error("Using __getattribute__ in old-style class (%s) does not work") USING_PROPERTIES_IN_CLASSIC_CLASS = Error("Using property (%s) in classic class %s may not work") USING_SLOTS_IN_CLASSIC_CLASS = Error("Using __slots__ in classic class %s has no effect, consider deriving from object") EMPTY_SLOTS = Warning("__slots__ are empty in %s") USES_EXEC = Security("Using the exec statement") USES_GLOBAL_EXEC = Security("Using the exec statement in global namespace") USES_INPUT = Security("Using input() is a security problem, consider using raw_input()") USING_DEPRECATED_MODULE = Deprecated("%s module is deprecated") USING_DEPRECATED_ATTR = Deprecated("%s is deprecated") USING_INSECURE_FUNC = Security("%s() is a security problem") USE_INSTEAD = ", consider using %s" USES_CONST_ATTR = Warning("Passing a constant string to %s, consider direct reference") BAD_STRING_FIND = Error("string.find() returns an integer, consider checking >= 0 or < 0 for not found") spe-0.8.4.h/_spe/plugins/pychecker/function.py0000755000175000017500000001220211002645341020335 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2002, MetaSlash Inc. All rights reserved. """ Object to hold information about functions. Also contain a pseudo Python function object """ import string _ARGS_ARGS_FLAG = 4 _KW_ARGS_FLAG = 8 _CO_FLAGS_MASK = _ARGS_ARGS_FLAG + _KW_ARGS_FLAG class _ReturnValues: def __init__(self): self.returnValues = None def returnsNoValue(self): returnValues = self.returnValues # if unset, we don't know if returnValues is None: return 0 # it's an empty list, that means no values if not returnValues: return 1 # make sure each value is not None for rv in returnValues: if not rv[1].isNone(): return 0 return returnValues[-1][1].isImplicitNone() class FakeCode : "This is a holder class for code objects (so we can modify them)" def __init__(self, code, varnames = None) : for attr in dir(code): try: setattr(self, attr, getattr(code, attr)) except: pass if varnames is not None: self.co_varnames = varnames class FakeFunction(_ReturnValues): "This is a holder class for turning code at module level into a function" def __init__(self, name, code, func_globals = {}, varnames = None) : _ReturnValues.__init__(self) self.func_name = self.__name__ = name self.func_doc = self.__doc__ = "ignore" self.func_code = FakeCode(code, varnames) self.func_defaults = None self.func_globals = func_globals def __str__(self): return self.func_name def __repr__(self): return '%s from %s' % (self.func_name, self.func_code.co_filename) class Function(_ReturnValues): "Class to hold all information about a function" def __init__(self, function, isMethod=0): _ReturnValues.__init__(self) self.function = function self.isMethod = isMethod self.minArgs = self.maxArgs = function.func_code.co_argcount if function.func_defaults is not None : self.minArgs = self.minArgs - len(function.func_defaults) # if function uses *args, there is no max # args try: if function.func_code.co_flags & _ARGS_ARGS_FLAG != 0 : self.maxArgs = None self.supportsKW = function.func_code.co_flags & _KW_ARGS_FLAG except AttributeError: # this happens w/Zope self.supportsKW = 0 def __str__(self): return self.function.func_name def __repr__(self): return '%s from %s:%d' % (self.function.func_name, self.function.func_code.co_filename, self.function.func_code.co_firstlineno) def arguments(self) : numArgs = self.function.func_code.co_argcount if self.maxArgs is None : numArgs = numArgs + 1 if self.supportsKW : numArgs = numArgs + 1 return self.function.func_code.co_varnames[:numArgs] def isParam(self, name) : return name in self.arguments() def isStaticMethod(self): return self.isMethod and isinstance(self.function, type(create_fake)) def isClassMethod(self): try: return self.isMethod and self.function.im_self is not None except AttributeError: return 0 def defaultValue(self, name) : func_code = self.function.func_code arg_names = list(func_code.co_varnames[:func_code.co_argcount]) i = arg_names.index(name) if i < self.minArgs : raise ValueError return self.function.func_defaults[i - self.minArgs] def varArgName(self) : if self.maxArgs is not None : return None func_code = self.function.func_code return func_code.co_varnames[func_code.co_argcount] def create_fake(name, code, func_globals = {}, varnames = None) : return Function(FakeFunction(name, code, func_globals, varnames)) def create_from_file(file, filename, module) : # Make sure the file is at the beginning # if python compiled the file, it will be at the end file.seek(0) # Read in the source file, see py_compile.compile() for games w/src str codestr = file.read() codestr = string.replace(codestr, "\r\n", "\n") codestr = string.replace(codestr, "\r", "\n") if codestr and codestr[-1] != '\n' : codestr = codestr + '\n' code = compile(codestr, filename, 'exec') return Function(FakeFunction('__main__', code, module.__dict__)) def _co_flags_equal(o1, o2) : return (o1.co_flags & _CO_FLAGS_MASK) == (o2.co_flags & _CO_FLAGS_MASK) def same_signature(func, object) : '''Return a boolean value if the has the same signature as a function with the same name in (ie, an overriden method)''' try : baseMethod = getattr(object, func.func_name) base_func_code = baseMethod.im_func.func_code except AttributeError : return 1 return _co_flags_equal(base_func_code, func.func_code) and \ base_func_code.co_argcount == func.func_code.co_argcount spe-0.8.4.h/_spe/plugins/pychecker/__init__.py0000644000175000017500000000103711002674135020253 0ustar stanistani""" Copyright (c) 2001, MetaSlash Inc. All rights reserved. PyChecker is a tool for finding common bugs in python source code. It finds problems that are typically caught by a compiler for less dynamic languages, like C and C++. It is also similar to lint. Contact Info: http://pychecker.sourceforge.net/ pychecker-list@lists.sourceforge.net """ # A version # to check against in the main module (checker.py) # this will allow us to check if there are two versions of checker # in site-packages and local dir MAIN_MODULE_VERSION = 3 spe-0.8.4.h/_spe/plugins/pychecker/checker.py0000755000175000017500000006715510576076436020157 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Check python source code files for possible errors and print warnings Contact Info: http://pychecker.sourceforge.net/ pychecker-list@lists.sourceforge.net """ import string import types import sys import imp import os import glob import traceback import re # see __init__.py for meaning, this must match the version there LOCAL_MAIN_VERSION = 3 def setupNamespace(path) : # remove pychecker if it's the first component, it needs to be last if sys.path[0][-9:] == 'pychecker' : del sys.path[0] # make sure pychecker is last in path, so we can import checker_path = os.path.dirname(os.path.dirname(path)) if checker_path not in sys.path : sys.path.append(checker_path) if __name__ == '__main__' : setupNamespace(sys.argv[0]) from pychecker import utils from pychecker import printer from pychecker import warn from pychecker import OP from pychecker import Config from pychecker import function from pychecker import msgs from pychecker.Warning import Warning # Globals for storing a dictionary of info about modules and classes _allModules = {} _cfg = None # Constants _DEFAULT_MODULE_TOKENS = ('__builtins__', '__doc__', '__file__', '__name__', '__path__') _DEFAULT_CLASS_TOKENS = ('__doc__', '__name__', '__module__') # When using introspection on objects from some C extension modules, # the interpreter will crash. Since pychecker exercises these bugs we # need to blacklist the objects and ignore them. For more info on how # to determine what object is causing the crash, search for this # comment below (ie, it is also several hundred lines down): # # README if interpreter is crashing: # FIXME: the values should indicate the versions of these modules # that are broken. We shouldn't ignore good modules. _EVIL_C_OBJECTS = { 'matplotlib.axes.BinOpType': None, # broken on versions <= 0.83.2 # broken on versions at least 2.5.5 up to 2.6 'wx.TheClipboard': None, 'wx._core.TheClipboard': None, 'wx._misc.TheClipboard': None, } _VERSION_MISMATCH_ERROR = ''' There seem to be two versions of PyChecker being used. One is probably in python/site-packages, the other in a local directory. If you want to run the local version, you must remove the version from site-packages. Or you can install the current version by doing python setup.py install. ''' def cfg() : return utils.cfg() def _flattenList(list) : "Returns a list which contains no lists" new_list = [] for element in list : if type(element) == types.ListType : new_list.extend(_flattenList(element)) else : new_list.append(element) return new_list def getModules(arg_list) : "Returns a list of module names that can be imported" new_arguments = [] for arg in arg_list : # is this a wildcard filespec? (necessary for windows) if '*' in arg or '?' in arg or '[' in arg : arg = glob.glob(arg) new_arguments.append(arg) PY_SUFFIXES = ['.py'] PY_SUFFIX_LENS = [3] if _cfg.quixote: PY_SUFFIXES.append('.ptl') PY_SUFFIX_LENS.append(4) modules = [] for arg in _flattenList(new_arguments) : # is it a .py file? for suf, suflen in zip(PY_SUFFIXES, PY_SUFFIX_LENS): if len(arg) > suflen and arg[-suflen:] == suf: arg_dir = os.path.dirname(arg) if arg_dir and not os.path.exists(arg) : print 'File or pathname element does not exist: "%s"' % arg continue module_name = os.path.basename(arg)[:-suflen] if arg_dir not in sys.path : sys.path.insert(0, arg_dir) arg = module_name modules.append(arg) return modules def _q_file(f): # crude hack!!! # imp.load_module requires a real file object, so we can't just # fiddle def lines and yield them import tempfile fd, newfname = tempfile.mkstemp(suffix=".py", text=True) newf = os.fdopen(fd, 'r+') os.unlink(newfname) for line in f: mat = re.match(r'(\s*def\s+\w+\s*)\[(html|plain)\](.*)', line) if mat is None: newf.write(line) else: newf.write(mat.group(1)+mat.group(3)+'\n') newf.seek(0) return newf def _q_find_module(p, path): if not _cfg.quixote: return imp.find_module(p, path) else: for direc in path: try: return imp.find_module(p, [direc]) except ImportError: f = os.path.join(direc, p+".ptl") if os.path.exists(f): return _q_file(file(f)), f, ('.ptl', 'U', 1) def _findModule(name) : """Returns the result of an imp.find_module(), ie, (file, filename, smt) name can be a module or a package name. It is *not* a filename.""" path = sys.path[:] packages = string.split(name, '.') for p in packages : # smt = (suffix, mode, type) file, filename, smt = _q_find_module(p, path) if smt[-1] == imp.PKG_DIRECTORY : try : # package found - read path info from init file m = imp.load_module(p, file, filename, smt) finally : if file is not None : file.close() # importing xml plays a trick, which replaces itself with _xmlplus # both have subdirs w/same name, but different modules in them # we need to choose the real (replaced) version if m.__name__ != p : try : file, filename, smt = _q_find_module(m.__name__, path) m = imp.load_module(p, file, filename, smt) finally : if file is not None : file.close() new_path = m.__path__ if type(new_path) == types.ListType : new_path = filename if new_path not in path : path.insert(1, new_path) elif smt[-1] != imp.PY_COMPILED: if p is not packages[-1] : if file is not None : file.close() raise ImportError, "No module named %s" % packages[-1] return file, filename, smt # in case we have been given a package to check return file, filename, smt class Variable : "Class to hold all information about a variable" def __init__(self, name, type): self.name = name self.type = type self.value = None def __str__(self) : return self.name __repr__ = utils.std_repr def _filterDir(object, ignoreList) : "Return a list of tokens (attributes) in a class, except for ignoreList" tokens = dir(object) for token in ignoreList : if token in tokens : tokens.remove(token) return tokens def _getClassTokens(c) : return _filterDir(c, _DEFAULT_CLASS_TOKENS) class Class : "Class to hold all information about a class" def __init__(self, name, module) : self.name = name self.classObject = getattr(module, name) modname = getattr(self.classObject, '__module__', None) if modname is None: # hm, some ExtensionClasses don't have a __module__ attribute # so try parsing the type output typerepr = repr(type(self.classObject)) mo = re.match("^$", typerepr) if mo: modname = ".".join(mo.group(1).split(".")[:-1]) self.module = sys.modules.get(modname) if not self.module: self.module = module sys.stderr.write("warning: couldn't find real module " "for class %s (module name: %s)\n" % (self.classObject, modname)) self.ignoreAttrs = 0 self.methods = {} self.members = { '__class__': types.ClassType, '__doc__': types.StringType, '__dict__': types.DictType, } self.memberRefs = {} self.statics = {} self.lineNums = {} def __str__(self) : return self.name __repr__ = utils.std_repr def getFirstLine(self) : "Return first line we can find in THIS class, not any base classes" lineNums = [] classDir = dir(self.classObject) for m in self.methods.values() : if m != None and m.function.func_code.co_name in classDir: lineNums.append(m.function.func_code.co_firstlineno) if lineNums : return min(lineNums) return 0 def allBaseClasses(self, c = None) : "Return a list of all base classes for this class and it's subclasses" baseClasses = [] if c == None : c = self.classObject for base in c.__bases__ : baseClasses = baseClasses + [ base ] + self.allBaseClasses(base) return baseClasses def __getMethodName(self, func_name, className = None) : if func_name[0:2] == '__' and func_name[-2:] != '__' : if className == None : className = self.name if className[0] != '_' : className = '_' + className func_name = className + func_name return func_name def addMethod(self, method, methodName = None) : if type(method) == types.StringType : self.methods[method] = None else : assert methodName is not None, "must supply methodName" self.methods[methodName] = function.Function(method, 1) def addMethods(self, classObject) : for classToken in _getClassTokens(classObject) : token = getattr(classObject, classToken, None) if token is None: continue # Looks like a method. Need to code it this way to # accommodate ExtensionClass and Python 2.2. Yecchh. if (hasattr(token, "func_code") and hasattr(token.func_code, "co_argcount")): self.addMethod(token, token.__name__) elif hasattr(token, '__get__') and \ not hasattr(token, '__set__') and \ type(token) is not types.ClassType : self.addMethod(getattr(token, '__name__', classToken)) else : self.members[classToken] = type(token) self.memberRefs[classToken] = None self.cleanupMemberRefs() # add standard methods for methodName in ('__class__',) : self.addMethod(methodName, classObject.__name__) def addMembers(self, classObject) : if not cfg().onlyCheckInitForMembers : for classToken in _getClassTokens(classObject) : method = getattr(classObject, classToken, None) if type(method) == types.MethodType : self.addMembersFromMethod(method.im_func) else: try: self.addMembersFromMethod(classObject.__init__.im_func) except AttributeError: pass def addMembersFromMethod(self, method) : if not hasattr(method, 'func_code') : return func_code, code, i, maxCode, extended_arg = OP.initFuncCode(method) stack = [] while i < maxCode : op, oparg, i, extended_arg = OP.getInfo(code, i, extended_arg) if op >= OP.HAVE_ARGUMENT : operand = OP.getOperand(op, func_code, oparg) if OP.LOAD_CONST(op) or OP.LOAD_FAST(op) or OP.LOAD_GLOBAL(op): stack.append(operand) elif OP.LOAD_DEREF(op): try: operand = func_code.co_cellvars[oparg] except IndexError: index = oparg - len(func_code.co_cellvars) operand = func_code.co_freevars[index] stack.append(operand) elif OP.STORE_ATTR(op) : if len(stack) > 0 : if stack[-1] == cfg().methodArgName: value = None if len(stack) > 1 : value = type(stack[-2]) self.members[operand] = value self.memberRefs[operand] = None stack = [] self.cleanupMemberRefs() def cleanupMemberRefs(self) : try : del self.memberRefs[Config.CHECKER_VAR] except KeyError : pass def abstractMethod(self, m): """Return 1 if method is abstract, None if not An abstract method always raises an exception. """ if not self.methods.get(m, None): return None func_code, bytes, i, maxCode, extended_arg = \ OP.initFuncCode(self.methods[m].function) # abstract if the first opcode is RAISE_VARARGS and it raises # NotImplementedError arg = "" while i < maxCode: op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg) if OP.LOAD_GLOBAL(op): arg = func_code.co_names[oparg] elif OP.RAISE_VARARGS(op): # if we saw NotImplementedError sometime before the raise # assume it's related to this raise stmt return arg == "NotImplementedError" if OP.conditional(op): break return None def isAbstract(self): """Return the method names that make a class abstract. An abstract class has at least one abstract method.""" result = [] for m in self.methods.keys(): if self.abstractMethod(m): result.append(m) return result def _getLineInFile(moduleName, linenum): line = '' file, filename, smt = _findModule(moduleName) try: lines = file.readlines() line = string.rstrip(lines[linenum - 1]) except (IOError, IndexError): pass file.close() return line def importError(moduleName): exc_type, exc_value, tb = sys.exc_info() # First, try to get a nice-looking name for this exception type. exc_name = getattr(exc_type, '__name__', None) if not exc_name: # either it's a string exception or a user-defined exception class # show string or fully-qualified class name exc_name = utils.safestr(exc_type) # Print a traceback, unless this is an ImportError. ImportError is # presumably the most common import-time exception, so this saves # the clutter of a traceback most of the time. Also, the locus of # the error is usually irrelevant for ImportError, so the lack of # traceback shouldn't be a problem. if exc_type is SyntaxError: # SyntaxErrors are special, we want to control how we format # the output and make it consistent for all versions of Python e = exc_value msg = '%s (%s, line %d)' % (e.msg, e.filename, e.lineno) line = _getLineInFile(moduleName, e.lineno) offset = e.offset if type(offset) is not types.IntType: offset = 0 exc_value = '%s\n %s\n %s^' % (msg, line, ' ' * offset) elif exc_type is not ImportError: sys.stderr.write(" Caught exception importing module %s:\n" % moduleName) try: tbinfo = traceback.extract_tb(tb) except: tbinfo = [] sys.stderr.write(" Unable to format traceback\n") for filename, line, func, text in tbinfo[1:]: sys.stderr.write(" File \"%s\", line %d" % (filename, line)) if func != "?": sys.stderr.write(", in %s()" % func) sys.stderr.write("\n") if text: sys.stderr.write(" %s\n" % text) # And finally print the exception type and value. # Careful formatting exc_value -- can fail for some user exceptions sys.stderr.write(" %s: " % exc_name) try: sys.stderr.write(utils.safestr(exc_value) + '\n') except: sys.stderr.write('**error formatting exception value**\n') def _getPyFile(filename): """Return the file and '.py' filename from a filename which could end with .py, .pyc, or .pyo""" if filename[-1] in 'oc' and filename[-4:-1] == '.py': return filename[:-1] return filename class PyCheckerModule : "Class to hold all information for a module" def __init__(self, moduleName, check = 1) : self.moduleName = moduleName self.variables = {} self.functions = {} self.classes = {} self.modules = {} self.moduleLineNums = {} self.attributes = [ '__dict__' ] self.main_code = None self.module = None self.check = check _allModules[moduleName] = self def __str__(self) : return self.moduleName __repr__ = utils.std_repr def addVariable(self, var, varType) : self.variables[var] = Variable(var, varType) def addFunction(self, func) : self.functions[func.__name__] = function.Function(func) def __addAttributes(self, c, classObject) : for base in classObject.__bases__ : self.__addAttributes(c, base) c.addMethods(classObject) c.addMembers(classObject) def addClass(self, name) : self.classes[name] = c = Class(name, self.module) try: objName = utils.safestr(c.classObject) except TypeError: # this can happen if there is a goofy __getattr__ c.ignoreAttrs = 1 else: packages = string.split(objName, '.') c.ignoreAttrs = packages[0] in cfg().blacklist if not c.ignoreAttrs : self.__addAttributes(c, c.classObject) def addModule(self, name) : module = _allModules.get(name, None) if module is None : self.modules[name] = module = PyCheckerModule(name, 0) if imp.is_builtin(name) == 0: module.load() else : globalModule = globals().get(name) if globalModule : module.attributes.extend(dir(globalModule)) else : self.modules[name] = module def filename(self) : try : filename = self.module.__file__ except AttributeError : filename = self.moduleName return _getPyFile(filename) def load(self): try : # there's no need to reload modules we already have module = sys.modules.get(self.moduleName) if module : if not _allModules[self.moduleName].module : return self._initModule(module) return 1 return self._initModule(self.setupMainCode()) except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : importError(self.moduleName) return 0 def initModule(self, module) : if not self.module: filename = _getPyFile(module.__file__) if string.lower(filename[-3:]) == '.py': try: file = open(filename) except IOError: pass else: self._setupMainCode(file, filename, module) return self._initModule(module) return 1 def _initModule(self, module): self.module = module self.attributes = dir(self.module) pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None : utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS) : if _EVIL_C_OBJECTS.has_key('%s.%s' % (self.moduleName, tokenName)): continue # README if interpreter is crashing: # Change 0 to 1 if the interpretter is crashing and re-run. # Follow the instructions from the last line printed. if 0: print "Add the following line to _EVIL_C_OBJECTS:\n" \ " '%s.%s': None, " % (self.moduleName, tokenName) token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType) : # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType) : self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') : self.addClass(tokenName) else : self.addVariable(tokenName, type(token)) if pychecker_attr is not None : utils.popConfig() return 1 def setupMainCode(self) : file, filename, smt = _findModule(self.moduleName) # FIXME: if the smt[-1] == imp.PKG_DIRECTORY : load __all__ module = imp.load_module(self.moduleName, file, filename, smt) self._setupMainCode(file, filename, module) return module def _setupMainCode(self, file, filename, module): try : self.main_code = function.create_from_file(file, filename, module) finally : if file != None : file.close() def getAllModules() : "Returns a list of all modules that should be checked." modules = [] for module in _allModules.values() : if module.check : modules.append(module) return modules _BUILTIN_MODULE_ATTRS = { 'sys': [ 'ps1', 'ps2', 'tracebacklimit', 'exc_type', 'exc_value', 'exc_traceback', 'last_type', 'last_value', 'last_traceback', ], } def fixupBuiltinModules(needs_init=0): for moduleName in sys.builtin_module_names : if needs_init: _ = PyCheckerModule(moduleName, 0) module = _allModules.get(moduleName, None) if module is not None : try : m = imp.init_builtin(moduleName) except ImportError : pass else : extra_attrs = _BUILTIN_MODULE_ATTRS.get(moduleName, []) module.attributes = [ '__dict__' ] + dir(m) + extra_attrs def _printWarnings(warnings, stream=None): if stream is None: stream = sys.stdout warnings.sort() lastWarning = None for warning in warnings : if lastWarning is not None: # ignore duplicate warnings if cmp(lastWarning, warning) == 0: continue # print blank line between files if lastWarning.file != warning.file: stream.write("\n") lastWarning = warning warning.output(stream) def processFiles(files, cfg = None, pre_process_cb = None) : # insert this here, so we find files in the local dir before std library if sys.path[0] != '' : sys.path.insert(0, '') # ensure we have a config object, it's necessary global _cfg if cfg is not None : _cfg = cfg elif _cfg is None : _cfg = Config.Config() warnings = [] utils.initConfig(_cfg) for moduleName in getModules(files) : if callable(pre_process_cb) : pre_process_cb(moduleName) module = PyCheckerModule(moduleName) if not module.load() : w = Warning(module.filename(), 1, msgs.Internal("NOT PROCESSED UNABLE TO IMPORT")) warnings.append(w) utils.popConfig() return warnings def getWarnings(files, cfg = None, suppressions = None): warnings = processFiles(files, cfg) fixupBuiltinModules() return warnings + warn.find(getAllModules(), _cfg, suppressions) def _print_processing(name) : if not _cfg.quiet : sys.stderr.write("Processing %s...\n" % name) def main(argv) : __pychecker__ = 'no-miximport' import pychecker if LOCAL_MAIN_VERSION != pychecker.MAIN_MODULE_VERSION : sys.stderr.write(_VERSION_MISMATCH_ERROR) sys.exit(100) # remove empty arguments argv = filter(None, argv) # if the first arg starts with an @, read options from the file # after the @ (this is mostly for windows) if len(argv) >= 2 and argv[1][0] == '@': # read data from the file command_file = argv[1][1:] try: f = open(command_file, 'r') command_line = f.read() f.close() except IOError, err: sys.stderr.write("Unable to read commands from file: %s\n %s\n" % \ (command_file, err)) sys.exit(101) # convert to an argv list, keeping argv[0] and the files to process argv = argv[:1] + string.split(command_line) + argv[2:] global _cfg _cfg, files, suppressions = Config.setupFromArgs(argv[1:]) if not files : return 0 # Now that we've got the args, update the list of evil C objects for evil_doer in _cfg.evil: _EVIL_C_OBJECTS[evil_doer] = None # insert this here, so we find files in the local dir before std library sys.path.insert(0, '') importWarnings = processFiles(files, _cfg, _print_processing) fixupBuiltinModules() if _cfg.printParse : for module in getAllModules() : printer.module(module) warnings = warn.find(getAllModules(), _cfg, suppressions) if not _cfg.quiet : print "\nWarnings...\n" if warnings or importWarnings : _printWarnings(importWarnings + warnings) return 1 if not _cfg.quiet : print "None" return 0 if __name__ == '__main__' : try : sys.exit(main(sys.argv)) except Config.UsageError : sys.exit(127) else : _orig__import__ = None _suppressions = None _warnings_cache = {} def _get_unique_warnings(warnings): for i in range(len(warnings)-1, -1, -1): w = warnings[i].format() if _warnings_cache.has_key(w): del warnings[i] else: _warnings_cache[w] = 1 return warnings def __import__(name, globals=None, locals=None, fromlist=None): if globals is None: globals = {} if locals is None: locals = {} if fromlist is None: fromlist = [] check = not sys.modules.has_key(name) and name[:10] != 'pychecker.' pymodule = _orig__import__(name, globals, locals, fromlist) if check : try : module = PyCheckerModule(pymodule.__name__) if module.initModule(pymodule): warnings = warn.find([module], _cfg, _suppressions) _printWarnings(_get_unique_warnings(warnings)) else : print 'Unable to load module', pymodule.__name__ except Exception: name = getattr(pymodule, '__name__', utils.safestr(pymodule)) importError(name) return pymodule def _init() : global _cfg, _suppressions, _orig__import__ args = string.split(os.environ.get('PYCHECKER', '')) _cfg, files, _suppressions = Config.setupFromArgs(args) utils.initConfig(_cfg) fixupBuiltinModules(1) # keep the orig __import__ around so we can call it import __builtin__ _orig__import__ = __builtin__.__import__ __builtin__.__import__ = __import__ if not os.environ.get('PYCHECKER_DISABLED') : _init() spe-0.8.4.h/_spe/plugins/pychecker/OptionTypes.py0000644000175000017500000000655311002666475021031 0ustar stanistaniimport Tkinter def bool(value): if value: return 1 return 0 class Base: "Base class for all OptionTypes" def __init__(self, name, default): self._name = name self._default = default self._var = None def name(self): return self._name def set(self, value): self._var.set(value) class Boolean(Base): "A option type for editing boolean values" def __init__(self, name, default): Base.__init__(self, name, default) def field(self, w): self._var = Tkinter.BooleanVar() if self._default: self._var.set(1) else: self._var.set(0) frame = Tkinter.Frame(w, name = self._name + "Frame") result = Tkinter.Checkbutton(frame, name=self._name, text=self._name, variable=self._var) result.grid(sticky=Tkinter.W) frame.columnconfigure(0, weight=1) return frame def arg(self): if bool(self._var.get()) != bool(self._default): if bool(self._var.get()): return "--" + self._name return "--no-" + self._name return None class Number(Base): "OptionType for editing numbers" def __init__(self, name, default): Base.__init__(self, name, default) def field(self, w): self._var = Tkinter.IntVar() self._var.set(self._default) frame = Tkinter.Frame(w, name = self._name + "Frame") label = Tkinter.Label(frame, text=self._name + ":") label.grid(row=0, column=0, sticky=Tkinter.W) entry = Tkinter.Entry(frame, name=self._name, textvariable=self._var, width=4) entry.grid(row=0, column=1, sticky=Tkinter.E) for i in range(2): frame.columnconfigure(i, weight=1) return frame def arg(self): if self._var.get() != self._default: return "--%s=%d" % (self._name, self._var.get()) return None class Text(Base): "OptionType for editing a little bit of text" def __init__(self, name, default): Base.__init__(self, name, default) def width(self): return int(min(15, len(self._default) * 1.20)) def field(self, w): self._var = Tkinter.StringVar() self._var.set(self._default) frame = Tkinter.Frame(w, name = self._name + "Frame") label = Tkinter.Label(frame, text=self._name + ":") label.grid(row=0, column=0, sticky=Tkinter.W) entry = Tkinter.Entry(frame, name=self._name, textvariable=self._var, width=self.width()) entry.grid(row=0, column=1, sticky=Tkinter.E) for i in range(2): frame.columnconfigure(i, weight=1) return frame def arg(self): if self._var.get() != self._default: return "--%s=%s" % (self._name, self._var.get()) return None def join(list): import string return string.join(list, ", ") class List(Text): "OptionType for editing a list of values" def __init__(self, name, default): Text.__init__(self, name, join(default)) def set(self, value): self._var.set(join(value)) spe-0.8.4.h/_spe/plugins/pychecker/options.py0000644000175000017500000002116311002666475020221 0ustar stanistani"Main module for running pychecker a Tkinter GUI for all the options" import sys import os import Tkinter, tkFileDialog from OptionTypes import * from string import capitalize, strip, rstrip, split import Config MAX_SUBBOX_ROWS = 8 MAX_BOX_COLS = 3 PAD = 10 EDITOR = "xterm -e vi -n +%(line)d %(file)s" if sys.platform == 'win32': EDITOR = "notepad %(file)s" def col_weight(grid): "Set column weights so that sticky grid settings actually work" unused, col = grid.grid_size() for c in range(col): grid.columnconfigure(c, weight=1) def spawn(cmd_list): try: if os.fork(): try: os.execvp(cmd_list[0], cmd_list) finally: sys.exit() except AttributeError: os.execvp(cmd_list[0], cmd_list) def edit(file, line): "Fire up an external editor to see the file at the given line" unused = file, line list = split(EDITOR) cmd_list = [] for word in list: cmd_list.append(word % locals()) spawn(cmd_list) def closeCB(): sys.exit(0) class Results: "Display the warnings produced by checker" def __init__(self, w): self.top = Tkinter.Toplevel(w, name="results") self.top.transient(w) self.top.bind('', self.hide) self.top.bind('', self.hide) self.text = Tkinter.Text(self.top, name="text") self.text.grid() self.text.bind('', self.showFile) close = Tkinter.Button(self.top, name="close", default=Tkinter.ACTIVE, command=self.hide) close.grid() self.text.update_idletasks() def show(self, text): self.text.delete("0.1", "end") self.text.insert("0.1", text) self.top.deiconify() self.top.lift() def hide(self, *unused): self.top.withdraw() def line(self): return split(self.text.index(Tkinter.CURRENT), ".")[0] def showFile(self, unused): import re line = self.line() text = self.text.get(line + ".0", line + ".end") text = rstrip(text) result = re.search("(.*):([0-9]+):", text) if result: file, line = result.groups() edit(file, int(line)) self.text.after(0, self.selectLine) def selectLine(self): line = self.line() self.text.tag_remove(Tkinter.SEL, "1.0", Tkinter.END) self.text.tag_add(Tkinter.SEL, line + ".0", line + ".end") class ConfigDialog: "Dialog for editing options" def __init__(self, tk): self._tk = tk self._cfg, _, _ = Config.setupFromArgs(sys.argv) self._help = None self._optMap = {} self._opts = [] self._file = Tkinter.StringVar() self._results = None if len(sys.argv) > 1: self._file.set(sys.argv[1]) for name, group in Config._OPTIONS: opts = [] for _, useValue, longArg, member, description in group: value = None if member: value = getattr(self._cfg, member) description = member + ": " + capitalize(description) description = strip(description) tk.option_add('*' + longArg + ".help", description) if useValue: if type(value) == type([]): field = List(longArg, value) elif type(value) == type(1): field = Number(longArg, int(value)) elif type(value) == type(''): field = Text(longArg, value) else: field = Boolean(longArg, value) else: field = Boolean(longArg, value) self._optMap[longArg] = field opts.append(field) self._opts.append( (name, opts)) def _add_fields(self, w, opts): count = 0 for opt in opts: f = opt.field(w) c, r = divmod(count, MAX_SUBBOX_ROWS) f.grid(row=r, column=c, sticky=Tkinter.NSEW) count = count + 1 def _add_group(self, w, name, opts): colFrame = Tkinter.Frame(w) label = Tkinter.Label(colFrame, text=name + ":") label.grid(row=0, column=0, sticky=Tkinter.NSEW) gframe = Tkinter.Frame(colFrame, relief=Tkinter.GROOVE, borderwidth=2) gframe.grid(row=1, column=0, sticky=Tkinter.NSEW) self._add_fields(gframe, opts) label = Tkinter.Label(colFrame) label.grid(row=2, column=0, sticky=Tkinter.NSEW) colFrame.rowconfigure(2, weight=1) return colFrame def main(self): frame = Tkinter.Frame(self._tk, name="opts") frame.grid() self._tk.option_readfile('Options.ad') self._fields = {} row, col = 0, 0 rowFrame = Tkinter.Frame(frame) rowFrame.grid(row=row) row = row + 1 for name, opts in self._opts: w = self._add_group(rowFrame, name, opts) w.grid(row=row, column=col, sticky=Tkinter.NSEW, padx=PAD) col = col + 1 if col >= MAX_BOX_COLS: col_weight(rowFrame) rowFrame=Tkinter.Frame(frame) rowFrame.grid(row=row, sticky=Tkinter.NSEW) col = 0 row = row + 1 col_weight(rowFrame) self._help = Tkinter.Label(self._tk, name="helpBox") self._help.grid(row=row) self._help.config(takefocus=0) buttons = Tkinter.Frame(self._tk, name="buttons") ok = Tkinter.Button(buttons, name="ok", command=self.ok, default=Tkinter.ACTIVE) ok.grid(row=row, column=0) default = Tkinter.Button(buttons, name="default", command=self.default) default.grid(row=row, column=1) close = Tkinter.Button(buttons, name="close", command=closeCB) close.grid(row=row, column=2) buttons.grid() f = Tkinter.Frame(self._tk, name="fileStuff") Tkinter.Button(f, name="getfile", command=self.file).grid(row=0, column=1) fileEntry = Tkinter.Entry(f, name="fname", textvariable=self._file) fileEntry.grid(row=0, column=2) Tkinter.Button(f, name="check", command=self.check).grid(row=0, column=3) f.grid(sticky=Tkinter.EW) self._tk.bind_all('', self.focus) self._tk.bind_all('', self.focus) self._tk.bind_all('', self.click) fileEntry.bind('', self.check) self._tk.mainloop() # # Callbacks # def help(self, w): if type(w) == type(''): # occurs with file dialog... return if self._help == w: # ignore help events on help... return help = w.option_get("help", "help") self._help.configure(text=help) def focus(self, ev): self.help(ev.widget) def click(self, ev): self.help(ev.widget) def ok(self): opts = [] # Pull command-line args for _, group in self._opts: for opt in group: arg = opt.arg() if arg: opts.append(arg) # Calculate config self._cfg, _, _ = Config.setupFromArgs(opts) # Set controls based on new config for _, group in Config._OPTIONS: for _, _, longArg, member, _ in group: if member: self._optMap[longArg].set(getattr(self._cfg, member)) def default(self): self._cfg, _, _ = Config.setupFromArgs(sys.argv) for _, group in Config._OPTIONS: for _, _, longArg, member, _ in group: if member: self._optMap[longArg].set(getattr(self._cfg, member)) else: self._optMap[longArg].set(0) def file(self): self._file.set(tkFileDialog.askopenfilename()) def check(self, *unused): import checker import StringIO self.ok() # show effect of all settings checker._allModules = {} warnings = checker.getWarnings([self._file.get()], self._cfg) capture = StringIO.StringIO() if not self._results: self._results = Results(self._help) checker._printWarnings(warnings, capture) value = strip(capture.getvalue()) if not value: value = "None" self._results.show(value) if __name__=='__main__': dirs = os.path.join(os.path.split(os.getcwd())[:-1]) sys.path.append(dirs[0]) tk = Tkinter.Tk() tk.title('PyChecker') ConfigDialog(tk).main() spe-0.8.4.h/_spe/plugins/pychecker/printer.py0000755000175000017500000000274711002645341020210 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001, MetaSlash Inc. All rights reserved. "Helper functions for printing out info about objects" from pychecker import utils def printFunction(spaces, prefix, func, className = None) : params = '' argcount = func.func_code.co_argcount defaultArgStart = argcount if func.func_defaults != None : defaultArgStart = argcount - len(func.func_defaults) for i in range(0, argcount) : arg = func.func_code.co_varnames[i] if i >= defaultArgStart : arg = arg + " = %s" % utils.safestr(func.func_defaults[i - defaultArgStart]) params = params + "%s, " % arg params = "(%s)" % params[:-2] if className == None : className = "" else : className = className + "." print "%s%s%s%s%s" % (spaces, prefix, className, func.func_name, params) def module(module) : print "Module: ", module.moduleName if module.module == None : return print " Imports: ", module.modules.keys() print " Variables:", module.variables.keys() print "" for function in module.functions.values() : printFunction(" ", "Function: ", function.function) print "" for c in module.classes.values() : for method in c.methods.values() : if method != None : printFunction(" ", "", method.function, c.name) print "" def attrs(object) : for attr in dir(object) : print " %s: %s" % (attr, `getattr(object, attr)`) spe-0.8.4.h/_spe/plugins/pychecker/Warning.py0000755000175000017500000000263511002645341020126 0ustar stanistani#!/usr/bin/env python # Copyright (c) 2001, MetaSlash Inc. All rights reserved. # Portions Copyright (c) 2005, Google, Inc. All rights reserved. """ Warning class to hold info about each warning. """ class Warning : "Class which holds error information." def __init__(self, file, line, err) : if hasattr(file, "function") : file = file.function.func_code.co_filename elif hasattr(file, "co_filename") : file = file.co_filename elif hasattr(line, "co_filename") : file = line.co_filename if file[:2] == './' : file = file[2:] self.file = file if hasattr(line, "co_firstlineno") : line = line.co_firstlineno if line == None : line = 1 self.line = line self.err = err self.level = err.level def __cmp__(self, warn) : if warn == None : return 1 if not self.file and not self.line: return 1 if self.file != warn.file : return cmp(self.file, warn.file) if self.line != warn.line : return cmp(self.line, warn.line) return cmp(self.err, warn.err) def format(self) : if not self.file and not self.line: return str(self.err) return "%s:%d: %s" % (self.file, self.line, self.err) def output(self, stream) : stream.write(self.format() + "\n") spe-0.8.4.h/_spe/plugins/XRCed/CHANGES.txt0000644000175000017500000002201210763311540016740 0ustar stanistani0.1.8-6 ------- Various fixes and improvements to get look-and-feel similar across different platforms. 0.1.8-5 ------- Preferences for default "sizeritem" parameters for new panels and controls can be configured ("File">"Preferences..."). Implemented comment object for including simple one-line comments and comment directives as tree nodes. No validation is performed for a valid XML string so comments must not contain "-->". Comment directive is a special comment starting with '%' character, followed by a line of python code. It is executed using 'exec' when the resource file is opened. This is useful to import plugin modules containing custom handlers which are specific to the resource file, hovewer this is of course a security hole if you use foreign XRC files. A warning is displayed if the preference option 'ask' is selected (by default). Added support for custom controls and plugin modules. Refer to this wxPythonWiki for the details: http://wiki.wxpython.org/index.cgi/XRCed#custom Tool panel sections can be collapsed/expanded by clicking on the label of a tool group. Some undo/redo and other fixes. 0.1.8-4 ------- Fixes for wxMSW (notebook highlighting, control sizes, tree Unselect). 0.1.8-3 ------- Notebook page highlighting fix. Highlight resizes when the window is resized. ParamUnit spin button detects event handler re-entry (wxGTK probably has a bug in wxSpinButton with repeated events). 0.1.8-2 ------- Fix for dealing with empty 'growable' property, using MiniFrame for properties panel, the panel is restored together with the main window. 0.1.8-1 ------- Fixed SetItemBold and editing 'growable' properties of wxFlexGridSizer. 0.1.8-0 ------- New feature added from a patch submitted on sourceforge by botg: moving of tree items. Bugs fixed: - ChecklistBox content editing; - Window styles more in sync with the docs; - Replacing items; - Reference property page created correctly (every property is optional). 0.1.7-5 ------- Fix for non-ascii characters support when using other encodings than utf-8 in 'content' property. Tested under unicode build. 0.1.7-4 ------- Second fix for Copy/Paste (using expat.native_encoding property). Added cellpos,cellspan properties for Spacer in GridBag sizer. 0.1.7-3 ------- Fix for Copy/Paste objects with international characters. 0.1.7-2 ------- Fixed Cut command, added support for MenuBar inside Frame/Dialog. 0.1.7-1 ------- Important update of Paste command code which was passing too much data thru clipboard using cPickle. Objects created while unpickling (from minidom) were clogging memory. Now using toxml() (why didn't I do it before - was I drunk or what? :) ). 0.1.7-0 ------- Added new controls (Choicebook, Listbook, StatusBar, DatePicker), and completed style flags. Test window is opened for an available parent control if no specific view defined. Better handling of exceptions (highlighting does not 'stick' anymore). Tested on wxGTK 2.6.1.0. 0.1.6-7 ------- Using system clipboard for Copy/Paste. 0.1.6-6 ------- Improved some dialogs (window styles, growable cols). Changed the range for wxSpinCtrl min/max to all integers (default 0/100 is not always good). 0.1.6-5 ------- Fixed testing for any element inside object tree. 0.1.6-4 ------- Fixed replacing op for sizer children and spacer objects. UndoReplace is not yet implemented. 0.1.6-3 ------- Fix for crash when opening new file with active tree selection. Replacing controls bug fixed. 0.1.6-2 ------- wxMSW wxTreeCtrl behaviour is still different from wxGTK for wxTR_MULTIPLE, some fixes for this. 0.1.6-1 ------- New (experimental ;) ) feature: support for "object_ref" tag, for creating references to named objects (see tn0014.txt). "reference..." menu command creates new object_ref node. Properties of the top-level object can be overriden, but overriding child controls is not working as expected (maybe a bug in wx). 0.1.5-3 ------- xxxStdDialogButtonSizer pulldown menu with standard buttons. Some fixes for selecting tools inside toolbar with test window open (whole toolbar is selected). Toolbars can be added inside windows. 0.1.5-2 ------- Using wx.GetDefaultPyEncoding/wx.SetDefaultPyEncoding for changing active encoding. Fixed pasting siblings (Ctrl key pressed while pasting). Dealed with ascii build (Python does not recognize 'ascii' as valid encoding). If encoding is not specified it is not written in XRC. Will add more customization in the future. Changed to use SimpleTool instead or Toggle tool (does not work on Win32). 0.1.5-1 ------- Added wxWizard, wxWizardPageSimple (only from pull-down menu). Hide command for test window. Replacing classes works better. Added Locate tool. 0.1.4-1 ------- Edit->Locate command (Ctrl-L) for quick selection of items. Works with event-handling controls (buttons, text fields) but not with labels/sizers. Some improvements: relative paths for files supplied as command- line argument work correctly, notebook panels are highlighted better. 0.1.2-1 _______ Added support for wxGridBagSizer (supported in wxPython 2.5). 0.1.1-5 ------- Added subclass attribute. 0.1.1-4 ------- Fixed problems with wxStaticBitmap (stock_id attribute, icon type switching). Changed some dimensions in properties panel elements. 0.1.1-3 ------- Sizes of some controls were not normal on wxMSW. Fixed. Some changes to test window code to make it resize better and to have focus control with sawfish for all types of windows. 0.1.1-2 ------- Bugs with currentEncoding and frame testing fixed. Some required parameters are set to default if missing. Unsupported classes are tolerated, with warning message. wxScrolledWindow added (to 'control' pulldown menu, not yet to the tool palette). Multi-line editing for labels and some values (wxTextCtrl, wxHtmlWindow). 0.1.1-1 ------- Changed internationalization support. '-i' option removed, default encoding is used (should be defined in sitecustomize.py, or 'ascii' by default). When XRC file is opened with encoding specified, translations are not used. 0.1.1 ----- Replace command added (not quite finished yet). 0.1.0 ----- Finally implemented tools panel for almost all controls (except wxHtmlWindow, wxCalendarCtrl and wxGenericDirCtrl - they are too rarely used). Changed some sizes in panel to better work with different fonts. Fixed double-refreshing after Ctrl+R. Maybe something else that I've forgot. It's been a looong day... :) 0.0.9-6 ------- Added dialog unit support. Dealing with non-specified required values (set to defaults, if exist). Added 'minsize' parameter of sizeritem. Added '-i' option to turn off translations and use international characters. 0.0.9-5 ------- Mac platform-specific checks. 0.0.9-4 ------- Implemented standard bitmap selection. Fixed a bug in FlexGridSizer code. 0.0.9-3 ------- File browsing (for bitmaps/icons, etc.) had a small problem when current file was not saved yet. 0.0.9-2 ------- Small bug fix for initial don't panic message. 0.0.9-1 ------- Changed program structure, reduced use of global variables (grouped in module 'globals', which creates an instanse 'g' of class Globals. First version of undo/redo working! Support for toolbars inside panels and frames. Added 'container' submenu for creating Panel, Notebook and ToolBar objects. wxMSW-only: added code to switch focus back to main window when test window is updated. 0.0.8-2 ------- Fixed unicode problem for unicode build. 0.0.8-1 ------- Using WX_2_4_BRANCH. Added new controls: wxSpinCtrl, wxGenericDirCtrl, unknown (custom control), improved wxXRC format suppor (menu styles, etc.). Some I18N support: parsing "encoding" attribute in XML header, later it can be modified in "properties" panel for "XML tree". UNIX note: currently XML writing for non-ascii chars works only if sys.getdefaultencoding() returns good value. To do this, one has to put following lines to "sitecustomize.py" file: # Start code segment import sys sys.setdefaultencoding('iso-8859-1') # or whatever # End code segment 0.0.7 ----- Some command-line arguments. "Test window" command and toolbar button. New panel interphace (wxHTMLWindow is not used anymore). Toggling between embedded and detached panel. Cache for already used windows. Current top-level control is bold, if test window shown. Undo/redo broken. CheckListBox does not work unless wxXRC source fixed (in both wxPytnon and wxWin): contrib/src/xrc/xmlrsall.cpp 45,46c45,46 < AddHandler(new wxListCtrlXmlHandler); < #if CHECKLISTBOX --- > AddHandler(new wxListCtrlXmlHandler); > #if wxUSE_CHECKLISTBOX This is fixed in CVS. 0.0.6 ----- Toolbar, bitmap, icon support (no display yet). Changed parameter objects, added support for multiple parameters (like `growablecols'). Fixed double-clicking problem with tree control on Windows. Some performance improovements. 0.0.5 ----- Added notebook with properties page and style page. Fixed some problems on Windows. 0.0.4 ----- Some fixes suggested by RD 0.0.3 ----- Faster preview window refresh. Cut/Paste works better. Some tree icons. Tree item names. Bugfixes. 0.0.2 ----- The first release. spe-0.8.4.h/_spe/plugins/XRCed/globals.py0000644000175000017500000000475210763311540017137 0ustar stanistani# Name: globals.py # Purpose: XRC editor, global variables # Author: Roman Rolinsky # Created: 02.12.2002 # RCS-ID: $Id: globals.py,v 1.35 2007/04/26 19:51:14 ROL Exp $ import wx import wx.xrc as xrc try: import wx.wizard except: pass import sys # Global constants progname = 'XRCed' version = '0.1.8-5' # Minimal wxWidgets version MinWxVersion = (2,6,0) if wx.VERSION[:3] < MinWxVersion: print '''\ ******************************* WARNING ************************************** This version of XRCed may not work correctly on your version of wxWidgets. Please upgrade wxWidgets to %d.%d.%d or higher. ******************************************************************************''' % MinWxVersion # Can be changed to set other default encoding different #defaultEncoding = '' # you comment above and can uncomment this: defaultEncoding = wx.GetDefaultPyEncoding() try: True except NameError: True = 1==1 False = 1==0 # Global variables class Globals: panel = None tree = None frame = None tools = None undoMan = None testWin = None testWinPos = wx.DefaultPosition currentXXX = None currentEncoding = defaultEncoding conf = None def _makeFonts(self): self._sysFont = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT) self._labelFont = wx.Font(self._sysFont.GetPointSize(), wx.DEFAULT, wx.NORMAL, wx.BOLD) self._modernFont = wx.Font(self._sysFont.GetPointSize(), wx.MODERN, wx.NORMAL, wx.NORMAL) self._smallerFont = wx.Font(self._sysFont.GetPointSize()-2, wx.DEFAULT, wx.NORMAL, wx.NORMAL) def sysFont(self): if not hasattr(self, "_sysFont"): self._makeFonts() return self._sysFont def labelFont(self): if not hasattr(self, "_labelFont"): self._makeFonts() return self._labelFont def modernFont(self): if not hasattr(self, "_modernFont"): self._makeFonts() return self._modernFont def smallerFont(self): if not hasattr(self, "_smallerFont"): self._makeFonts() return self._smallerFont g = Globals() class MyDataObject(wx.PyDataObjectSimple): def __init__(self): wx.PyDataObjectSimple.__init__(self, wx.CustomDataFormat('XRCed_DND')) self.data = '' def GetDataSize(self): return len(self.data) def GetDataHere(self): return self.data # returns a string def SetData(self, data): self.data = data return True spe-0.8.4.h/_spe/plugins/XRCed/xrced.ico0000644000175000017500000000427610763311540016744 0ustar stanistani ( @UUUrrr999rrUU99                                                                                      spe-0.8.4.h/_spe/plugins/XRCed/xrced.py0000644000175000017500000022736010763311540016623 0ustar stanistani# Name: xrced.py # Purpose: XRC editor, main module # Author: Roman Rolinsky # Created: 20.08.2001 # RCS-ID: $Id: xrced.py,v 1.74 2007/05/14 12:24:44 ROL Exp $ """ xrced -- Simple resource editor for XRC format used by wxWidgets/wxPython GUI toolkit. Usage: xrced [ -h ] [ -v ] [ XRC-file ] Options: -h output short usage info and exit -v output version info and exit """ from globals import * import os, sys, getopt, re, traceback, tempfile, shutil, cPickle from xml.parsers import expat # Local modules from tree import * # imports xxx which imports params from panel import * from tools import * from params import genericStyles # Cleanup recursive import sideeffects, otherwise we can't create undoMan import undo undo.ParamPage = ParamPage undoMan = g.undoMan = UndoManager() # Set application path for loading resources if __name__ == '__main__': basePath = os.path.dirname(sys.argv[0]) else: basePath = os.path.dirname(__file__) # Remember system path sys_path = sys.path # 1 adds CMD command to Help menu debug = 0 g.helpText = """\

Welcome to XRCed

DON'T PANIC :)

Read this note before clicking on anything!

To start select tree root, then popup menu with your right mouse button, select "Append Child", and then any command.

Or just press one of the buttons on the tools palette.

Enter XML ID, change properties, create children.

To test your interface select Test command (View menu).

Consult README.txt file for the details. """ defaultIDs = {xxxPanel:'PANEL', xxxDialog:'DIALOG', xxxFrame:'FRAME', xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR', xxxWizard:'WIZARD', xxxBitmap:'BITMAP', xxxIcon:'ICON'} defaultName = 'UNTITLED.xrc' ################################################################################ # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font class ScrolledMessageDialog(wx.Dialog): def __init__(self, parent, msg, caption, pos = wx.DefaultPosition, size = (500,300)): from wx.lib.layoutf import Layoutf wx.Dialog.__init__(self, parent, -1, caption, pos, size) text = wx.TextCtrl(self, -1, msg, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE | wx.TE_READONLY) text.SetFont(g.modernFont()) dc = wx.WindowDC(text) w, h = dc.GetFullTextExtent(' ', g.modernFont())[:2] ok = wx.Button(self, wx.ID_OK, "OK") ok.SetDefault() text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok))) text.SetSize((w * 80 + 30, h * 40)) text.ShowPosition(1) # scroll to the first line ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!35', (self,))) self.SetAutoLayout(True) self.Fit() self.CenterOnScreen(wx.BOTH) ################################################################################ # Event handler for using during location class Locator(wx.EvtHandler): def ProcessEvent(self, evt): print evt class TaskBarIcon(wx.TaskBarIcon): def __init__(self, frame): wx.TaskBarIcon.__init__(self) self.frame = frame # Set the image self.SetIcon(images.getIconIcon(), "XRCed") # ArtProvider for toolbar icons class ToolArtProvider(wx.ArtProvider): def __init__(self): wx.ArtProvider.__init__(self) self.images = { 'ART_LOCATE': images.getLocateImage(), 'ART_TEST': images.getTestImage(), 'ART_REFRESH': images.getRefreshImage(), 'ART_AUTO_REFRESH': images.getAutoRefreshImage(), 'ART_MOVEUP': images.getMoveUpImage(), 'ART_MOVEDOWN': images.getMoveDownImage(), 'ART_MOVELEFT': images.getMoveLeftImage(), 'ART_MOVERIGHT': images.getMoveRightImage() } if wx.Platform in ['__WXMAC__', '__WXMSW__']: self.images.update({ wx.ART_NORMAL_FILE: images.getNewImage(), wx.ART_FILE_OPEN: images.getOpenImage(), wx.ART_FILE_SAVE: images.getSaveImage(), wx.ART_UNDO: images.getUndoImage(), wx.ART_REDO: images.getRedoImage(), wx.ART_CUT: images.getCutImage(), wx.ART_COPY: images.getCopyImage(), wx.ART_PASTE: images.getPasteImage() }) def CreateBitmap(self, id, client, size): bmp = wx.NullBitmap if id in self.images: img = self.images[id] # Alpha not implemented completely there if wx.Platform in ['__WXMAC__', '__WXMSW__']: img.ConvertAlphaToMask() bmp = wx.BitmapFromImage(img) return bmp class Frame(wx.Frame): def __init__(self, pos, size): wx.Frame.__init__(self, None, -1, '', pos, size) global frame frame = g.frame = self bar = self.CreateStatusBar(2) bar.SetStatusWidths([-1, 40]) self.SetIcon(images.getIconIcon()) try: self.tbicon = TaskBarIcon(self) except: self.tbicon = None # Idle flag self.inIdle = False # Load our own resources self.res = xrc.EmptyXmlResource() # !!! Blocking of assert failure occurring in older unicode builds try: quietlog = wx.LogNull() self.res.Load(os.path.join(basePath, 'xrced.xrc')) except wx._core.PyAssertionError: print 'PyAssertionError was ignored' # Make menus menuBar = wx.MenuBar() menu = wx.Menu() menu.Append(wx.ID_NEW, '&New\tCtrl-N', 'New file') menu.AppendSeparator() menu.Append(wx.ID_OPEN, '&Open...\tCtrl-O', 'Open XRC file') self.recentMenu = wx.Menu() g.fileHistory.UseMenu(self.recentMenu) g.fileHistory.AddFilesToMenu() self.Bind(wx.EVT_MENU, self.OnRecentFile, id=wx.ID_FILE1, id2=wx.ID_FILE9) menu.AppendMenu(-1, 'Open &Recent', self.recentMenu, 'Open a recent file') menu.AppendSeparator() menu.Append(wx.ID_SAVE, '&Save\tCtrl-S', 'Save XRC file') menu.Append(wx.ID_SAVEAS, 'Save &As...', 'Save XRC file under different name') self.ID_GENERATE_PYTHON = wx.NewId() menu.Append(self.ID_GENERATE_PYTHON, '&Generate Python...', 'Generate a Python module that uses this XRC') menu.AppendSeparator() self.ID_PREFS = wx.NewId() menu.Append(self.ID_PREFS, 'Preferences...', 'Change XRCed settings') menu.AppendSeparator() menu.Append(wx.ID_EXIT, '&Quit\tCtrl-Q', 'Exit application') menuBar.Append(menu, '&File') menu = wx.Menu() menu.Append(wx.ID_UNDO, '&Undo\tCtrl-Z', 'Undo') menu.Append(wx.ID_REDO, '&Redo\tCtrl-Y', 'Redo') menu.AppendSeparator() menu.Append(wx.ID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard') menu.Append(wx.ID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard') menu.Append(wx.ID_PASTE, '&Paste\tCtrl-V', 'Paste from the clipboard') self.ID_DELETE = wx.NewId() menu.Append(self.ID_DELETE, '&Delete\tCtrl-D', 'Delete object') menu.AppendSeparator() self.ID_LOCATE = wx.NewId() self.ID_TOOL_LOCATE = wx.NewId() self.ART_LOCATE = 'ART_LOCATE' self.ID_TOOL_PASTE = wx.NewId() menu.Append(self.ID_LOCATE, '&Locate\tCtrl-L', 'Locate control in test window and select it') menuBar.Append(menu, '&Edit') menu = wx.Menu() self.ID_EMBED_PANEL = wx.NewId() menu.Append(self.ID_EMBED_PANEL, '&Embed Panel', 'Toggle embedding properties panel in the main window', True) menu.Check(self.ID_EMBED_PANEL, conf.embedPanel) self.ID_SHOW_TOOLS = wx.NewId() menu.Append(self.ID_SHOW_TOOLS, 'Show &Tools', 'Toggle tools', True) menu.Check(self.ID_SHOW_TOOLS, conf.showTools) menu.AppendSeparator() self.ID_TEST = wx.NewId() self.ART_TEST = 'ART_TEST' menu.Append(self.ID_TEST, '&Test\tF5', 'Show test window') self.ID_REFRESH = wx.NewId() self.ART_REFRESH = 'ART_REFRESH' menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh test window') self.ID_AUTO_REFRESH = wx.NewId() self.ART_AUTO_REFRESH = 'ART_AUTO_REFRESH' menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tAlt-A', 'Toggle auto-refresh mode', True) menu.Check(self.ID_AUTO_REFRESH, conf.autoRefresh) self.ID_TEST_HIDE = wx.NewId() menu.Append(self.ID_TEST_HIDE, '&Hide\tF6', 'Close test window') menuBar.Append(menu, '&View') menu = wx.Menu() self.ID_MOVEUP = wx.NewId() self.ART_MOVEUP = 'ART_MOVEUP' menu.Append(self.ID_MOVEUP, '&Up', 'Move before previous sibling') self.ID_MOVEDOWN = wx.NewId() self.ART_MOVEDOWN = 'ART_MOVEDOWN' menu.Append(self.ID_MOVEDOWN, '&Down', 'Move after next sibling') self.ID_MOVELEFT = wx.NewId() self.ART_MOVELEFT = 'ART_MOVELEFT' menu.Append(self.ID_MOVELEFT, '&Make sibling', 'Make sibling of parent') self.ID_MOVERIGHT = wx.NewId() self.ART_MOVERIGHT = 'ART_MOVERIGHT' menu.Append(self.ID_MOVERIGHT, '&Make child', 'Make child of previous sibling') menuBar.Append(menu, '&Move') menu = wx.Menu() menu.Append(wx.ID_ABOUT, '&About...', 'About XCRed') self.ID_README = wx.NewId() menu.Append(self.ID_README, '&Readme...\tF1', 'View the README file') if debug: self.ID_DEBUG_CMD = wx.NewId() menu.Append(self.ID_DEBUG_CMD, 'CMD', 'Python command line') wx.EVT_MENU(self, self.ID_DEBUG_CMD, self.OnDebugCMD) menuBar.Append(menu, '&Help') self.menuBar = menuBar self.SetMenuBar(menuBar) # Create toolbar tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) if wx.Platform != '__WXMAC__': # Redefine AddSeparator on wxGTK and wxMSW to add vertical line def _AddSeparator(): tb.AddControl(wx.StaticLine(tb, -1, size=(-1,23), style=wx.LI_VERTICAL)) tb.AddSeparator = _AddSeparator # Use tango icons and slightly wider bitmap size on Mac if wx.Platform in ['__WXMAC__', '__WXMSW__']: tb.SetToolBitmapSize((26,26)) else: tb.SetToolBitmapSize((24,24)) new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR) open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR) save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR) undo_bmp = wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR) redo_bmp = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR) cut_bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR) copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR) paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR) tb.AddSimpleTool(wx.ID_NEW, new_bmp, 'New', 'New file') tb.AddSimpleTool(wx.ID_OPEN, open_bmp, 'Open', 'Open file') tb.AddSimpleTool(wx.ID_SAVE, save_bmp, 'Save', 'Save file') tb.AddSeparator() tb.AddSimpleTool(wx.ID_UNDO, undo_bmp, 'Undo', 'Undo') tb.AddSimpleTool(wx.ID_REDO, redo_bmp, 'Redo', 'Redo') tb.AddSeparator() tb.AddSimpleTool(wx.ID_CUT, cut_bmp, 'Cut', 'Cut') tb.AddSimpleTool(wx.ID_COPY, copy_bmp, 'Copy', 'Copy') tb.AddSimpleTool(self.ID_TOOL_PASTE, paste_bmp, 'Paste', 'Paste') tb.AddSeparator() bmp = wx.ArtProvider.GetBitmap(self.ART_LOCATE, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_TOOL_LOCATE, bmp, 'Locate', 'Locate control in test window and select it', True) bmp = wx.ArtProvider.GetBitmap(self.ART_TEST, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_TEST, bmp, 'Test', 'Test window') bmp = wx.ArtProvider.GetBitmap(self.ART_REFRESH, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_REFRESH, bmp, 'Refresh', 'Refresh view') bmp = wx.ArtProvider.GetBitmap(self.ART_AUTO_REFRESH, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_AUTO_REFRESH, bmp, 'Auto-refresh', 'Toggle auto-refresh mode', True) tb.AddSeparator() bmp = wx.ArtProvider.GetBitmap(self.ART_MOVEUP, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_MOVEUP, bmp, 'Up', 'Move before previous sibling') bmp = wx.ArtProvider.GetBitmap(self.ART_MOVEDOWN, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_MOVEDOWN, bmp, 'Down', 'Move after next sibling') bmp = wx.ArtProvider.GetBitmap(self.ART_MOVELEFT, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_MOVELEFT, bmp, 'Make Sibling', 'Make sibling of parent') bmp = wx.ArtProvider.GetBitmap(self.ART_MOVERIGHT, wx.ART_TOOLBAR) tb.AddSimpleTool(self.ID_MOVERIGHT, bmp, 'Make Child', 'Make child of previous sibling') tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh) tb.Realize() self.tb = tb self.minWidth = tb.GetSize()[0] # minimal width is the size of toolbar # File wx.EVT_MENU(self, wx.ID_NEW, self.OnNew) wx.EVT_MENU(self, wx.ID_OPEN, self.OnOpen) wx.EVT_MENU(self, wx.ID_SAVE, self.OnSaveOrSaveAs) wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnSaveOrSaveAs) wx.EVT_MENU(self, self.ID_GENERATE_PYTHON, self.OnGeneratePython) wx.EVT_MENU(self, self.ID_PREFS, self.OnPrefs) wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit) # Edit wx.EVT_MENU(self, wx.ID_UNDO, self.OnUndo) wx.EVT_MENU(self, wx.ID_REDO, self.OnRedo) wx.EVT_MENU(self, wx.ID_CUT, self.OnCutDelete) wx.EVT_MENU(self, wx.ID_COPY, self.OnCopy) wx.EVT_MENU(self, wx.ID_PASTE, self.OnPaste) wx.EVT_MENU(self, self.ID_TOOL_PASTE, self.OnPaste) wx.EVT_MENU(self, self.ID_DELETE, self.OnCutDelete) wx.EVT_MENU(self, self.ID_LOCATE, self.OnLocate) wx.EVT_MENU(self, self.ID_TOOL_LOCATE, self.OnLocate) # View wx.EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel) wx.EVT_MENU(self, self.ID_SHOW_TOOLS, self.OnShowTools) wx.EVT_MENU(self, self.ID_TEST, self.OnTest) wx.EVT_MENU(self, self.ID_REFRESH, self.OnRefresh) wx.EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh) wx.EVT_MENU(self, self.ID_TEST_HIDE, self.OnTestHide) # Move wx.EVT_MENU(self, self.ID_MOVEUP, self.OnMoveUp) wx.EVT_MENU(self, self.ID_MOVEDOWN, self.OnMoveDown) wx.EVT_MENU(self, self.ID_MOVELEFT, self.OnMoveLeft) wx.EVT_MENU(self, self.ID_MOVERIGHT, self.OnMoveRight) # Help wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout) wx.EVT_MENU(self, self.ID_README, self.OnReadme) # Update events wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, wx.ID_CUT, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, wx.ID_COPY, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, wx.ID_PASTE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_LOCATE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_TOOL_LOCATE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_TOOL_PASTE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_MOVEUP, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_MOVEDOWN, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_MOVELEFT, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_MOVERIGHT, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI) # Build interface sizer = wx.BoxSizer(wx.VERTICAL) #sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) # Horizontal sizer for toolbar and splitter self.toolsSizer = sizer1 = wx.BoxSizer() splitter = wx.SplitterWindow(self, -1, style=wx.SP_3DSASH) self.splitter = splitter splitter.SetMinimumPaneSize(100) # Create tree global tree g.tree = tree = XML_Tree(splitter, -1) # Init pull-down menu data global pullDownMenu g.pullDownMenu = pullDownMenu = PullDownMenu(self) # Vertical toolbar for GUI buttons g.tools = tools = Tools(self) tools.Show(conf.showTools) if conf.showTools: sizer1.Add(tools, 0, wx.EXPAND) tree.RegisterKeyEvents() # Miniframe for split mode miniFrame = wx.MiniFrame(self, -1, 'Properties & Style', (conf.panelX, conf.panelY), (conf.panelWidth, conf.panelHeight)) self.miniFrame = miniFrame sizer2 = wx.BoxSizer() miniFrame.SetSizer(sizer2) # Create panel for parameters global panel if conf.embedPanel: panel = Panel(splitter) # Set plitter windows splitter.SplitVertically(tree, panel, conf.sashPos) else: panel = Panel(miniFrame) sizer2.Add(panel, 1, wx.EXPAND) miniFrame.Show(True) splitter.Initialize(tree) if wx.Platform == '__WXMAC__': sizer1.Add(splitter, 1, wx.EXPAND|wx.RIGHT, 5) else: sizer1.Add(splitter, 1, wx.EXPAND) sizer.Add(sizer1, 1, wx.EXPAND) self.SetAutoLayout(True) self.SetSizer(sizer) # Other events wx.EVT_IDLE(self, self.OnIdle) wx.EVT_CLOSE(self, self.OnCloseWindow) wx.EVT_KEY_DOWN(self, tools.OnKeyDown) wx.EVT_KEY_UP(self, tools.OnKeyUp) wx.EVT_ICONIZE(self, self.OnIconize) def OnRecentFile(self,evt): # open recently used file if not self.AskSave(): return wx.BeginBusyCursor() # get the pathname based on the menu ID fileNum = evt.GetId() - wx.ID_FILE1 path = g.fileHistory.GetHistoryFile(fileNum) if self.Open(path): self.SetStatusText('Data loaded') # add it back to the history so it will be moved up the list self.SaveRecent(path) else: self.SetStatusText('Failed') wx.EndBusyCursor() def OnNew(self, evt): if not self.AskSave(): return self.Clear() def OnOpen(self, evt): if not self.AskSave(): return dlg = wx.FileDialog(self, 'Open', os.path.dirname(self.dataFile), '', '*.xrc', wx.OPEN | wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.SetStatusText('Loading...') wx.BeginBusyCursor() try: if self.Open(path): self.SetStatusText('Data loaded') self.SaveRecent(path) else: self.SetStatusText('Failed') finally: wx.EndBusyCursor() dlg.Destroy() def OnSaveOrSaveAs(self, evt): if evt.GetId() == wx.ID_SAVEAS or not self.dataFile: if self.dataFile: name = '' else: name = defaultName dirname = os.path.abspath(os.path.dirname(self.dataFile)) dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.xrc', wx.SAVE | wx.OVERWRITE_PROMPT | wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() if isinstance(path, unicode): path = path.encode(sys.getfilesystemencoding()) dlg.Destroy() else: dlg.Destroy() return if conf.localconf: # if we already have a localconf then it needs to be # copied to a new config with the new name lc = conf.localconf nc = self.CreateLocalConf(path) flag, key, idx = lc.GetFirstEntry() while flag: nc.Write(key, lc.Read(key)) flag, key, idx = lc.GetNextEntry(idx) conf.localconf = nc else: # otherwise create a new one conf.localconf = self.CreateLocalConf(path) else: path = self.dataFile self.SetStatusText('Saving...') wx.BeginBusyCursor() try: try: tmpFile,tmpName = tempfile.mkstemp(prefix='xrced-') os.close(tmpFile) self.Save(tmpName) # save temporary file first shutil.move(tmpName, path) self.dataFile = path self.SetModified(False) if conf.localconf.ReadBool("autogenerate", False): pypath = conf.localconf.Read("filename") embed = conf.localconf.ReadBool("embedResource", False) genGettext = conf.localconf.ReadBool("genGettext", False) self.GeneratePython(self.dataFile, pypath, embed, genGettext) self.SetStatusText('Data saved') self.SaveRecent(path) except IOError: self.SetStatusText('Failed') finally: wx.EndBusyCursor() def SaveRecent(self,path): # append to recently used files g.fileHistory.AddFileToHistory(path) def GeneratePython(self, dataFile, pypath, embed, genGettext): try: import wx.tools.pywxrc rescomp = wx.tools.pywxrc.XmlResourceCompiler() rescomp.MakePythonModule([dataFile], pypath, embed, genGettext) except: inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error generating python code : %s' % pypath) raise def OnGeneratePython(self, evt): if self.modified or not conf.localconf: wx.MessageBox("Save the XRC file first!", "Error") return dlg = PythonOptions(self, conf.localconf, self.dataFile) dlg.ShowModal() dlg.Destroy() def OnPrefs(self, evt): dlg = PrefsDialog(self) if dlg.ShowModal() == wx.ID_OK: # Fetch new preferences for id,cdp in dlg.checkControls.items(): c,d,p = cdp if dlg.FindWindowById(id).IsChecked(): d[p] = str(c.GetValue()) elif p in d: del d[p] g.conf.allowExec = ('ask', 'yes', 'no')[dlg.radio_allow_exec.GetSelection()] dlg.Destroy() def OnExit(self, evt): self.Close() def OnUndo(self, evt): # Extra check to not mess with idle updating if undoMan.CanUndo(): undoMan.Undo() g.panel.SetModified(False) if not undoMan.CanUndo(): self.SetModified(False) def OnRedo(self, evt): if undoMan.CanRedo(): undoMan.Redo() self.SetModified(True) def OnCopy(self, evt): selected = tree.selection if not selected: return # key pressed event xxx = tree.GetPyData(selected) if wx.TheClipboard.Open(): if xxx.isElement: data = wx.CustomDataObject('XRCED') # Set encoding in header # (False,True) s = xxx.node.toxml(encoding=expat.native_encoding) else: data = wx.CustomDataObject('XRCED_node') s = xxx.node.data data.SetData(cPickle.dumps(s)) wx.TheClipboard.SetData(data) wx.TheClipboard.Close() self.SetStatusText('Copied') else: wx.MessageBox("Unable to open the clipboard", "Error") def OnPaste(self, evt): selected = tree.selection if not selected: return # key pressed event # For pasting with Ctrl pressed appendChild = True if evt.GetId() == pullDownMenu.ID_PASTE_SIBLING: appendChild = False elif evt.GetId() == self.ID_TOOL_PASTE: if g.tree.ctrl: appendChild = False else: appendChild = not tree.NeedInsert(selected) else: appendChild = not tree.NeedInsert(selected) xxx = tree.GetPyData(selected) if not appendChild: # If has next item, insert, else append to parent nextItem = tree.GetNextSibling(selected) parentLeaf = tree.GetItemParent(selected) # Expanded container (must have children) elif tree.IsExpanded(selected) and tree.GetChildrenCount(selected, False): # Insert as first child nextItem = tree.GetFirstChild(selected)[0] parentLeaf = selected else: # No children or unexpanded item - appendChild stays True nextItem = wx.TreeItemId() # no next item parentLeaf = selected parent = tree.GetPyData(parentLeaf).treeObject() # Create a copy of clipboard pickled element success = success_node = False if wx.TheClipboard.Open(): try: data = wx.CustomDataObject('XRCED') if wx.TheClipboard.IsSupported(data.GetFormat()): try: success = wx.TheClipboard.GetData(data) except: # there is a problem if XRCED_node is in clipboard # but previous SetData was for XRCED pass if not success: # try other format data = wx.CustomDataObject('XRCED_node') if wx.TheClipboard.IsSupported(data.GetFormat()): success_node = wx.TheClipboard.GetData(data) finally: wx.TheClipboard.Close() if not success and not success_node: wx.MessageBox( "There is no data in the clipboard in the required format", "Error") return xml = cPickle.loads(data.GetData()) # xml representation of element if success: elem = minidom.parseString(xml).childNodes[0] else: elem = g.tree.dom.createComment(xml) # Tempopary xxx object to test things xxx = MakeXXXFromDOM(parent, elem) # Check compatibility if not self.ItemsAreCompatible(parent, xxx.treeObject()): return # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. isChildContainer = isinstance(xxx, xxxChildContainer) parentIsBook = parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook] if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (parentIsBook and not isinstance(xxx, xxxPage)) or \ not (parent.isSizer or parentIsBook)): elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False # Parent is sizer or notebook, child is not child container if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): # Create sizer item element sizerItemElem = MakeEmptyDOM(parent.itemTag) sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook) and not isChildContainer: pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxChoicebook) and not isChildContainer: pageElem = MakeEmptyDOM('choicebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxListbook) and not isChildContainer: pageElem = MakeEmptyDOM('listbookpage') pageElem.appendChild(elem) elem = pageElem # Insert new node, register undo newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem) undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) # Scroll to show new item (!!! redundant?) tree.EnsureVisible(newItem) tree.SelectItem(newItem) if not tree.IsVisible(newItem): tree.ScrollTo(newItem) tree.Refresh() # Update view? if g.testWin and tree.IsHighlatable(newItem): if conf.autoRefresh: tree.needUpdate = True tree.pendingHighLight = newItem else: tree.pendingHighLight = None self.SetModified() self.SetStatusText('Pasted') def ItemsAreCompatible(self, parent, child): # Check compatibility error = False # Comments are always compatible if child.__class__ == xxxComment: return True # Top-level if child.__class__ in [xxxDialog, xxxFrame, xxxWizard]: # Top-level classes if parent.__class__ != xxxMainNode: error = True elif child.__class__ == xxxMenuBar: # Menubar can be put in frame or dialog if parent.__class__ not in [xxxMainNode, xxxFrame, xxxDialog]: error = True elif child.__class__ == xxxToolBar: # Toolbar can be top-level of child of panel or frame if parent.__class__ not in [xxxMainNode, xxxPanel, xxxFrame] and \ not parent.isSizer: error = True elif not parent.hasChildren: error = True elif child.__class__ == xxxPanel and parent.__class__ == xxxMainNode: pass elif child.__class__ == xxxSpacer: if not parent.isSizer: error = True elif child.__class__ == xxxSeparator: if not parent.__class__ in [xxxMenu, xxxToolBar]: error = True elif child.__class__ == xxxTool: if parent.__class__ != xxxToolBar: error = True elif child.__class__ == xxxMenu: if not parent.__class__ in [xxxMainNode, xxxMenuBar, xxxMenu]: error = True elif child.__class__ == xxxMenuItem: if not parent.__class__ in [xxxMenuBar, xxxMenu]: error = True elif child.isSizer and parent.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]: error = True else: # normal controls can be almost anywhere if parent.__class__ == xxxMainNode or \ parent.__class__ in [xxxMenuBar, xxxMenu]: error = True if error: if parent.__class__ == xxxMainNode: parentClass = 'root' else: parentClass = parent.className wx.LogError('Incompatible parent/child: parent is %s, child is %s!' % (parentClass, child.className)) return False return True def OnMoveUp(self, evt): selected = tree.selection if not selected: return index = tree.ItemIndex(selected) if index == 0: return # No previous sibling found # Remove highlight, update testWin if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() tree.needUpdate = True # Undo info self.lastOp = 'MOVEUP' status = 'Moved before previous sibling' # Prepare undo data panel.Apply() tree.UnselectAll() parent = tree.GetItemParent(selected) elem = tree.RemoveLeaf(selected) nextItem = tree.GetFirstChild(parent)[0] for i in range(index - 1): nextItem = tree.GetNextSibling(nextItem) selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem) newIndex = tree.ItemIndex(selected) tree.SelectItem(selected) undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex)) self.modified = True self.SetStatusText(status) return def OnMoveDown(self, evt): selected = tree.selection if not selected: return index = tree.ItemIndex(selected) next = tree.GetNextSibling(selected) if not next: return # Remove highlight, update testWin if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() tree.needUpdate = True # Undo info self.lastOp = 'MOVEDOWN' status = 'Moved after next sibling' # Prepare undo data panel.Apply() tree.UnselectAll() parent = tree.GetItemParent(selected) elem = tree.RemoveLeaf(selected) nextItem = tree.GetFirstChild(parent)[0] for i in range(index + 1): nextItem = tree.GetNextSibling(nextItem) selected = tree.InsertNode(parent, tree.GetPyData(parent).treeObject(), elem, nextItem) newIndex = tree.ItemIndex(selected) tree.SelectItem(selected) undoMan.RegisterUndo(UndoMove(parent, index, parent, newIndex)) self.modified = True self.SetStatusText(status) return def OnMoveLeft(self, evt): selected = tree.selection if not selected: return oldParent = tree.GetItemParent(selected) if not oldParent: return pparent = tree.GetItemParent(oldParent) if not pparent: return # Check compatibility if not self.ItemsAreCompatible(tree.GetPyData(pparent).treeObject(), tree.GetPyData(selected).treeObject()): return if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() tree.needUpdate = True # Undo info self.lastOp = 'MOVELEFT' status = 'Made next sibling of parent' # Prepare undo data panel.Apply() tree.UnselectAll() oldIndex = tree.ItemIndex(selected) elem = tree.RemoveLeaf(selected) nextItem = tree.GetFirstChild(pparent)[0] parentIndex = tree.ItemIndex(oldParent) for i in range(parentIndex + 1): nextItem = tree.GetNextSibling(nextItem) # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. parent = tree.GetPyData(pparent).treeObject() xxx = MakeXXXFromDOM(parent, elem) isChildContainer = isinstance(xxx, xxxChildContainer) if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False # Parent is sizer or notebook, child is not child container if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): # Create sizer item element sizerItemElem = MakeEmptyDOM('sizeritem') sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook) and not isChildContainer: pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem selected = tree.InsertNode(pparent, tree.GetPyData(pparent).treeObject(), elem, nextItem) newIndex = tree.ItemIndex(selected) tree.SelectItem(selected) undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, pparent, newIndex)) self.modified = True self.SetStatusText(status) def OnMoveRight(self, evt): selected = tree.selection if not selected: return oldParent = tree.GetItemParent(selected) if not oldParent: return newParent = tree.GetPrevSibling(selected) if not newParent: return parent = tree.GetPyData(newParent).treeObject() # Check compatibility if not self.ItemsAreCompatible(parent, tree.GetPyData(selected).treeObject()): return # Remove highlight, update testWin if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() tree.needUpdate = True # Prepare undo data panel.Apply() tree.UnselectAll() # Undo info self.lastOp = 'MOVERIGHT' status = 'Made last child of previous sibling' oldIndex = tree.ItemIndex(selected) elem = tree.RemoveLeaf(selected) # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. xxx = MakeXXXFromDOM(parent, elem) isChildContainer = isinstance(xxx, xxxChildContainer) if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False # Parent is sizer or notebook, child is not child container if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): # Create sizer item element sizerItemElem = MakeEmptyDOM('sizeritem') sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook) and not isChildContainer: pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem selected = tree.InsertNode(newParent, tree.GetPyData(newParent).treeObject(), elem, wx.TreeItemId()) newIndex = tree.ItemIndex(selected) tree.Expand(selected) tree.SelectItem(selected) undoMan.RegisterUndo(UndoMove(oldParent, oldIndex, newParent, newIndex)) self.modified = True self.SetStatusText(status) def OnCutDelete(self, evt): selected = tree.selection if not selected: return # key pressed event # Undo info if evt.GetId() == wx.ID_CUT: self.lastOp = 'CUT' status = 'Removed to clipboard' else: self.lastOp = 'DELETE' status = 'Deleted' # Delete testWin? if g.testWin: # If deleting top-level item, delete testWin if selected == g.testWin.item: g.testWin.Destroy() g.testWin = None else: # Remove highlight, update testWin if g.testWin.highLight: g.testWin.highLight.Remove() tree.needUpdate = True # Prepare undo data panel.Apply() index = tree.ItemFullIndex(selected) xxx = tree.GetPyData(selected) parent = tree.GetPyData(tree.GetItemParent(selected)).treeObject() tree.UnselectAll() elem = tree.RemoveLeaf(selected) undoMan.RegisterUndo(UndoCutDelete(index, parent, elem)) if evt.GetId() == wx.ID_CUT: if wx.TheClipboard.Open(): if xxx.isElement: data = wx.CustomDataObject('XRCED') # (False, True) s = elem.toxml(encoding=expat.native_encoding) else: data = wx.CustomDataObject('XRCED_node') s = xxx.node.data data.SetData(cPickle.dumps(s)) wx.TheClipboard.SetData(data) wx.TheClipboard.Close() else: wx.MessageBox("Unable to open the clipboard", "Error") tree.pendingHighLight = None # Update tools panel.Clear() self.SetModified() self.SetStatusText(status) def OnSubclass(self, evt): selected = tree.selection xxx = tree.GetPyData(selected).treeObject() elem = xxx.node subclass = xxx.subclass dlg = wx.TextEntryDialog(self, 'Subclass:', defaultValue=subclass) if dlg.ShowModal() == wx.ID_OK: subclass = dlg.GetValue() if subclass: elem.setAttribute('subclass', subclass) elif elem.hasAttribute('subclass'): elem.removeAttribute('subclass') self.SetModified() xxx.subclass = elem.getAttribute('subclass') tree.SetItemText(selected, xxx.treeName()) panel.pages[0].box.SetLabel(xxx.panelName()) dlg.Destroy() def OnEmbedPanel(self, evt): conf.embedPanel = evt.IsChecked() if conf.embedPanel: # Remember last dimentions conf.panelX, conf.panelY = self.miniFrame.GetPosition() conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() size = self.GetSize() pos = self.GetPosition() sizePanel = panel.GetSize() panel.Reparent(self.splitter) self.miniFrame.GetSizer().Remove(panel) # Widen self.SetDimensions(pos.x, pos.y, size.width + sizePanel.width, size.height) self.splitter.SplitVertically(tree, panel, conf.sashPos) self.miniFrame.Show(False) else: conf.sashPos = self.splitter.GetSashPosition() pos = self.GetPosition() size = self.GetSize() sizePanel = panel.GetSize() self.splitter.Unsplit(panel) sizer = self.miniFrame.GetSizer() panel.Reparent(self.miniFrame) panel.Show(True) sizer.Add(panel, 1, wx.EXPAND) self.miniFrame.Show(True) self.miniFrame.SetDimensions(conf.panelX, conf.panelY, conf.panelWidth, conf.panelHeight) self.miniFrame.Layout() # Reduce width self.SetDimensions(pos.x, pos.y, max(size.width - sizePanel.width, self.minWidth), size.height) def OnShowTools(self, evt): conf.showTools = evt.IsChecked() g.tools.Show(conf.showTools) if conf.showTools: self.toolsSizer.Prepend(g.tools, 0, wx.EXPAND) else: self.toolsSizer.Remove(g.tools) self.toolsSizer.Layout() def OnTest(self, evt): if not tree.selection: return # key pressed event tree.ShowTestWindow(tree.selection) def OnTestHide(self, evt): tree.CloseTestWindow() # Find object by relative position def FindObject(self, item, obj): # We simply perform depth-first traversal, sinse it's too much # hassle to deal with all sizer/window combinations w = tree.FindNodeObject(item) if w == obj or isinstance(w, wx.GBSizerItem) and w.GetWindow() == obj: return item if tree.ItemHasChildren(item): child = tree.GetFirstChild(item)[0] while child: found = self.FindObject(child, obj) if found: return found child = tree.GetNextSibling(child) return None # Click event after locate activated def OnTestWinLeftDown(self, evt): # Restore normal event processing self.SetHandler(g.testWin) g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN) item = self.FindObject(g.testWin.item, evt.GetEventObject()) if item: tree.EnsureVisible(item) tree.SelectItem(item) self.tb.ToggleTool(self.ID_TOOL_LOCATE, False) if item: self.SetStatusText('Selected %s' % tree.GetItemText(item)) else: self.SetStatusText('Locate failed!') def SetHandler(self, w, h=None): if h: w.SetEventHandler(h) w.SetCursor(wx.CROSS_CURSOR) else: w.SetEventHandler(w) w.SetCursor(wx.NullCursor) for ch in w.GetChildren(): self.SetHandler(ch, h) def OnLocate(self, evt): if g.testWin: if evt.GetId() == self.ID_LOCATE or \ evt.GetId() == self.ID_TOOL_LOCATE and evt.IsChecked(): self.SetHandler(g.testWin, g.testWin) g.testWin.Connect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN, self.OnTestWinLeftDown) if evt.GetId() == self.ID_LOCATE: self.tb.ToggleTool(self.ID_TOOL_LOCATE, True) elif evt.GetId() == self.ID_TOOL_LOCATE and not evt.IsChecked(): self.SetHandler(g.testWin, None) g.testWin.Disconnect(wx.ID_ANY, wx.ID_ANY, wx.wxEVT_LEFT_DOWN) self.SetStatusText('Click somewhere in your test window now') def OnRefresh(self, evt): # If modified, apply first selection = tree.selection if selection: xxx = tree.GetPyData(selection) if xxx and panel.IsModified(): tree.Apply(xxx, selection) if g.testWin: # (re)create tree.CreateTestWin(g.testWin.item) panel.modified = False tree.needUpdate = False def OnAutoRefresh(self, evt): conf.autoRefresh = evt.IsChecked() self.menuBar.Check(self.ID_AUTO_REFRESH, conf.autoRefresh) self.tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh) def OnAbout(self, evt): str = '''\ XRCed version %s (c) Roman Rolinsky Homepage: http://xrced.sourceforge.net\ ''' % version dlg = wx.MessageDialog(self, str, 'About XRCed', wx.OK | wx.CENTRE) dlg.ShowModal() dlg.Destroy() def OnReadme(self, evt): text = open(os.path.join(basePath, 'README.txt'), 'r').read() dlg = ScrolledMessageDialog(self, text, "XRCed README") dlg.ShowModal() dlg.Destroy() # Simple emulation of python command line def OnDebugCMD(self, evt): while 1: try: exec raw_input('C:\> ') except EOFError: print '^D' break except: (etype, value, tb) =sys.exc_info() tblist =traceback.extract_tb(tb)[1:] msg =' '.join(traceback.format_exception_only(etype, value) +traceback.format_list(tblist)) print msg def OnCreate(self, evt): # Ignore fake events generated while dragging if g.tools.drag: g.tools.drag = False return selected = tree.selection if tree.ctrl: appendChild = False else: appendChild = not tree.NeedInsert(selected) xxx = tree.GetPyData(selected) if not appendChild: # If insert before if tree.shift: # If has previous item, insert after it, else append to parent nextItem = selected parentLeaf = tree.GetItemParent(selected) else: # If has next item, insert, else append to parent nextItem = tree.GetNextSibling(selected) parentLeaf = tree.GetItemParent(selected) # Expanded container (must have children) elif tree.shift and tree.IsExpanded(selected) \ and tree.GetChildrenCount(selected, False): nextItem = tree.GetFirstChild(selected)[0] parentLeaf = selected else: nextItem = wx.TreeItemId() parentLeaf = selected parent = tree.GetPyData(parentLeaf) if parent.hasChild: parent = parent.child self.CreateXXX(parent, parentLeaf, nextItem, evt.GetId()) # Actual method to create object and add to XML and wx trees def CreateXXX(self, parent, parentLeaf, nextItem, id): selected = tree.selection # Create object_ref? if id == ID_NEW.REF: ref = wx.GetTextFromUser('Create reference to:', 'Create reference') if not ref: return xxx = MakeEmptyRefXXX(parent, ref) elif id == ID_NEW.COMMENT: xxx = MakeEmptyCommentXXX(parent) else: # Create empty element if id >= ID_NEW.CUSTOM: className = pullDownMenu.customMap[id] else: className = pullDownMenu.createMap[id] xxx = MakeEmptyXXX(parent, className) # Insert new node, register undo if xxx.isElement: # true object # Set default name for top-level windows if parent.__class__ == xxxMainNode: cl = xxx.treeObject().__class__ frame.maxIDs[cl] += 1 xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl])) # And for some other standard controls elif parent.__class__ == xxxStdDialogButtonSizer: # ... we can even set automatically tree name xxx.setTreeName(pullDownMenu.stdButtonIDs[id][0]) obj = xxx.treeObject() # ... and label elem = g.tree.dom.createElement('label') elem.appendChild(g.tree.dom.createTextNode(pullDownMenu.stdButtonIDs[id][1])) obj.params['label'] = xxxParam(elem) xxx.treeObject().node.appendChild(elem) # Else, set label if exists to class name elif 'label' in xxx.treeObject().allParams: label = className if label[:2] == 'wx': label = label[2:] xxx.treeObject().set('label', label.upper()) # For comment nodes, simply add node newItem = tree.InsertNode(parentLeaf, parent, xxx.node, nextItem) undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) tree.EnsureVisible(newItem) tree.SelectItem(newItem) if not tree.IsVisible(newItem): tree.ScrollTo(newItem) tree.Refresh() # Update view? if xxx.isElement and g.testWin and tree.IsHighlatable(newItem): if conf.autoRefresh: tree.needUpdate = True tree.pendingHighLight = newItem else: tree.pendingHighLight = None tree.SetFocus() if not xxx.isElement: tree.EditLabel(newItem) self.SetModified() return xxx # Replace one object with another def OnReplace(self, evt): selected = tree.selection xxx = tree.GetPyData(selected).treeObject() elem = xxx.node parent = elem.parentNode undoMan.RegisterUndo(UndoReplace(selected)) # New class className = pullDownMenu.createMap[evt.GetId() - 1000] # Create temporary empty node (with default values) dummy = MakeEmptyDOM(className) if className == 'spacer' and xxx.className != 'spacer': klass = xxxSpacer elif xxx.className == 'spacer' and className != 'spacer': klass = xxxSizerItem else: klass = xxxDict[className] # Remove non-compatible children if tree.ItemHasChildren(selected) and not klass.hasChildren: tree.DeleteChildren(selected) nodes = elem.childNodes[:] tags = [] for node in nodes: if node.nodeType != minidom.Node.ELEMENT_NODE: continue remove = False tag = node.tagName if tag == 'object': if not klass.hasChildren: remove = True elif tag not in klass.allParams and \ (not klass.hasStyle or tag not in klass.styles): remove = True else: tags.append(tag) if remove: elem.removeChild(node) node.unlink() # Remove sizeritem child if spacer if className == 'spacer' and xxx.className != 'spacer': sizeritem = elem.parentNode assert sizeritem.getAttribute('class') == 'sizeritem' sizeritem.removeChild(elem) elem.unlink() elem = sizeritem tree.GetPyData(selected).hasChild = False elif xxx.className == 'spacer' and className != 'spacer': # Create sizeritem element assert xxx.parent.isSizer elem.setAttribute('class', 'sizeritem') node = MakeEmptyDOM(className) elem.appendChild(node) # Replace to point to new object xxx = xxxSizerItem(xxx.parent, elem) elem = node tree.SetPyData(selected, xxx) xxx = xxx.child else: # Copy parameters present in dummy but not in elem for node in dummy.childNodes: if node.tagName not in tags: elem.appendChild(node.cloneNode(True)) dummy.unlink() # Change class name elem.setAttribute('class', className) if elem.hasAttribute('subclass'): elem.removeAttribute('subclass') # clear subclassing # Re-create xxx element xxx = MakeXXXFromDOM(xxx.parent, elem) # Remove incompatible style flags if 'style' in xxx.params: styles = map(string.strip, xxx.params['style'].value().split('|')) newStyles = [s for s in styles if s in klass.winStyles or s in genericStyles] if newStyles != styles: if newStyles: value = reduce(lambda a,b: a+'|'+b, newStyles) else: value = '' xxx.params['style'].update(value) # Update parent in child objects if tree.ItemHasChildren(selected): i, cookie = tree.GetFirstChild(selected) while i.IsOk(): x = tree.GetPyData(i) x.parent = xxx if x.hasChild: x.child.parent = xxx i, cookie = tree.GetNextChild(selected, cookie) # Update tree if tree.GetPyData(selected).hasChild: # child container container = tree.GetPyData(selected) container.resetChild(xxx) xxx = container else: tree.SetPyData(selected, xxx) tree.SetItemText(selected, xxx.treeName()) tree.SetItemImage(selected, xxx.treeImage()) # Set default name for top-level windows if parent.__class__ == xxxMainNode: cl = xxx.treeObject().__class__ frame.maxIDs[cl] += 1 xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl])) # Update panel g.panel.SetData(xxx) # Update tools g.tools.UpdateUI() #undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected)) # Update view? if g.testWin and tree.IsHighlatable(selected): if conf.autoRefresh: tree.needUpdate = True tree.pendingHighLight = selected else: tree.pendingHighLight = None tree.SetFocus() self.SetModified() # Expand/collapse subtree def OnExpand(self, evt): if tree.selection: tree.ExpandAll(tree.selection) else: tree.ExpandAll(tree.root) def OnCollapse(self, evt): if tree.selection: tree.CollapseAll(tree.selection) else: tree.CollapseAll(tree.root) def OnPullDownHighlight(self, evt): menuId = evt.GetMenuId() if menuId != -1: menu = evt.GetEventObject() try: help = menu.GetHelpString(menuId) self.SetStatusText(help) except: self.SetStatusText('') else: self.SetStatusText('') def OnUpdateUI(self, evt): if evt.GetId() in [wx.ID_CUT, wx.ID_COPY, self.ID_DELETE]: evt.Enable(tree.selection is not None and tree.selection != tree.root) elif evt.GetId() == wx.ID_SAVE: evt.Enable(self.modified) elif evt.GetId() in [wx.ID_PASTE, self.ID_TOOL_PASTE]: evt.Enable(tree.selection is not None) elif evt.GetId() in [self.ID_TEST, self.ID_MOVEUP, self.ID_MOVEDOWN, self.ID_MOVELEFT, self.ID_MOVERIGHT]: evt.Enable(tree.selection is not None and tree.selection != tree.root) elif evt.GetId() in [self.ID_LOCATE, self.ID_TOOL_LOCATE, self.ID_REFRESH]: evt.Enable(g.testWin is not None) elif evt.GetId() == wx.ID_UNDO: evt.Enable(undoMan.CanUndo()) elif evt.GetId() == wx.ID_REDO: evt.Enable(undoMan.CanRedo()) def OnIdle(self, evt): if self.inIdle: return # Recursive call protection self.inIdle = True #print 'onidle',tree.needUpdate,tree.pendingHighLight try: if tree.needUpdate: if conf.autoRefresh: if g.testWin: #self.SetStatusText('Refreshing test window...') # (re)create tree.CreateTestWin(g.testWin.item) #self.SetStatusText('') tree.needUpdate = False elif tree.pendingHighLight: try: tree.HighLight(tree.pendingHighLight) except: # Remove highlight if any problem if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() tree.pendingHighLight = None raise else: evt.Skip() finally: self.inIdle = False def OnIconize(self, evt): if evt.Iconized(): conf.x, conf.y = self.GetPosition() conf.width, conf.height = self.GetSize() if conf.embedPanel: conf.sashPos = self.splitter.GetSashPosition() else: conf.panelX, conf.panelY = self.miniFrame.GetPosition() conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() self.miniFrame.Show(False) else: if not conf.embedPanel: self.miniFrame.Show(True) evt.Skip() def OnCloseWindow(self, evt): if not self.AskSave(): return if g.testWin: g.testWin.Destroy() if not panel.GetPageCount() == 2: panel.page2.Destroy() else: # If we don't do this, page does not get destroyed (a bug?) panel.RemovePage(1) if not self.IsIconized(): conf.x, conf.y = self.GetPosition() if wx.Platform == '__WXMAC__': conf.width, conf.height = self.GetClientSize() else: conf.width, conf.height = self.GetSize() if conf.embedPanel: conf.sashPos = self.splitter.GetSashPosition() else: conf.panelX, conf.panelY = self.miniFrame.GetPosition() conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize() evt.Skip() def CreateLocalConf(self, path): name = os.path.splitext(path)[0] name += '.xcfg' return wx.FileConfig(localFilename=name) def Clear(self): self.dataFile = '' conf.localconf = None undoMan.Clear() self.SetModified(False) tree.Clear() panel.Clear() if g.testWin: g.testWin.Destroy() g.testWin = None # Numbers for new controls self.maxIDs = {} for cl in [xxxPanel, xxxDialog, xxxFrame, xxxMenuBar, xxxMenu, xxxToolBar, xxxWizard, xxxBitmap, xxxIcon]: self.maxIDs[cl] = 0 # Restore handlers, menu, etc. to initial setHandlers(self.handlers[:]) g.pullDownMenu.custom = self.custom[:] # Remove modules imported from comment directives map(sys.modules.pop, [m for m in sys.modules if m not in self.modules]) xxxParamComment.locals = {} # clear local namespace xxxParamComment.allow = None # clear execution state def SetModified(self, state=True): self.modified = state name = os.path.basename(self.dataFile) if not name: name = defaultName if state: self.SetTitle(progname + ': ' + name + ' *') else: self.SetTitle(progname + ': ' + name) def Open(self, path): if not os.path.exists(path): wx.LogError('File does not exists: %s' % path) return False # Try to read the file try: f = open(path) self.Clear() dom = minidom.parse(f) f.close() # Set encoding global variable and default encoding if dom.encoding: g.currentEncoding = dom.encoding wx.SetDefaultPyEncoding(g.currentEncoding.encode()) else: g.currentEncoding = '' # Change dir self.dataFile = path = os.path.abspath(path) dir = os.path.dirname(path) if dir: os.chdir(dir) # Allow importing modules from the same directory sys.path = sys_path + [dir] tree.SetData(dom) self.SetTitle(progname + ': ' + os.path.basename(path)) conf.localconf = self.CreateLocalConf(self.dataFile) except: # Nice exception printing inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error reading file: %s' % path) if debug: raise return False return True def Indent(self, node, indent = 0): if node.nodeType == minidom.Node.COMMENT_NODE: text = self.domCopy.createTextNode('\n' + ' ' * indent) node.parentNode.insertBefore(text, node) return # no children # Copy child list because it will change soon children = node.childNodes[:] # Main node doesn't need to be indented if indent: text = self.domCopy.createTextNode('\n' + ' ' * indent) node.parentNode.insertBefore(text, node) if children: # Append newline after last child, except for text nodes if children[-1].nodeType == minidom.Node.ELEMENT_NODE: text = self.domCopy.createTextNode('\n' + ' ' * indent) node.appendChild(text) # Indent children which are elements for n in children: if n.nodeType == minidom.Node.ELEMENT_NODE or \ n.nodeType == minidom.Node.COMMENT_NODE: self.Indent(n, indent + 2) def Save(self, path): try: import codecs # Apply changes if tree.selection and panel.IsModified(): self.OnRefresh(wx.CommandEvent()) if g.currentEncoding: f = codecs.open(path, 'wt', g.currentEncoding) else: f = codecs.open(path, 'wt') # Make temporary copy for formatting it # !!! We can't clone dom node, it works only once #self.domCopy = tree.dom.cloneNode(True) self.domCopy = MyDocument() mainNode = self.domCopy.appendChild(tree.mainNode.cloneNode(True)) # Remove first child (test element) testElem = mainNode.firstChild mainNode.removeChild(testElem) testElem.unlink() self.Indent(mainNode) self.domCopy.writexml(f, encoding = g.currentEncoding) f.close() self.domCopy.unlink() self.domCopy = None self.SetModified(False) panel.SetModified(False) conf.localconf.Flush() except: inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error writing file: %s' % path) raise def AskSave(self): if not (self.modified or panel.IsModified()): return True flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CANCEL | wx.CENTRE dlg = wx.MessageDialog( self, 'File is modified. Save before exit?', 'Save before too late?', flags ) say = dlg.ShowModal() dlg.Destroy() wx.Yield() if say == wx.ID_YES: self.OnSaveOrSaveAs(wx.CommandEvent(wx.ID_SAVE)) # If save was successful, modified flag is unset if not self.modified: return True elif say == wx.ID_NO: self.SetModified(False) panel.SetModified(False) return True return False ################################################################################ class PythonOptions(wx.Dialog): def __init__(self, parent, cfg, dataFile): pre = wx.PreDialog() g.frame.res.LoadOnDialog(pre, parent, "PYTHON_OPTIONS") self.PostCreate(pre) self.cfg = cfg self.dataFile = dataFile self.AutoGenerateCB = xrc.XRCCTRL(self, "AutoGenerateCB") self.EmbedCB = xrc.XRCCTRL(self, "EmbedCB") self.GettextCB = xrc.XRCCTRL(self, "GettextCB") self.MakeXRSFileCB = xrc.XRCCTRL(self, "MakeXRSFileCB") self.FileNameTC = xrc.XRCCTRL(self, "FileNameTC") self.BrowseBtn = xrc.XRCCTRL(self, "BrowseBtn") self.GenerateBtn = xrc.XRCCTRL(self, "GenerateBtn") self.SaveOptsBtn = xrc.XRCCTRL(self, "SaveOptsBtn") self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.BrowseBtn) self.Bind(wx.EVT_BUTTON, self.OnGenerate, self.GenerateBtn) self.Bind(wx.EVT_BUTTON, self.OnSaveOpts, self.SaveOptsBtn) if self.cfg.Read("filename", "") != "": self.FileNameTC.SetValue(self.cfg.Read("filename")) else: name = os.path.splitext(os.path.split(dataFile)[1])[0] name += '_xrc.py' self.FileNameTC.SetValue(name) self.AutoGenerateCB.SetValue(self.cfg.ReadBool("autogenerate", False)) self.EmbedCB.SetValue(self.cfg.ReadBool("embedResource", False)) self.MakeXRSFileCB.SetValue(self.cfg.ReadBool("makeXRS", False)) self.GettextCB.SetValue(self.cfg.ReadBool("genGettext", False)) def OnBrowse(self, evt): path = self.FileNameTC.GetValue() dirname = os.path.abspath(os.path.dirname(path)) name = os.path.split(path)[1] dlg = wx.FileDialog(self, 'Save As', dirname, name, '*.py', wx.SAVE | wx.OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.FileNameTC.SetValue(path) dlg.Destroy() def OnGenerate(self, evt): pypath = self.FileNameTC.GetValue() embed = self.EmbedCB.GetValue() genGettext = self.GettextCB.GetValue() frame.GeneratePython(self.dataFile, pypath, embed, genGettext) self.OnSaveOpts() def OnSaveOpts(self, evt=None): self.cfg.Write("filename", self.FileNameTC.GetValue()) self.cfg.WriteBool("autogenerate", self.AutoGenerateCB.GetValue()) self.cfg.WriteBool("embedResource", self.EmbedCB.GetValue()) self.cfg.WriteBool("makeXRS", self.MakeXRSFileCB.GetValue()) self.cfg.WriteBool("genGettext", self.GettextCB.GetValue()) self.EndModal(wx.ID_OK) ################################################################################ class PrefsDialog(wx.Dialog): def __init__(self, parent): pre = wx.PreDialog() g.frame.res.LoadOnDialog(pre, parent, "DIALOG_PREFS") self.PostCreate(pre) self.checkControls = {} # map of check IDs to (control,dict,param) ##xxx = sys.modules['xxx'] import xxx d = xxx.xxxSizerItem.defaults_panel self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_panel') id = self.check_proportion_panel.GetId() wx.EVT_CHECKBOX(self, id, self.OnCheck) self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_panel'), d, 'option') self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_panel') id = self.check_flag_panel.GetId() wx.EVT_CHECKBOX(self, id, self.OnCheck) self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_panel'), d, 'flag') d = xxx.xxxSizerItem.defaults_control self.check_proportion_panel = xrc.XRCCTRL(self, 'check_proportion_control') id = self.check_proportion_panel.GetId() wx.EVT_CHECKBOX(self, id, self.OnCheck) self.checkControls[id] = (xrc.XRCCTRL(self, 'spin_proportion_control'), d, 'option') self.check_flag_panel = xrc.XRCCTRL(self, 'check_flag_control') id = self.check_flag_panel.GetId() wx.EVT_CHECKBOX(self, id, self.OnCheck) self.checkControls[id] = (xrc.XRCCTRL(self, 'text_flag_control'), d, 'flag') for id,cdp in self.checkControls.items(): c,d,p = cdp try: if isinstance(c, wx.SpinCtrl): c.SetValue(int(d[p])) else: c.SetValue(d[p]) self.FindWindowById(id).SetValue(True) except KeyError: c.Enable(False) self.radio_allow_exec = xrc.XRCCTRL(self, 'radio_allow_exec') try: radio = {'ask': 0, 'yes':1, 'no':2}[g.conf.allowExec] except KeyError: radio = 0 self.radio_allow_exec.SetSelection(radio) def OnCheck(self, evt): self.checkControls[evt.GetId()][0].Enable(evt.IsChecked()) evt.Skip() ################################################################################ # Parse string in form var1=val1[,var2=val2]* as dictionary def ReadDictFromString(s): d = {} for vv in s.split(','): var,val = vv.split(':') d[var.strip()] = val return d # Transform dictionary with strings into one string def DictToString(d): return ','.join(map(':'.join, d.items())) def usage(): print >> sys.stderr, 'usage: xrced [-dhiv] [file]' class App(wx.App): def OnInit(self): # Check version if wx.VERSION[:3] < MinWxVersion: wx.LogWarning('''\ This version of XRCed may not work correctly on your version of wxWidgets. \ Please upgrade wxWidgets to %d.%d.%d or higher.''' % MinWxVersion) global debug # Process comand-line opts = args = None try: opts, args = getopt.getopt(sys.argv[1:], 'dhiv') for o,a in opts: if o == '-h': usage() sys.exit(0) elif o == '-d': debug = True elif o == '-v': print 'XRCed version', version sys.exit(0) except getopt.GetoptError: if wx.Platform != '__WXMAC__': # macs have some extra parameters print >> sys.stderr, 'Unknown option' usage() sys.exit(1) self.SetAppName('xrced') # Settings global conf conf = g.conf = wx.Config(style = wx.CONFIG_USE_LOCAL_FILE) conf.localconf = None conf.autoRefresh = conf.ReadInt('autorefresh', True) pos = conf.ReadInt('x', -1), conf.ReadInt('y', -1) size = conf.ReadInt('width', 800), conf.ReadInt('height', 600) conf.embedPanel = conf.ReadInt('embedPanel', True) conf.showTools = conf.ReadInt('showTools', True) conf.sashPos = conf.ReadInt('sashPos', 200) # read recently used files g.fileHistory = wx.FileHistory() g.fileHistory.Load(conf) if not conf.embedPanel: conf.panelX = conf.ReadInt('panelX', -1) conf.panelY = conf.ReadInt('panelY', -1) else: conf.panelX = conf.panelY = -1 conf.panelWidth = conf.ReadInt('panelWidth', 200) conf.panelHeight = conf.ReadInt('panelHeight', 200) conf.panic = not conf.HasEntry('nopanic') # Preferences conf.allowExec = conf.Read('Prefs/allowExec', 'ask') p = 'Prefs/sizeritem_defaults_panel' import xxx if conf.HasEntry(p): ##sys.modules['xxx'].xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p)) xxx.xxxSizerItem.defaults_panel = ReadDictFromString(conf.Read(p)) p = 'Prefs/sizeritem_defaults_control' if conf.HasEntry(p): ##sys.modules['xxx'].xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p)) xxx.xxxSizerItem.defaults_control = ReadDictFromString(conf.Read(p)) # Add handlers wx.FileSystem.AddHandler(wx.MemoryFSHandler()) self.toolArtProvider = ToolArtProvider() wx.ArtProvider.Push(self.toolArtProvider) # Create main frame frame = Frame(pos, size) # Mac does not set the correct size if wx.Platform == '__WXMAC__': frame.SetClientSize(size) frame.Show(True) # Load plugins plugins = os.getenv('XRCEDPATH') if plugins: cwd = os.getcwd() try: for dir in plugins.split(':'): if os.path.isdir(dir) and \ os.path.isfile(os.path.join(dir, '__init__.py')): # Normalize dir = os.path.abspath(os.path.normpath(dir)) sys.path = sys_path + [os.path.dirname(dir)] try: os.chdir(dir) __import__(os.path.basename(dir), globals(), locals(), ['*']) except: print traceback.print_exc() finally: os.chdir(cwd) # Store important data frame.handlers = getHandlers()[:] frame.custom = g.pullDownMenu.custom[:] frame.modules = sys.modules.copy() # Initialize frame.Clear() # Load file after showing if args: conf.panic = False frame.open = frame.Open(args[0]) return True def OnExit(self): # Write config global conf wc = conf wc.WriteInt('autorefresh', conf.autoRefresh) wc.WriteInt('x', conf.x) wc.WriteInt('y', conf.y) wc.WriteInt('width', conf.width) wc.WriteInt('height', conf.height) wc.WriteInt('embedPanel', conf.embedPanel) wc.WriteInt('showTools', conf.showTools) if not conf.embedPanel: wc.WriteInt('panelX', conf.panelX) wc.WriteInt('panelY', conf.panelY) wc.WriteInt('sashPos', conf.sashPos) wc.WriteInt('panelWidth', conf.panelWidth) wc.WriteInt('panelHeight', conf.panelHeight) wc.WriteInt('nopanic', 1) g.fileHistory.Save(wc) # Preferences wc.DeleteGroup('Prefs') wc.Write('Prefs/allowExec', conf.allowExec) import xxx ##v = sys.modules['xxx'].xxxSizerItem.defaults_panel v = xxx.xxxSizerItem.defaults_panel if v: wc.Write('Prefs/sizeritem_defaults_panel', DictToString(v)) ###v = sys.modules['xxx'].xxxSizerItem.defaults_control v = xxx.xxxSizerItem.defaults_control if v: wc.Write('Prefs/sizeritem_defaults_control', DictToString(v)) wc.Flush() def main(): app = App(0, useBestVisual=False) #app.SetAssertMode(wx.PYAPP_ASSERT_LOG) app.MainLoop() app.OnExit() global conf del conf if __name__ == '__main__': main() spe-0.8.4.h/_spe/plugins/XRCed/params.py0000644000175000017500000011466010763311540016777 0ustar stanistani# Name: params.py # Purpose: Classes for parameter introduction # Author: Roman Rolinsky # Created: 22.08.2001 # RCS-ID: $Id: params.py,v 1.36 2007/06/23 20:49:37 RD Exp $ import string import os.path from globals import * from types import * genericStyles = [ 'wxSIMPLE_BORDER', 'wxSUNKEN_BORDER', 'wxDOUBLE_BORDER', 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_BORDER', 'wxCLIP_CHILDREN', 'wxTRANSPARENT_WINDOW', 'wxWANTS_CHARS', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE' ] genericExStyles = [ 'wxWS_EX_VALIDATE_RECURSIVELY', 'wxWS_EX_BLOCK_EVENTS', 'wxWS_EX_TRANSIENT', 'wxFRAME_EX_CONTEXTHELP', 'wxWS_EX_PROCESS_IDLE', 'wxWS_EX_PROCESS_UI_UPDATES' ] # Global vars initialized in Panel.__init__ for button and textbox size in screen pixels buttonSize = textSise = None # Default Button size in dialog units buttonSizeD = (35,-1) # Class that can properly disable children class PPanel(wx.Panel): def __init__(self, parent, name): wx.Panel.__init__(self, parent, -1, name=name) self.modified = self.freeze = False def Enable(self, value): self.enabled = value # Something strange is going on with enable so we make sure... for w in self.GetChildren(): w.Enable(value) #wx.Panel.Enable(self, value) def SetModified(self, state=True): self.modified = state if state: g.panel.SetModified(True) # Common method to set modified state def OnChange(self, evt): if self.freeze: return self.SetModified() evt.Skip() class ParamBinaryOr(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON_CHOICES = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(200,-1)) sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_CHOICES, 'Edit...', size=(buttonSize[0], textSize[1])) sizer.Add(self.button, 0, wx.EXPAND) self.SetSizerAndFit(sizer) wx.EVT_BUTTON(self, self.ID_BUTTON_CHOICES, self.OnButtonChoices) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): return self.text.GetValue() def SetValue(self, value): self.freeze = True self.text.SetValue(value) self.freeze = False def OnButtonChoices(self, evt): dlg = g.frame.res.LoadDialog(self, 'DIALOG_CHOICES') if self.GetName() == 'flag': dlg.SetTitle('Sizer item flags') elif self.GetName() == 'style': dlg.SetTitle('Window styles') elif self.GetName() == 'exstyle': dlg.SetTitle('Extended window styles') listBox = xrc.XRCCTRL(dlg, 'CHECKLIST') listBox.InsertItems(self.values, 0) value = map(string.strip, self.text.GetValue().split('|')) if value == ['']: value = [] ignored = [] for i in value: try: listBox.Check(self.values.index(i)) except ValueError: # Try to find equal if self.equal.has_key(i): listBox.Check(self.values.index(self.equal[i])) else: print 'WARNING: unknown flag: %s: ignored.' % i ignored.append(i) if dlg.ShowModal() == wx.ID_OK: value = [] for i in range(listBox.GetCount()): if listBox.IsChecked(i): value.append(self.values[i]) # Add ignored flags value.extend(ignored) self.SetValue('|'.join(value)) self.SetModified() dlg.Destroy() class ParamFlag(ParamBinaryOr): values = ['wxTOP', 'wxBOTTOM', 'wxLEFT', 'wxRIGHT', 'wxALL', 'wxEXPAND', 'wxGROW', 'wxSHAPED', 'wxSTRETCH_NOT', 'wxALIGN_CENTRE', 'wxALIGN_LEFT', 'wxALIGN_RIGHT', 'wxALIGN_TOP', 'wxALIGN_BOTTOM', 'wxALIGN_CENTRE_VERTICAL', 'wxALIGN_CENTRE_HORIZONTAL', 'wxADJUST_MINSIZE', 'wxFIXED_MINSIZE' ] equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE', 'wxALIGN_CENTER_VERTICAL': 'wxALIGN_CENTRE_VERTICAL', 'wxALIGN_CENTER_HORIZONTAL': 'wxALIGN_CENTRE_HORIZONTAL', 'wxUP': 'wxTOP', 'wxDOWN': 'wxBOTTOM', 'wxNORTH': 'wxTOP', 'wxSOUTH': 'wxBOTTOM', 'wxWEST': 'wxLEFT', 'wxEAST': 'wxRIGHT'} def __init__(self, parent, name): ParamBinaryOr.__init__(self, parent, name) class ParamNonGenericStyle(ParamBinaryOr): def __init__(self, parent, name): self.values = g.currentXXX.winStyles ParamBinaryOr.__init__(self, parent, name) class ParamStyle(ParamBinaryOr): equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE'} def __init__(self, parent, name): ParamBinaryOr.__init__(self, parent, name) self.valuesSpecific = g.currentXXX.winStyles if self.valuesSpecific: # override if using specific styles # Remove duplicates self.valuesGeneric = [s for s in genericStyles if s not in self.valuesSpecific] wx.EVT_BUTTON(self, self.ID_BUTTON_CHOICES, self.OnButtonChoicesBoth) else: self.values = genericStyles def OnButtonChoicesBoth(self, evt): dlg = g.frame.res.LoadDialog(self, 'DIALOG_STYLES') listBoxSpecific = xrc.XRCCTRL(dlg, 'CHECKLIST_SPECIFIC') listBoxSpecific.InsertItems(self.valuesSpecific, 0) listBoxGeneric = xrc.XRCCTRL(dlg, 'CHECKLIST_GENERIC') listBoxGeneric.InsertItems(self.valuesGeneric, 0) value = map(string.strip, self.text.GetValue().split('|')) if value == ['']: value = [] # Set specific styles value2 = [] # collect generic and ignored here for i in value: try: listBoxSpecific.Check(self.valuesSpecific.index(i)) except ValueError: # Try to find equal if self.equal.has_key(i): listBoxSpecific.Check(self.valuesSpecific.index(self.equal[i])) else: value2.append(i) ignored = [] # Set generic styles, collect non-standart values for i in value2: try: listBoxGeneric.Check(self.valuesGeneric.index(i)) except ValueError: # Try to find equal if self.equal.has_key(i): listBoxGeneric.Check(self.valuesGeneric.index(self.equal[i])) else: print 'WARNING: unknown flag: %s: ignored.' % i ignored.append(i) if dlg.ShowModal() == wx.ID_OK: value = [self.valuesSpecific[i] for i in range(listBoxSpecific.GetCount()) if listBoxSpecific.IsChecked(i)] + \ [self.valuesGeneric[i] for i in range(listBoxGeneric.GetCount()) if listBoxGeneric.IsChecked(i)] + ignored self.SetValue('|'.join(value)) self.SetModified() dlg.Destroy() class ParamExStyle(ParamBinaryOr): def __init__(self, parent, name): if g.currentXXX: self.values = g.currentXXX.exStyles + genericExStyles else: self.values = [] ParamBinaryOr.__init__(self, parent, name) class ParamColour(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=(80,-1)) sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2) self.button = wx.Panel(self, self.ID_BUTTON, wx.DefaultPosition, wx.Size(20, 20)) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) self.SetSizer(sizer) self.textModified = False wx.EVT_PAINT(self.button, self.OnPaintButton) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) wx.EVT_LEFT_DOWN(self.button, self.OnLeftDown) def GetValue(self): return self.text.GetValue() def SetValue(self, value): self.freeze = True if not value: value = '#FFFFFF' self.text.SetValue(str(value)) # update text ctrl try: colour = wx.Colour(int(value[1:3], 16), int(value[3:5], 16), int(value[5:7], 16)) self.button.SetBackgroundColour(colour) except: # ignore errors pass self.button.Refresh() self.freeze = False def OnPaintButton(self, evt): dc = wx.PaintDC(self.button) dc.SetBrush(wx.TRANSPARENT_BRUSH) if self.IsEnabled(): dc.SetPen(wx.BLACK_PEN) else: dc.SetPen(wx.GREY_PEN) size = self.button.GetSize() dc.DrawRectangle(0, 0, size.width, size.height) def OnLeftDown(self, evt): data = wx.ColourData() data.SetColour(self.GetValue()) dlg = wx.ColourDialog(self, data) if dlg.ShowModal() == wx.ID_OK: self.SetValue('#%02X%02X%02X' % dlg.GetColourData().GetColour().Get()) self.SetModified() dlg.Destroy() ################################################################################ # Mapping from wx constants to XML strings fontFamiliesWx2Xml = {wx.DEFAULT: 'default', wx.DECORATIVE: 'decorative', wx.ROMAN: 'roman', wx.SCRIPT: 'script', wx.SWISS: 'swiss', wx.MODERN: 'modern'} fontStylesWx2Xml = {wx.NORMAL: 'normal', wx.SLANT: 'slant', wx.ITALIC: 'italic'} fontWeightsWx2Xml = {wx.NORMAL: 'normal', wx.LIGHT: 'light', wx.BOLD: 'bold'} def ReverseMap(m): rm = {} for k,v in m.items(): rm[v] = k return rm fontFamiliesXml2wx = ReverseMap(fontFamiliesWx2Xml) fontStylesXml2wx = ReverseMap(fontStylesWx2Xml) fontWeightsXml2wx = ReverseMap(fontWeightsWx2Xml) class ParamFont(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON_SELECT = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=(200,-1)) sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_SELECT, 'Select...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) self.SetSizer(sizer) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_SELECT, self.OnButtonSelect) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def OnChange(self, evt): PPanel.OnChange(self, evt) self.textModified = True def _defaultValue(self): return [`g.sysFont().GetPointSize()`, 'default', 'normal', 'normal', '0', '', ''] def GetValue(self): if self.textModified: # text has newer value try: return eval(self.text.GetValue()) except SyntaxError: wx.LogError('Syntax error in parameter value: ' + self.GetName()) return self._defaultValue() return self.value def SetValue(self, value): self.freeze = True # disable other handlers if not value: value = self._defaultValue() self.value = value self.text.SetValue(str(value)) # update text ctrl self.freeze = False def OnButtonSelect(self, evt): if self.textModified: # text has newer value try: self.value = eval(self.text.GetValue()) except SyntaxError: wx.LogError('Syntax error in parameter value: ' + self.GetName()) self.value = self._defaultValue() # Make initial font # Default values size = g.sysFont().GetPointSize() family = wx.DEFAULT style = weight = wx.NORMAL underlined = 0 face = '' enc = wx.FONTENCODING_DEFAULT # Fall back to default if exceptions error = False try: try: size = int(self.value[0]) except ValueError: error = True; wx.LogError('Invalid size specification') try: family = fontFamiliesXml2wx[self.value[1]] except KeyError: error = True; wx.LogError('Invalid family specification') try: style = fontStylesXml2wx[self.value[2]] except KeyError: error = True; wx.LogError('Invalid style specification') try: weight = fontWeightsXml2wx[self.value[3]] except KeyError: error = True; wx.LogError('Invalid weight specification') try: underlined = bool(int(self.value[4])) except ValueError: error = True; wx.LogError('Invalid underlined flag specification') face = self.value[5] except IndexError: error = True mapper = wx.FontMapper() if not self.value[6]: enc = mapper.CharsetToEncoding(self.value[6]) if error: wx.LogError('Invalid font specification') if enc == wx.FONTENCODING_DEFAULT: enc = wx.FONTENCODING_SYSTEM font = wx.Font(size, family, style, weight, underlined, face, enc) data = wx.FontData() data.SetInitialFont(font) dlg = wx.FontDialog(self, data) if dlg.ShowModal() == wx.ID_OK: font = dlg.GetFontData().GetChosenFont() if font.GetEncoding() == wx.FONTENCODING_SYSTEM: encName = '' else: encName = wx.FontMapper.GetEncodingName(font.GetEncoding()).encode() value = [str(font.GetPointSize()), fontFamiliesWx2Xml.get(font.GetFamily(), "default"), fontStylesWx2Xml.get(font.GetStyle(), "normal"), fontWeightsWx2Xml.get(font.GetWeight(), "normal"), str(int(font.GetUnderlined())), font.GetFaceName().encode(), encName ] self.SetValue(value) self.SetModified() self.textModified = False dlg.Destroy() ################################################################################ class ParamInt(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_SPIN_CTRL = wx.NewId() sizer = wx.BoxSizer() self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1)) self.spin.SetRange(-2147483648, 2147483647) # min/max integers sizer.Add(self.spin) self.SetSizer(sizer) wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange) def GetValue(self): return str(self.spin.GetValue()) def SetValue(self, value): self.freeze = True if not value: value = 0 self.spin.SetValue(int(value)) self.freeze = False # Non-negative number class ParamIntNN(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_SPIN_CTRL = wx.NewId() sizer = wx.BoxSizer() self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1)) self.spin.SetRange(0, 10000) # min/max integers sizer.Add(self.spin) self.SetSizer(sizer) wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange) def GetValue(self): return str(self.spin.GetValue()) def SetValue(self, value): self.freeze = True if not value: value = 0 self.spin.SetValue(int(value)) self.freeze = False # Same as int but allows dialog units (XXXd) class ParamUnit(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_SPIN_BUTTON = wx.NewId() sizer = wx.BoxSizer(wx.HORIZONTAL) self.spin = wx.SpinButton(self, self.ID_SPIN_BUTTON, style = wx.SP_VERTICAL, size=(-1,0)) textW = 60 - self.spin.GetSize()[0] self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=(textW,-1)) self.spin.SetRange(-10000, 10000) sizer.Add(self.text, 0, wx.EXPAND) sizer.Add(self.spin, 0, wx.EXPAND) self.SetSizer(sizer) self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp) self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown) self.text.Bind(wx.EVT_TEXT, self.OnChange) def GetValue(self): return self.text.GetValue() def SetValue(self, value): self.freeze = True if not value: value = '0' self.text.SetValue(value) self.Change(0) self.freeze = False def Change(self, x): self.freeze = True # Check if we are working with dialog units value = self.text.GetValue() units = '' if value[-1].upper() == 'D': units = value[-1] value = value[:-1] try: intValue = int(value) + x self.spin.SetValue(intValue) if x: # 0 can be passed to update spin value only self.text.SetValue(str(intValue) + units) self.SetModified() except: # !!! Strange, if I use wx.LogWarning, event is re-generated print 'ERROR: incorrect unit format' self.freeze = False def OnSpinUp(self, evt): self.freeze = True self.Change(1) def OnSpinDown(self, evt): if self.freeze: return self.freeze = True self.Change(-1) class ParamMultilineText(PPanel): def __init__(self, parent, name, textWidth=-1): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON_EDIT = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(200,-1)) sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) self.SetSizerAndFit(sizer) wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): return self.text.GetValue() def SetValue(self, value): self.freeze = True # disable other handlers self.text.SetValue(value) self.freeze = False # disable other handlers def OnButtonEdit(self, evt): dlg = g.frame.res.LoadDialog(self, 'DIALOG_TEXT') textCtrl = xrc.XRCCTRL(dlg, 'TEXT') textCtrl.SetValue(self.text.GetValue()) if dlg.ShowModal() == wx.ID_OK: self.text.SetValue(textCtrl.GetValue()) self.SetModified() dlg.Destroy() class ParamText(PPanel): def __init__(self, parent, name, textWidth=-1, style=0): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() # We use sizer even here to have the same size of text control sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(textWidth,-1), style=style) if textWidth == -1: option = 1 else: option = 0 sizer.Add(self.text, option, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2) self.SetSizer(sizer) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): return self.text.GetValue() def SetValue(self, value): self.freeze = True # disable other handlers self.text.SetValue(value) self.freeze = False # disable other handlers class ParamAccel(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 100) class ParamPosSize(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 80) class ParamLabel(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 200) class ParamEncoding(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 100) class ParamComment(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 330 + buttonSize[0], style=wx.TE_PROCESS_ENTER) class ContentDialog(wx.Dialog): def __init__(self, parent, value): # Load from resource pre = wx.PreDialog() g.frame.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT') self.PostCreate(pre) self.list = xrc.XRCCTRL(self, 'LIST') # Set list items for v in value: self.list.Append(v) self.SetAutoLayout(True) self.GetSizer().Fit(self) # Callbacks self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND') self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP') self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN') wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp) wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown) wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend) wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI) def OnButtonUp(self, evt): i = self.list.GetSelection() str = self.list.GetString(i) self.list.Delete(i) self.list.InsertItems([str], i-1) self.list.SetSelection(i-1) def OnButtonDown(self, evt): i = self.list.GetSelection() str = self.list.GetString(i) self.list.Delete(i) self.list.InsertItems([str], i+1) self.list.SetSelection(i+1) def OnButtonAppend(self, evt): str = wx.GetTextFromUser('Enter new item:', 'Append', '', self) self.list.Append(str) def OnButtonRemove(self, evt): self.list.Delete(self.list.GetSelection()) def OnUpdateUI(self, evt): if evt.GetId() == self.ID_BUTTON_REMOVE: evt.Enable(self.list.GetSelection() != -1) elif evt.GetId() == self.ID_BUTTON_UP: evt.Enable(self.list.GetSelection() > 0) elif evt.GetId() == self.ID_BUTTON_DOWN: evt.Enable(self.list.GetSelection() != -1 and \ self.list.GetSelection() < self.list.GetCount() - 1) class ContentCheckListDialog(wx.Dialog): def __init__(self, parent, value): pre = wx.PreDialog() g.frame.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT_CHECKLIST') self.PostCreate(pre) self.list = xrc.XRCCTRL(self, 'CHECK_LIST') # Set list items i = 0 for v,ch in value: self.list.Append(v) self.list.Check(i, ch) i += 1 self.SetAutoLayout(True) self.GetSizer().Fit(self) # Callbacks self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND') self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP') self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN') wx.EVT_CHECKLISTBOX(self, self.list.GetId(), self.OnCheck) wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp) wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown) wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend) wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI) def OnCheck(self, evt): # !!! Wrong wxGTK (wxMSW?) behavior: toggling selection if checking self.list.Deselect(evt.GetSelection()) def OnButtonUp(self, evt): i = self.list.GetSelection() str, ch = self.list.GetString(i), self.list.IsChecked(i) self.list.Delete(i) self.list.InsertItems([str], i-1) self.list.Check(i-1, ch) self.list.SetSelection(i-1) def OnButtonDown(self, evt): i = self.list.GetSelection() str, ch = self.list.GetString(i), self.list.IsChecked(i) self.list.Delete(i) self.list.InsertItems([str], i+1) self.list.Check(i+1, ch) self.list.SetSelection(i+1) def OnButtonAppend(self, evt): str = wx.GetTextFromUser('Enter new item:', 'Append', '', self) self.list.Append(str) def OnButtonRemove(self, evt): self.list.Delete(self.list.GetSelection()) def OnUpdateUI(self, evt): if evt.GetId() == self.ID_BUTTON_REMOVE: evt.Enable(self.list.GetSelection() != -1) elif evt.GetId() == self.ID_BUTTON_UP: evt.Enable(self.list.GetSelection() > 0) elif evt.GetId() == self.ID_BUTTON_DOWN: evt.Enable(self.list.GetSelection() != -1 and \ self.list.GetSelection() < self.list.GetCount() - 1) class ParamContent(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON_EDIT = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(200,-1)) sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) self.SetSizer(sizer) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def OnChange(self, evt): PPanel.OnChange(self, evt) self.textModified = True def GetValue(self): if self.textModified: # text has newer value try: return self.text.GetValue().split('|') except ValueError: return [] return self.value def SetValue(self, value): self.freeze = True if not value: value = [] self.value = value repr_ = '|'.join(map(str, value)) self.text.SetValue(repr_) # update text ctrl self.freeze = False def OnButtonEdit(self, evt): if self.textModified: # text has newer value self.value = self.GetValue() dlg = ContentDialog(self, self.value) if dlg.ShowModal() == wx.ID_OK: value = [] for i in range(dlg.list.GetCount()): value.append(dlg.list.GetString(i)) self.SetValue(value) self.SetModified() self.textModified = False dlg.Destroy() def SetModified(self, state=True): PPanel.SetModified(self, state) self.textModified = False # CheckList content class ParamContentCheckList(ParamContent): def __init__(self, parent, name): ParamContent.__init__(self, parent, name) def OnButtonEdit(self, evt): if self.textModified: # text has newer value self.value = self.GetValue() dlg = ContentCheckListDialog(self, self.value) if dlg.ShowModal() == wx.ID_OK: value = [] for i in range(dlg.list.GetCount()): value.append((dlg.list.GetString(i), int(dlg.list.IsChecked(i)))) self.SetValue(value) self.SetModified() self.textModified = False dlg.Destroy() def SetValue(self, value): self.freeze = True if not value: value = [] self.value = value repr_ = '|'.join(map(str,value)) self.text.SetValue(repr_) # update text ctrl self.freeze = False class IntListDialog(wx.Dialog): def __init__(self, parent, value): pre = wx.PreDialog() g.frame.res.LoadOnDialog(pre, parent, 'DIALOG_INTLIST') self.PostCreate(pre) self.list = xrc.XRCCTRL(self, 'LIST') # Set list items value.sort() for v in value: if type(v) != IntType: wx.LogError('Invalid item type') else: self.list.Append(str(v)) self.SetAutoLayout(True) self.GetSizer().Fit(self) # Callbacks self.spinCtrl = xrc.XRCCTRL(self, 'SPIN') wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_ADD'), self.OnButtonAdd) self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_CLEAR'), self.OnButtonClear) wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI) def OnButtonAdd(self, evt): # Check that it's unique try: v = self.spinCtrl.GetValue() s = str(v) # to be sure i = self.list.FindString(s) if i == -1: # ignore non-unique # Find place to insert found = False for i in range(self.list.GetCount()): if int(self.list.GetString(i)) > v: found = True break if found: self.list.InsertItems([s], i) else: self.list.Append(s) except ValueError: wx.LogError('List item is not an int!') def OnButtonRemove(self, evt): self.list.Delete(self.list.GetSelection()) def OnButtonClear(self, evt): self.list.Clear() def OnUpdateUI(self, evt): if evt.GetId() == self.ID_BUTTON_REMOVE: evt.Enable(self.list.GetSelection() != -1) # For growable list class ParamIntList(ParamContent): def __init__(self, parent, name): ParamContent.__init__(self, parent, name) def OnButtonEdit(self, evt): if self.textModified: # text has newer value try: self.value = map(int, self.text.GetValue().split('|')) except ValueError: self.value = [] dlg = IntListDialog(self, self.value) if dlg.ShowModal() == wx.ID_OK: value = [] for i in range(dlg.list.GetCount()): value.append(int(dlg.list.GetString(i))) self.SetValue(value) self.SetModified() self.textModified = False dlg.Destroy() # Boxless radiobox class RadioBox(PPanel): def __init__(self, parent, id, choices, pos=wx.DefaultPosition, name='radiobox'): PPanel.__init__(self, parent, name) self.choices = choices topSizer = wx.BoxSizer() for i in choices: button = wx.RadioButton(self, -1, i, size=(-1,buttonSize[1]), name=i) topSizer.Add(button, 0, wx.RIGHT, 5) wx.EVT_RADIOBUTTON(self, button.GetId(), self.OnRadioChoice) self.SetSizer(topSizer) def SetStringSelection(self, value): self.freeze = True for i in self.choices: self.FindWindowByName(i).SetValue(i == value) self.value = value self.freeze = False def OnRadioChoice(self, evt): if self.freeze: return if evt.GetSelection(): self.value = evt.GetEventObject().GetName() self.SetModified() def GetStringSelection(self): return self.value class ParamBool(RadioBox): values = {'yes': '1', 'no': '0'} seulav = {'1': 'yes', '0': 'no'} def __init__(self, parent, name): RadioBox.__init__(self, parent, -1, choices=self.values.keys(), name=name) def GetValue(self): return self.values[self.GetStringSelection()] def SetValue(self, value): if not value: value = '1' self.SetStringSelection(self.seulav[value]) class ParamOrient(RadioBox): values = {'horizontal': 'wxHORIZONTAL', 'vertical': 'wxVERTICAL'} seulav = {'wxHORIZONTAL': 'horizontal', 'wxVERTICAL': 'vertical'} def __init__(self, parent, name): RadioBox.__init__(self, parent, -1, choices=self.values.keys(), name=name) def GetValue(self): return self.values[self.GetStringSelection()] def SetValue(self, value): if not value: value = 'wxHORIZONTAL' self.SetStringSelection(self.seulav[value]) class ParamOrientation(RadioBox): values = {'horizontal': 'horizontal', 'vertical': 'vertical'} seulav = {'horizontal': 'horizontal', 'vertical': 'vertical'} def __init__(self, parent, name): RadioBox.__init__(self, parent, -1, choices=self.values.keys(), name=name) def GetValue(self): return self.values[self.GetStringSelection()] def SetValue(self, value): if not value: value = 'vertical' self.SetStringSelection(self.seulav[value]) class ParamFile(PPanel): def __init__(self, parent, name): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() self.ID_BUTTON_BROWSE = wx.NewId() sizer = wx.BoxSizer() self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(200,-1)) sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_BROWSE, 'Browse...',size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) self.SetSizer(sizer) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_BROWSE, self.OnButtonBrowse) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def OnChange(self, evt): PPanel.OnChange(self, evt) self.textModified = True def GetValue(self): if self.textModified: # text has newer value return self.text.GetValue() return self.value def SetValue(self, value): self.freeze = True self.value = value self.text.SetValue(value) # update text ctrl self.freeze = False def OnButtonBrowse(self, evt): if self.textModified: # text has newer value self.value = self.text.GetValue() dlg = wx.FileDialog(self, defaultDir = os.path.abspath(os.path.dirname(self.value)), defaultFile = os.path.basename(self.value)) if dlg.ShowModal() == wx.ID_OK: # Get common part of selected path and current if g.frame.dataFile: curpath = os.path.abspath(g.frame.dataFile) else: curpath = os.path.join(os.getcwd(), '') common = os.path.commonprefix([curpath, dlg.GetPath()]) self.SetValue(dlg.GetPath()[len(common):]) self.SetModified() self.textModified = False dlg.Destroy() class ParamBitmap(PPanel): def __init__(self, parent, name): pre = wx.PrePanel() g.frame.res.LoadOnPanel(pre, parent, 'PANEL_BITMAP') self.PostCreate(pre) self.modified = self.freeze = False self.radio_std = xrc.XRCCTRL(self, 'RADIO_STD') self.radio_file = xrc.XRCCTRL(self, 'RADIO_FILE') self.combo = xrc.XRCCTRL(self, 'COMBO_STD') self.text = xrc.XRCCTRL(self, 'TEXT_FILE') self.button = xrc.XRCCTRL(self, 'BUTTON_BROWSE') self.textModified = False self.SetAutoLayout(True) self.GetSizer().SetMinSize((260, -1)) self.GetSizer().Fit(self) wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_STD'), self.OnRadioStd) wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_FILE'), self.OnRadioFile) wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_BROWSE'), self.OnButtonBrowse) wx.EVT_COMBOBOX(self, xrc.XRCID('COMBO_STD'), self.OnCombo) wx.EVT_TEXT(self, xrc.XRCID('COMBO_STD'), self.OnChange) wx.EVT_TEXT(self, xrc.XRCID('TEXT_FILE'), self.OnChange) def OnRadioStd(self, evt): self.SetModified() self.SetValue(['wxART_MISSING_IMAGE','']) def OnRadioFile(self, evt): self.SetModified() self.SetValue(['','']) def updateRadios(self): if self.value[0]: self.radio_std.SetValue(True) self.radio_file.SetValue(False) self.text.Enable(False) self.button.Enable(False) self.combo.Enable(True) else: self.radio_std.SetValue(False) self.radio_file.SetValue(True) self.text.Enable(True) self.button.Enable(True) self.combo.Enable(False) def OnChange(self, evt): PPanel.OnChange(self, evt) self.textModified = True def OnCombo(self, evt): PPanel.OnChange(self, evt) self.value[0] = self.combo.GetValue() def GetValue(self): if self.textModified: # text has newer value return [self.combo.GetValue(), self.text.GetValue()] return self.value def SetValue(self, value): self.freeze = True if not value: self.value = ['', ''] else: self.value = value self.combo.SetValue(self.value[0]) self.text.SetValue(self.value[1]) # update text ctrl self.updateRadios() self.freeze = False def OnButtonBrowse(self, evt): if self.textModified: # text has newer value self.value[1] = self.text.GetValue() dlg = wx.FileDialog(self, defaultDir = os.path.abspath(os.path.dirname(self.value[1])), defaultFile = os.path.basename(self.value[1])) if dlg.ShowModal() == wx.ID_OK: # Get common part of selected path and current if g.frame.dataFile: curpath = os.path.abspath(g.frame.dataFile) else: curpath = os.path.join(os.getcwd(), '') common = os.path.commonprefix([curpath, dlg.GetPath()]) self.SetValue(['', dlg.GetPath()[len(common):]]) self.SetModified() self.textModified = False dlg.Destroy() paramDict = { 'flag': ParamFlag, 'style': ParamStyle, 'exstyle': ParamExStyle, 'pos': ParamPosSize, 'size': ParamPosSize, 'cellpos': ParamPosSize, 'cellspan': ParamPosSize, 'border': ParamUnit, 'cols': ParamIntNN, 'rows': ParamIntNN, 'vgap': ParamUnit, 'hgap': ParamUnit, 'checkable': ParamBool, 'checked': ParamBool, 'radio': ParamBool, 'accel': ParamAccel, 'label': ParamMultilineText, 'title': ParamText, 'value': ParamText, 'content': ParamContent, 'selection': ParamIntNN, 'min': ParamInt, 'max': ParamInt, 'fg': ParamColour, 'bg': ParamColour, 'font': ParamFont, 'enabled': ParamBool, 'focused': ParamBool, 'hidden': ParamBool, 'tooltip': ParamText, 'bitmap': ParamBitmap, 'icon': ParamBitmap, 'encoding': ParamEncoding, 'borders': ParamUnit, 'comment': ParamComment } spe-0.8.4.h/_spe/plugins/XRCed/license.txt0000644000175000017500000000245710763311540017325 0ustar stanistaniCopyright (c) 2002, Roman Rolinsky All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. spe-0.8.4.h/_spe/plugins/XRCed/images.py0000644000175000017500000034124010763311540016755 0ustar stanistani#---------------------------------------------------------------------- # This file was generated by encode_bitmaps.py # from wx import ImageFromStream, BitmapFromImage, EmptyIcon import cStringIO def getAutoRefreshData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04\xdaIDAT8\x8d\xc5\x95[lTE\x18\xc7\xff3s\xce\x9e\xed\x9en[\xb6\x97\xa5+\ \xb4\x05B%\n\x08\xb4\x94kkK!>\xa0$\x1aC\x1a\x8a\t/\x06|T\x89\t\xd1\x18\x8d1\ \xc4\xa0!\x01\r\xa0\x04/\xb0\x05\x8a\x0f\x06D\xf1A\xe8-@Yz\xa3AZDm\x97n/\x0b\ t\xdb\xbd\x9f\xdb\x8c\x0flk[j\xe2\x9b\x93\xfc\x93/3\xdf\xfcf\xbeo\xfe\xc9\ \x00\xff\xe7\xd8^\xbf\x97\xfd\x97\xbc\xca3k\x8b6\x9e[\xe7\x02\x002k\xc2we\ \xc5L\x91\xdfa\xc0&\xc34\xf3\x05\xb8L\t\x8bRJ\x83\\X\x979\xe7\xe7H\x947]\xd9\ \xddfL\xec)?\xbd\xc6\xcd8\xbf\xaa\xc1\xdct\xad\xb6\xa3\x7f\x1a\x98\x88ZR}\ \xf6\xaf\xe3\x00j6\xcc/\xb7=\x9d\xf7\x8c\xe4TT0\xc2\x9044\xc4\x8d\x18\xee\ \x8f\xf7[\x9dC\x1d\xb1`l\x84A\x90OL[\xf4\xa0CO\xa7I\n\x1f,\xab\x98\x08Q\xd8\ \xf0Z\x9b\x7f\x1ax\xf3\x99\xf5_\x17f.\xd8\xbec\xf9N\x87fi\x08\'\xc7\xa0*N8d\ \x15\x14\x14\x94\x10\x08\x00\x94\x10D\xb4\x08Z\xfa\x1a\x92\xad\x81V\xdd"bpc\ \xc1\xc6\x85\xb7G\xba\x8dPb|Icm\xeb\x804Y\xfe\xc9\x925\xaa\xac\xbe\xbai\xe1f\ \xc7Q\xdf\x17<\x98x@%P\x98\x9c\x0bJ\x84\xe9V\xf3\x13\xa5\xf3\xca\xd4\x95sW1\ \x03\x1c\x9aH\xa0rQ\xb5}\xd5\xbcR\xfb\x1f\xa3\xf7\x9cU\x85[\xc8\xad\xe1NS\ \xa7:\x07\x00:\x01f\x92}\x8f\xd3\x96\xa1\x9eh?.\xc6\xcd0Q\xe5\xb4\xa4eY\xf5\ \x8d\xb5\xad\xd4\x12\t\xf7@,\xb0\xe5\xa7\xdf/~\xbf\xbf\xf9\xa3x\xfb\x90O\xa4\ 1\x15\x83\x89\x00\xc6\xccQ\x94z\xca\x88D%\xe8\x96\x055)M\x07S\xe0\x85\xfe\ \xb0\x9f\xb8\x9c\xd9\xa1b\xf7\xe2\x8e\xa4\xa9\x87\xc0q\x00\x00\x9aj\xbbC-;n\ \xde\xb8\\s\xb5F\xb3\x8c\r\xbf\xdc\xbd\xe4;\xd1\xf6U<\x93f\xe1)G\x01Z\x82\r\ \x90\xa9\r\x10\x16\xd1\x996\x1dl\x11\xa18l\x8e@Q^\xc11\xd5\x9eq\n\x14w\xb9b\ \x85f:\xa6\xb9\xd6\xd7\xa9\x9b\xfa\xbe\x88\x1ef\x0e\xd9\x89\xe1D\x00\x00\x87\ B\xed0\x84E \xcb\x1c\x00&{,,+\x9e\x91\x9esH\xb5g\\\x88+\xdaC\x9d\x88o\xdd\ \xb9\x19\xe1\x99\xe0\no\xc92\x06\xe9\xfc\xeb%o(nG\x1e\xd6\xe7UBa\n87\t\ \x97m\xd3\xc1.\x8fc\x81\xd9x\x9e\x7f\xf0\xe2y>\x9b\xb7\x01\xa0\xe2dI>\'\xe4\ \x12\xe1\x96\xe3\x88\xef\xb0&\x84\x80E\x04\xa8\x10\xe0B\xc0\x04\xb7\x99\xb1\ \xc7\x8f7i\xb7J\xef\xea\x07\x9c\x90\xf4\xd9\x80B\x88\x88$\xc8\x96\xa4k\xb4G\ \x04\xd3\xd3\xfe\xed`*d\xe5\xda\xae\xe2\xa0 ^!M\x99\xcf\xfaf\xabW\x92\xa9\r\ \x82\x08PPhf\x12\x1f6\xbf\xab\xf9\xc3}o]\xd9y\xa3+\x95\xa7\x01@\xd5\xb1\x12\ \xd9p\xc1\xb1rEy2G\x9f3\xa7\xe7~\xd7\xfa\xa1G\xf7\xbf\x14\xc4\x9b3\xad\x15\ \x16@\x14\xc9\x8e\x96\x91_A\x04\xc1\xea\xdc\r8{\xc7\xab\rD\xfd\x9f7\xd4\xfaN\ \xcd\xbc\x1dO\x97\xdcv\x8b\x1d\xc9\x88H?$\xf8xn8\x16\xda\xcd$\x9b5y\xfb\x89\ \x80\xa5\xfa\xa2s\x13\x1eu>\x04\x80\xee\x07]\x82\x80.[{z\xf5\xfc\x99`\x06dpa\ \xad\x0b\xc7\xc3;{\x03\xb7\xf7F\x13\x91"&\xc8\x9f\x13\xeb\xff\xb8B\x08B@\xb1\ 4k9\x86\xe2\x03\x90\xa8\x84\xfdU\x9f\xd9\xeb{\xea\xaa\x7f\xbe\xf7cOU]\xd9a\ \x83\xf3\x9b\xa0\xf0+&\x95,\xf0O\xd3\xe4\xb4\xac\x9e\xc0\x9dJ\xbbd\x13.5\xdb\ x\x94\x08\x1d\x7f\x02\x0c\x00\x84\x10\xc4\xf58\x16g>\x0b\xc3\xd2p+\xd4\x86\ \xf2\x82\nV\xea)s\xb4\r\xf9\xde\x1e\x8e\x0c%\x07#\x01\xf20\xf1HU\x08C^\x9a\ \x1bK\xf2\x96 G\xcd%u\x9d\xa7\x92TO\xf7>\x01\xa6\x94\x92\xfep\x1f\xdek\xdc7F\ A\xe9\xd6E/\xd9\x9e/\xac\xb2\x8f\x99\xa3\x10\xe0X\x91\xbfR2\xe6.Mg\xa0 \xa00\ \x85\x01\x83\x9b\x18\xd7B8\xdd\xe1\x8d\x1a\x86\xf5f\xf3\xae\xcb\xc9\xa9\xad\ \x05\x00V\xf4\x8a\xe7\xfd\x1b\x03\xd7b}M\xfem]\x87z\x0f\x062\xfd\x83\xd7C\ \xcd\x8b\xc6\x93\xe3\xaa\xccl\xd4is\x12\xa7\xec\x04\x07\x87\xc9MD\xf5\x08\ \xda\x07n\xf2\x8b\xbd\x17\xb4\xf0P\xe4\xc0\xd5=\xed\xde\x14O\x00\xb0&|l\xaf\ \xf0\x96\x84B\xbfE\xb7w\x7f\xdc{\x1b@ZJ\xf6\xa2m\x9e\xe7<\xd5\xee\x1a6G^%Q(\ \x0eY5\x12f\x9cq!`Dy\xcbHS\xf0\xc8\xbd:\x7f\x17\x80DJq\x00\xf1\t0Y{t\xf9\xcb\ \xd7\xf7\xdcj\x04`\x07\xa0L\x91\x9c\x12\x93\xb3\x99\x9c\xbd\xd4\xe5\x8a\x0e\ \xc7C\xd1\xdeX\x08\x80\x8e\xc7\xbe\xd6R\xd0H*\x16\xb3}Ml\nlB\xd2\xd42S2R\xd2\ \x01\x98\xa9\xb9\xc9\xf17D|>\xc5\x05Q\xf4%\x00\x00\x00\x00IEND\xaeB`\x82' def getAutoRefreshBitmap(): return BitmapFromImage(getAutoRefreshImage()) def getAutoRefreshImage(): stream = cStringIO.StringIO(getAutoRefreshData()) return ImageFromStream(stream) def getAutoRefreshIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getAutoRefreshBitmap()) return icon #---------------------------------------------------------------------- def getCopyData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x02jIDAT8\x8d\x95\x95\xcfO\x13A\x14\xc7\xbfof\xb7-=\xb4\xb7^\xb9\xb4t\xeb_\ \xa1\x07\x13\x8dW\xff\x01\xefDK\x14\x8c\xc4\xb3\t`A1\xfe\x88\x1a\xfd3<\x99\ \x10\x02%DR%\x01\xda\xd43\x1e\x80\x83\x10H\xba\x9dv\x9e\x87aw;u\xbb\x94\xb9\ \xb4\xe9{\xfb\x99\xcf{\xf3vJ\xb5WK\x0fX\xeb\n\xae\xb9H\x88\xe6\xe3\xea\xec\ \xd7QqGu\xbb\xde\xd3\xd9\xf9\xebr\xf1zu\xd9K\x8a;B\x10\x00\xe0\xf4\xf4\xef\ \xd8\xd0\\.\x0f"J\xccq\x92\x82\xccL\xddnW\x0e\xfd\x86T*\rf\xe6\xb1\xc1\xed\ \xf6o\x0b\xda\xf8\xb5s\xff\xe2\xe2|\x12\xc0\x00\x84@d6x\xb9\xbc\xf0(\x86ID\ \xb4f\x81\xa7\xa6J\xe1w\xdf\xf7\xe5\xda\xfa\xf7\xc9\xb9\'\xcf\x88\x99\x93\ \xeb\xb6\xa9\xa8\xad,\xde\x1ci\xacz\n\x97\xa6tvv:.\x17\xb9\\\x1e\x00x\xa4q\ \xa7\xd3\xc1f}}l `\xda\x13\xac\x18c\x13T\xaak%6\x9b\xcd+\xa1\x9e\x17\xbd\x0e\ \x16\xb8T*\xc2\xb0\xd8\x18om\x841\xcf\x8b\x1f\xdb`sf\x8e7ff\xb4\xdb\xed\x10\ \xac\x94\xb2\x12[\xadV,4JaT*7"p\x10`f\x14\x8b\x03\xc6\xbe\x8f\xad\xed\xcd0\ \xb1R\x89\xca\xb4-M>\x11%\x19\x9b\x1e33\x94\xea\xfdg<\x084\x9f\xc1\xa6\x1e\ \x98\x81t:m\x83\xb5\xd6\xa1\xb1\x01\x03\xbe\xdf\xc1\xf6\x8fz\x98X.\x97C\xbba\ c"\x01\xc7\x91PJAk\x1d\x81\xfb\xfd\xbeU\x16\xb3=:\xcc\x8c\x83\x83`*\xec\xbcl\ 6\x8b|>\x0f\x00(\x14\n!k\x00\x1c\xc0\x02\x0b\xb2\xc0\xe5\xf2\x94\x05\x04\x18\ BHH)\xa1\xb5\x86\x10\x02A\xf5\x97\x87g&`bb"l\t\x11\xc1u\xdd\xa1\xc3"\x10ES\ \xe0\xba.\x88\x84\xb1s\x9c\xf0\xf0\xea[\x1b\xd0Z\xc3qS\xa9\xd6\xbb\x0fob/z"\ \n7\x1b\xb4\x15B\x80H@k\x8d\x8f\x9f\xdf\xc7=\xdat\x92\xfe\x05\x16\x96^<\x1c\ \xee\x7fP>3\x9b6\x80q\xf7\xf6=\x00\xc0\xf1\xc9\x11\x1a?w\xc0\x84O\x89\xf7\ \xf1p\xff]\xd7\x81\x94\xe6\x11cM\x90\xd2\\\xd7\x87\x7f\x0e\xb1\xb7\xbf\x8bL6\ \xfb\xa5:=\xb3z%X)\x85L&c\xbd\xb2RF\xd6\xfd\xbe\xc6\xf1\xc9\x11\xf6\xf6w\x01\ A\xd3\xd5\xe9\x99\xb7\x00\x90x\xcf\xd6V\x16\xbf\xf5z\xbd;\x80=~\xc1b0\x18\ \xd0\x02\xd4\xd0\xe0[\xf3s\xcf\xcf\x83\xd8?*\xc0\x9c\xe7m\xfeA\x16\x00\x00\ \x00\x00IEND\xaeB`\x82' def getCopyBitmap(): return BitmapFromImage(getCopyImage()) def getCopyImage(): stream = cStringIO.StringIO(getCopyData()) return ImageFromStream(stream) def getCopyIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getCopyBitmap()) return icon #---------------------------------------------------------------------- def getCutData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04/IDAT8\x8d\x85\x93]H\\G\x14\xc7\xffsw\xee\xde\xbbYM\xe2\xc7\xc6\x98]u\ \x0bmbiblK\xaa\x11\rI\xb4\xa5-}\x08\x01i)\x92\xbe\x08JmZ\xe9\x83\n[Z,\x08\ \xc6\x06\xb4\x14!\xa4!\x0f!\x14?\x82\xb1\x86\x90\x16S\x89i\x8a\xb5\x0f5%&i\ \xa4\x15c\xd5m\xdc\xac\xba\xdfw\xef\x9d\xb9\xd3\x07W\xb0\xcb\xba90\x0c\xcc9\ \xe77\xffs8\x87 \xc9\xba\xbf>;a\x9af\xb9a\x18Um-\x9e;\xc9\xfe\r\xeb\xec\xeah\ \x06\xd0\xad\xaa\xb6\xc5\xe6\x8f?u%\xfb\xa5\xe4`I\x92\xca\x0e\x1d*CnN\xee\ \xe8VP\x00PU\xf5\xab\xb7\xdfz\x07\x92$9;\xbb:\xae\xa6\x05\xdb\xed\xf6\x0f\ \xdfx\xfdM\xe2.|\x0e\x16\xc9\xa2~{\xe1\\{*\xe87\xbd=}\xce=N\x9a\xb53\x1bG\ \xaa\x8ebw\xde\xee\x03i\xc1\x8c1gn\x8e\x03\x00Pu\xe4(\x00x\x92\x13:\xbb:\x8a\ \xe2\xf1\xf8\xbb\xe5e\x15\xe0\x9cCUUD\xa2\x91\x82\xb4\xe0x<>3r\xed\xaai\xb5Z\ !S\x19yy\xf9\x96\xcb\xdf]\x1a\xdb\x1c\x93\x99\x999|\xb8\xbc\x02\x8cqH\x92\ \x84[\xe3?!\x14\n\xb5\xa6\x05\x038\xe1{\xea#\x9a\x16\x83\x10\x02%\x07\x0e"\ \x1c\x0e\x1d\xdb\xa4\xb6\x92s^\xear\x16B\x08\x81\'\xcbO\x10\x8f\xebkm-\x9e\ \x9e\xb4\xe0\xb6\x16\xcfc\x00\x17\x87G\x86\x84\xddn\x87\x10\x02/\x1f|\x15\ \x03\x83}\x8f\x00 ##\xe3\xfa\xf1c5`\x8c\x81R\x8a\xf1\xdbc\x88\xc5\xa2\xa5\ \xc9\xd0T\x8a\xd1\xd6\xe2\xa9\xd74-\xf0\xf0\xcf\xfb\x82\x10\x82\xdc\\\x07B\ \xa1\xe0\xde\x0b\x17\xcf\xf7\xec\xdc\x91\xb5]Ul\x10B`\xea\xee\xefP\x14\xa5?!\ \xe6\xd9\xe0\x845\xfe:9A\xb6m[\x87\x1c.\xafDff\xe6\'\x05\x85E\x10B@\x92\x08\ \x16\x16\xe7\xf5\xd3M\xcd\xefm\x91\x9f\x1a\xdc\xd6\xe2\xe97Ms\xfc\xe7;\xb7M\ \x8b\xc5\x02Y\x96\xa1(*8c \x84\xe0\xc7\xd1\x1f\x10\n\x85\xaa\xb7\x82\xa6S\ \x0c\x00\x1f\xfc=\xfb\x97\x00\x11\x10B\xa0x\xef\x8b\x88D\xc2\x98\x9d\x9b\x05\ \xb5X\x1e\xa4\xdbJ\x00\xb0l\xe5\xb89:\x16\xa8\xae9n\xfbwf\xa6\xb2\xb8\xa4\ \x14\x86a@\xd7u\xf8\x1f>\xc0\xa9\xc6\xa6]\xe9\xa0\xcfR\x8c\xe2\xcf\xda\xf5\ \xf8\xdc\x1c\xa6\xff\x98Bqq1\x89\x85B\xf0\xcd<\xc2\xb0\xd5\x9ar#7\x1bI~\xb8\ \x0c\xb8w\xa8j\xbbDHm\x9c1u\xff\xfe\x97\x88\xdff\xc3?\x93\xbf\xa1\xa0\xec5\ \xe4\xc4b\x98\x9e\xbe/\x14J5S\x88\xc1\x80\xa6}Q\x07\xcc\xa5\x05\x0f[\xad\x8d\ \xb2\xc5\xf2yQVV\xbe*\xcb\x90\xa5\xf5\x82&\xe7\xe7E"V\x94\x15\x16\x12\x000L\ \x13\x9aa\xe0\xf1\xea\xaa\xd7\xe0\xfc\xcb\x13\xba~.e+\x86\\\xce\x1a.D\xeb>\ \x87#\x7f-\x16\xf3O{\xbd\xab\xfeh\x14\xcb\xe10t\xce\xcf\xd0\xda\x93\xe7u\xce\ \xcf,\x87\xc3\xf0G\xa3\x98\xf6zW\xd7b1\xff>\x87#\x9f\x0b\xd1:\xe4r\xd6\xa4\ \xeeq4Z_\xe1v\xbb\xfd\x91\x08\x96\xc3\xe1\x01\x9d\xf3^\x9b,c)\x18\x84\t\xdc=\ \xd97\xd8\x00`j)\x18\x84M\x96\xa1s\xde\xbb\x1c\x0e\x0f\xf8#\x11T\xb8\xddnD\ \xa3\xf5\xa9\xc1\x86\xf1\xbcJ)"\xba\xce|\x9c\x8f(\x946\xd8\xadVH\x84,\x9e\ \x02\xae\x01P\xeb\x80\xef%B\x16\xedV+\x14J\x1b|\x9c\x8fDt\x9d\xa9\x94B\xe8\ \xfa\x0b\x9b[K7> \x06s\x055\r\xdbU\x15%\x94\xdepegcji\xc97\xcf\xd8\x00\x00\'\ \x00\x01\x00\xf3\x8c\xf5\xc3\xeb\xad{\xc5\xe5\xda\xb5\xb0\xb2rC\xa6\x94\x055\ \r\x12\xe3N\x00*\x00\x03\x00\x97\x12\xbfHVJ/-\x04\x02\xc8\x90ejS\x14\xdc\xf3\ z\xb1"\xc4/\x1f16\x08 ;q\x1cM\x8c]y*\xc4\xc4=\xaf\x176EA\x86,\xd3\x85@\x00&\ \xa5}\x00\x14\xac\xef\x06\xd9\x90n\x01@\xaf\xa8j\x8b$D\xb5)\x04\xf1\nq\xf3\ \xb4a\x0c%|fR\x85\xac\x9b\xd2\xda=\x92TM\t\xe1qBn\xbd\xafig\x01\xb0\r\xc5\ \x9b\xc7\x8dl\xa8O\x1c\n@\xc6\xffGr\xa3B3\x01\xe1\x9bn$\xdae\x02\xc0\x7f\xa7\ \xeb\xd5\x9f5w\xb0\xfd\x00\x00\x00\x00IEND\xaeB`\x82' def getCutBitmap(): return BitmapFromImage(getCutImage()) def getCutImage(): stream = cStringIO.StringIO(getCutData()) return ImageFromStream(stream) def getCutIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getCutBitmap()) return icon #---------------------------------------------------------------------- def getIconData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x02\x00\ \x00\x00\xfc\x18\xed\xa3\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x01\xf9IDATH\x89\xddV\xd1\x8d\xdb0\x0c\xe5\x1dn\x0ck\x0fk\x10f\x8fc\xe6\ \x88\xbc\x07=\x88\xb4\x07\xb3\x07\xfbA\x87\x92m\xd9\xe7\xa2\x08\x8a\xf6!\x08\ ,S\xe2#\xf9(\xc9\x1f\xaa\n\xef\xc4\xe7[\xbd\x03\xc0\x17\x00\x94RRJ\x00\x90R\ \x1a\x86\x01\x00\xee\xf7\xbb\x88\x10\xd18\x8e\xd34\xe5\x9c\xdb51FD\xb4\x99\ \x86v\x0e""b\x9d\xad\xaa\xaa\x1ac\x04\x00"RU#s\xd3j\xf6\x0b\x88\xa8/\x84\x10\ 6V\xf3cX\xbc\x18\x7f\x08!\xe7l\x0br\xce-\x013\xdbPDZz\x8b\x06\x11m\xbe\xe7\ \xe1\xcb\xc1\xa9,\t\xfbo\x03\xdc\x10xS\x1cY\xed\x8d{\xa8\x04\x1eZ\xcb\xef\ \x0b\x88\x88\x99\x99\xd9\x87\xaa\xca\xcc-Y\x17+\x9bW\xb3}\xd9\xd5@D.\x12\xd4\ 6-\xa5x\x12\xf3<\xefu\xb3\x0c\xac\x86\xd34\xedY\xfb\xf0\xfax\xf5M\xed#\r,j/\ \xb1YSJ>\x7f\xa3\xe2\xa7\x87\x9csFDf\x0e!\x88\xc8\xedv\xbb\x12\x9f\x11\xcc\ \xf3\\J\xb12X#y\xf5@U7\xad\xe9\xadf\x85\xeef\x10c\xf4\x90\x89h\xc3\xda6\xd5\ \x97\xf9\x1d_\x00\x80q\x1c\x89HD,\'K\xd9\xf5\xb7m\xdc\xba{<\x1e\xc30\x1c\xed\ \xe4\x0f\xfd\x1f\x0e\xbb?\xc7\xf3\tV\xa1\xce\x9e9\xd9#\xd7\xc1\xac\x00\xdau\ \xf6\xf6\x12\xfdU\r\xe6\x19J\x01;>b\x84\x18a\x1c\x17\xd3\xf3\t\xd3\xb4\x98B\ \xa8\xef;8*k\xceKY\xfd\xd7\x1c\x1fJ\xb42\xc5x\xa8\xc1!\x81\xafd\xae\x1a\xda\ \x01\xe3C"e^\x91]%0\x17!\xa8\xdf\x0b\x88\x8b\x0b\xe6\xe5\xb99,\xce28\xd3@\ \x04b<\xb4~\x7f\xaf\x9e\xd7\xdf\x05\x15g\x04]\xf5v7\xfc\x0f8#\x18\x06H\t\xec\ \xeb\xc4\xda\xa9\xa5,\xa5\xee\xdbR\x8e\xbdt5\x10\xa92\x1aB\xa8"\xa7\xb4XM\ \xa1\xb6\xdf\xae\x8a\xac\xbbFl\xd7\x8bTU=\x8e\xdf&PU\xe6\xea\xa8\xb9B\xb6\ \x1cm\x1f\xef\xf1\xef\xdf\x07o\'\xf8\x05\x02\xba\x08\xf5X\n-\xd8\x00\x00\x00\ \x00IEND\xaeB`\x82' def getIconBitmap(): return BitmapFromImage(getIconImage()) def getIconImage(): stream = cStringIO.StringIO(getIconData()) return ImageFromStream(stream) def getIconIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getIconBitmap()) return icon #---------------------------------------------------------------------- def getLocateData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x03+IDAT8\x8d\x85\xd4\xcfoTe\x14\xc6\xf1\xcf\x94N\x0b\x9dD\xa6\xc0\x15HL\ \xe4\xc5\x04c\xc0t\x8c&,f\x01\x04Cwn\x8dIM\xfd\x13\x80\x85+\x7f\x90\xb8\xd7n\ ]\x18\xc1L\x0c\x1b#ac\xc0M\x17\xce\xc2\x15c\xc4D$\xe1-Qca\x18\xa6E\xeem\xa9\ \xd0\xba\x98;\xd3\x99\xb1\xe0Inr\xdf\xfb\x9e\xf7{\xcfy\xce{N\xc13,T\xc3|r(9\ \xb6\xd5^\xd6\xca\\\xbf|\xbd\xf0\xb4\xb3[n\x84j\x98C\x05Sv+\x1b\xdb\xc2\xa9\ \x855\r,\xc7z<\xfe\xbf\xe0\x1c:\x9b\xbc\x9e\x94\x8d\xd2\\lr\xdb<\x0e\xe4\xcf\ \x05\x93fM\x90\xbc\x90\xc8\x162\xe9\x9d\xb4\x11\xeb\xf1\xb5\xa7\x82\xfb\xa1\ \xcd{Mn{\x07\xbfc\x11_\xe0\x18\x8e\xa2\x88\x92IWJ\xfbK\xb4\xfc\x07>\xfa,h\ \xac\xc7\x8b}\xfb\xbd\x00b=\xd6\xf3o\xd3\xa9\xf4Ji\x7fII\xa9\x12\xaa\xe1Z\ \x17\xde\x03\xa3\x92\x1cM\xcay\xea=h\x98\xc9\xf5^3e\x1dE\x9f\x87\x10\x96q:\ \xd6\xe2\xd5ax\x176\xd2\x17\xedT\xf3\xee\x96\xd0\x06\xcei[\xb0\x84\xd4\x05\ \x9c\xc3\xe90\x13*\xb1\x1e\xafj\x9bN\xffJ\xa5\x0fR\xa1\x1a\xae\xf5\xc0\xddh\ \xad\xb3\x05\xf4R\xac\xc5y\x99e+hi\xc4Z\x9c\xc7\xdc\x00\x1cv\x91\x1cJ*\xfd\ \xe0\x8e\xdd6\xdb/\r\x16b-.\xe5\xeb\xd38\x91\xffL\xac\xc5\x86\xce-)\x83\xb6i\ \xd9\xe6\xe1~\x8d\xe1\xddP\r'\xf1\xa25S\xda>\x0b\xd5\\\xcfzl\xf4\x15rS\xf7M\ \x9f\x01\x1b\x06\xbf\xd9{[\xc7\x86n1\xcaC~\x15\x1c\x1b\xf2\x19\xb0\x91\xa1\ \xf5l\xac\xc7B\xac\xc7\x82\xa2\x86\tg\xfa\xd3\xef\xb3\x8e,\x83>'\x9e\x1e\xf1\ \xa4\x0b\xf8\nl\xb3\xec9\x8dx9\xce3\xd0\xe6=YB\x08=\x9fp2l\xd8\xbeE\xc4\xd9B\ \xc6\x04\xa1\x1aNA\xac\xc5\xe3x/\xcc\x84n\xaa\x9d\xf4sY\xf2[s\xbe\x97\xcd\ \x0ed\x9d\xe1D\xde\xd2\xa1\x1a*\xf8\xd2~\x15\xabh\x9b\xee^\xa10\x13\xce\xe3@\ \xde eE\r\xdb,\xe7\xd0K\xb1\x16\x97\xc2\xc9\xb0a\x12KXq&\xd6\xe3\\oVtGd3m\ \x92\xe1\x9e\xb7\xdc\xf1\x036\xb0\xddK\xbe\xc7\x11E\x1f\xd9\xe6;k\xfetS\xcbA\ \x8fLR\x1a-\x91\xe9\x8d\xd2\xcd\xe2\xad;\xdb\xbc\xd1\xfc9)%L`\x8f\xcb\xf68\ \x95\xd7aT\xe6o+h\xfb\xd1/n\xb9iu\x18\x9a\xdeK\xcf\x86j(\x0f\x82\x17\xfda\ \xd5\xfb\xcd\x1b\xcd\xeb=\xf8^\x17\x1d\xd6\xf4\xbc7\xf2\xc8Y7\xee\xa0\x96\ \xc3\xee\x0f@\xef\xa6\x1fx\xe8\xdbX\xef4\xd4\xa6\x14!\xec\xc5\xb8]\x0e\x19\ \xf7i\xf2r\xf2*\xf4\xa4\xe9\xb7\xed\x1d\xe0\xc4\x8e\tY+\xeb@S_{\xe8a\x8c\xb1\ 9\x0c\xde\x97\xa7]\xb0\xdbA#\xcaF}\xd2\xfd\xc1\xb0\xf5\x80O\xfcj\xc5OR\x0f\ \xf08\xc6x\x7f\x18<\xa6#\xc0N\x9dA\xbe\xa6\xec\x88\x11;\x15\xac\x1b\xf3\xb1\ \x82W<\xf1\xa1\x7f\xdcR\xf0X\xea7\xab\x161\x86\x07\xc8b\x8ck\x03\xe0\x1c^\ \xc8u/b\xdf\x18q\xd4#ok\xb9\xda\x11\xc4\x08\x1e\xa1\x8d\x8d\x18\xe3\ F\x97\xf5/\xb7arI\xda\xd1{\x91\x00\x00\x00\x00IEND\xaeB`\x82" def getLocateBitmap(): return BitmapFromImage(getLocateImage()) def getLocateImage(): stream = cStringIO.StringIO(getLocateData()) return ImageFromStream(stream) def getLocateIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getLocateBitmap()) return icon #---------------------------------------------------------------------- def getLocateArmedData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\ \x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x01~IDATH\x89\xb5U\xc1\x8d\xc2@\x0c\x9c\xe5\xeeO\x07\x14@\x03@!H\x14\xc0?\n\ \xd4\x91D\xfb\xa7\x00$\n\x01\x1a\xa0\x00:\xa0\x82\xbd\x07\x1a2\xf1z\x838\xdd\ \xcd3vf\xec\xb1\x9d\x840\xf9\xc2\x7f\xe2\xfb]\xc2f>Kc\xf1\xe3\xed\x1e\xc6\ \xe2\xa1\xd4\x81\x12WS\xff\xe5\xf8x/4\x19#\xaf\xa6=\xf9e]!>\x9e\xa4\x97u\x05\ \x1b/u\x9a\t(9\x89I\xa8X\x9d\xefA\x85J"\x03\x01\x8f\x1c\x00\xea\xdd>\xd4\xbb\ }fA\xbd\xdb\x87\xd5\xf9iMId0\x83\xcd|\x96<\xf2\xf3\xcao\x9f\xe4\x00\xc0\x9c\ \xf8\x00\x16\xdb\n,\xe8\xd5\x81*[r\xda\xa13\xb8\xac+\xa8\xb0\x8a]\x0f\xd1\ \xb7H\xb7E\xc9\xbb\xb6I\xd6"\xdac\xbb#G\xd76)\x13\xd0\xea\t%?\xde\xeea\xb1\ \xcd\x07N2\xed\x82\xc8\x0e\x8d\xed\xd1\xb2\xeb!b3\x9f%\xee9\xc5\xd4R\xe6d\ \xca^\x07%\xb0\xcaO\x91u0\xb0\xe0\x14\xe1Y\x02<\xed\xea\xda&e9\xa78\xc8\xcb\ \x04\x96\xa7\xf8\xf2\x92\x03\xb4\xb6\xa8]\x9a\xe3\xad\xf3\xc0"~[thKS\x91\xc6\ \xb9e\x1e\x07Q<4\xef\x88,t\x85\xed\xa1\xb1\xabL\x00\xe8wYE\xba\xb6I\xdc0\xf5\ \xdc\x923\x9e]2\xd0{\xcbD\xad\xdc;\xb4\x12\xb9"[SO\xc4\xb3H\x9f[r-\xe6\xcf~8\ \x1e\xf9\xa8\x000\xf4\xbd\x04;\x0f\x1b\x1f\x15P!\xa0\xff\x8cX\x9f=\xe2\x8f\ \x04\x08\xda\xa6[\xf2\x0e\x1f\t\xfc\x06?%\xb3\x0b\x14\x95x1\xa9\x00\x00\x00\ \x00IEND\xaeB`\x82' def getLocateArmedBitmap(): return BitmapFromImage(getLocateArmedImage()) def getLocateArmedImage(): stream = cStringIO.StringIO(getLocateArmedData()) return ImageFromStream(stream) def getLocateArmedIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getLocateArmedBitmap()) return icon #---------------------------------------------------------------------- def getMoveDownData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04\x15IDAT8\x8d\x8d\x94Mh\\U\x18\x86\xdfs\xe6\xde\xc9\x9d\x9b\x99\xc9\x9f\ \xa9\x06zf&\x18\xac\x82\x84t\xd9E\x82i\xc9\xc0$]\x14\x11\x14l\x17\xe2Bq\x11+\ t\xa1`q!\xa8\xbb\xa8\x88(\xf8\x83\xd4Eu+\xed\xe8H \xba\x91\x9a\x8dJ\xb5\x15\ \xb4\xb9wN\xc8LM\x82\xb9s\xe7\xfed\xee\xcf\xe7\xc2\x19\x1c\x92\x9b\xe2\x07\ \x07\x0e/\xefyx\xcfw\xbe{Y\xa5R1\xaa\xd5j\t\x07\xea\xd4\xa9S\x9fLNN\x9e\x1d\ \x19\x19I5\x1a\rWJ\xf9\xd5\xfa\xfa\xfa\x0b\x07}G\x95\x92$\xce\xcc\xcc\xbc\ \xbd\xb8\xb8\xf8\xf8\xc2\xc2\xc2\x10\x11\xa1\xd1h\x8c\xae\xae\xae>\xc99\xb7\ \xee\xde\xbd\xfb\x8ea\x18\xcd\xff\x03\x1e\xacT*\xe7{\x82\xef\xfb\x0f\x00\x98\ \xcd\xe5r\xd9\xcd\xcdM\xf8\xbe\x0fEQ011\x91\xcf\xe7\xf3'vvvR5!\x1e\xc90\xa61\ &`w\xb6^\xdfL\x02\xab\x00\xae\xf4\x04M\xd3\x00\x00\xa6iF\x9e\xe7!\x9dN\xc3q\ \x1cH)\xd1\xe9t\xc0\x18\xcb\x02\x98W\x80\x13\x9c\xb1g\t\xf8\xe3\x87B\xe1\xa5\ \x10\xf8{\xb6^\xff\xa9\x1f\xbcW\xadV\x87\x0f\xb4\xe2=UU/\xd8\xb6\x9d\xd74\r\ \xb6m\xa3\xd9l\xda\xadV\xeb\xcf \x08\xec\xb2\x94\xefw\xad/\xae\x15\n\xcbY\ \xc6>\xcb\x00\xf6\xf7\x85\xc2\x13s\xf5\xfa\xad\xc4\x1e\x17\x8bE\xb5\xddn\x7f\ *\xa5\x1c\xb7,\xebt&\x93I\xb9\xae\xeb\xb5Z\xadU\xd7u\xbf4Ms\xab\xdf\xdf!\xfa\ \xb0\r\xb4\xb3\x8c}<\xc4\xd8\x9bk\x85\xc2\x1b\x1d\xa2\xdb\x87\xc0\xa6i\x06\ \xa5R\xe9\xe7V\xab\xf5\x9a\xef\xfb_(\x8a\xa2\x84a\xe8\x07A\xf0{\x14E\x1b\x07\ \xfde)\xf7kB\\m\x11\x15\x879\x7f\x99\x017\xcbR\xfe\x988\x15D\x14\x03\xe8p\ \xce\xf7UU\r\xe38\xf6\x01\x04\x8c\xb18\xc9_\x96\xd2\xad\t\xf1\xfan\x1c?t\x1f\ \xe7\xe7W\x85P\x0f\x81K\xa5\x92\x92N\xa7\x1f>~\xfc\xf8+SSS\xe5\xa1\xa1!ekk\ \xcb5\x0c\xe3\x9b\xbd\xbd\xbdw'''onll\x84\t\xf0\xb0&D\x08\xa0\xc8\x80\x99C`\ \xc30\xc2\x93'O>\x7f\xe6\xcc\x99\xb3\xf3\xf3\xf3\xf98\x8e\xb1\xbd\xbd=\xbc\ \xb6\xb6v\xee\xc6\x8d\x1b\xbb\x9e\xe7\xad\x00\xd8:x\xae\xbf\x18PV\x00\xe4+\ \x95\xca\xc5\x9e\xd8\xe9t\xc6\x89h.\x93\xc9\x0c\xf6F\x8cs\x8e\xb1\xb1\xb1\\.\ \x97{pww7_,\x16\x1b\xa6i\xd2\xbd\xe0\xbd\xc4+=!\x9dN\xf7\x92G\x9e\xe7a``\x00\ \xedv\x1bRJ\xec\xef\xef\xdf\x8b\x05\xd6]\xd4\x05\xb7\xaa\xd5\xeah\xbfazzz\ \x85s\xfe\x8cm\xdbC\x03\x03\x03p\x1c\x07\xcdf\xd3\xb2,\xebv\x18\x86\xd6Qi{)\ \t\xc9s\xac8\x8e\xf3\x91\x94r\xcc\xb2\xac\xb2\xae\xeb\x8a\xe38\xaem\xdb_{\ \x9ew5\x8e\xe3\xed\xa3\x12\xf3nb\x9e\x046M3,\x16\x8b\xb7l\xdb~\xd5u\xdd+\xa9\ T\x8aEQ\xd4\x89\xa2\xe8N\x1c\xc7[\xa6i\x1e\x9a\x08\x00\xa8\t\xa12@\xe9^\xc5K\ \x9c\xe3\xeeU\xeb\xdd\x95X5!Re)\xa3\xee~X\x01\xde\xcar\xfe\x94E\x84y)\xf5$\ \xb0\xc6\x18\xd3\x88hO\xd7ur]w\xa9\xab_\xe3\x9c\x97\x88\xa8AD\x9d\xb2\x94QM\ \x88\xdf\x00\xcc\xa5\x19\xbb\x9ce\xec\xb9\xd4\xbf\x7f\xbbu$\xb5\x02\x80OD>\ \x80\x1e\xf4zW_\xd24\xcd\xf0}_\x10\xd1fM\x88\x16\x07\xda\xa3\x9c_\x8e\x81e\ \x05\x80E\xf4\xddc\xf5\xfai\x00P\x82 \x18\x06\xb0\xd8=|\xbdo\x7f\xbe\x0f\x8a\ \xf1\xf1\xf1\xc0\xf7\xfd\x8b\x1f\x1c;v\xae\xa4\xaa\x97r\x8ceU\xc6r\nc\xcbN\ \x1c\xc3\x03\xbe\x9d\xab\xd7\xcb=?\xe7\x9c\x07\xba\xae_\xd3u\xfd\x1a\x00\xf4\ \xed\xb5\xfek\xd8\xb6\xddp\x1c\xe7\xd8_Q\xb4\r\x80B\x80u\x88`\xc5\xf1/6\xd1\ \x85\xd9>(\x00\xa0R\xa9\x18G\xbc\x0f\xf5\xa5\x07c\xeci]\xd7\x89s~?\x00\xd4\ \x84\xd8\xab\ta\xd4\x84x4\xe9pR\x8f9\x80\x18\xff}DK\x00@D\x9f\xbb\xae\xcb.\ \x8d\x8ej\x0b\x83\x83\xa9\xb2\x94\xc3\xdd\xc7\xfb5\t\xfc\x0f\x05`\x02\xf8(\ \x82\x9al\x00\x00\x00\x00IEND\xaeB`\x82" def getMoveDownBitmap(): return BitmapFromImage(getMoveDownImage()) def getMoveDownImage(): stream = cStringIO.StringIO(getMoveDownData()) return ImageFromStream(stream) def getMoveDownIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getMoveDownBitmap()) return icon #---------------------------------------------------------------------- def getMoveLeftData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x03\x9bIDAT8\x8d\x9d\x94\xefk\x1cE\x18\xc7\xbf\xb3?\xce\xdd\xad\x97n.x&\xe8\ \xf6v\x11QB\x89\xe7\x0b\x91\x14|S\x88\xb8\xa9H\xda\xbc\xe8\x1b\x85\xfaJ,\xbe\ \xf0\x85\xbe\xf0\xbd\xda7\xa2\x15}S\x11E\x14\x05AA\xb49\x9a\x98\x7f@\x03!\ \x05E\x1a\xcc\xed\xde\x06\xee\xd2\xf4\xd2\xbb\xbd\xc9\xdc\xde\xed\xee\xac/\ \xba\x176\xcd5\t>0\xcc\xccwv?\xcfw\x9f\x9d\x19b\xdb\xb6S\xa9TL\xa4a\x9a\xa6\ \xe88N<==\xfd\x95eY/\x8f\x8e\x8e\x8a\xf5z\x9dy\x9e\xf7+\xa5\xf4\xb3 \x08nU\ \xab\xd5\x18G\x84t\xbf\xe08N\\.\x97\xaf\xce\xce\xce^\x98\x99\x999\x99$\t\xea\ \xf5zayy\xf9\xe2\xca\xcaJ\xbb\xd7\xeb}\n\xa0q\x1c\xf0\t\xdb\xb6_\x1d\x08A\ \x10\x8c\x038\x9b\xcf\xe7\xf3\x9b\x9b\x9b\x08\x82\x00\x92$abbbddd\xe4\xa9f\ \xb3\xa9\x97J\xa5-\xd7u\x93\xa3\xc02\x80o\x07\x82\xa2(\x03\xe7\xbc\xdb\xed"\ \x97\xcbaww\x17\x9e\xe7\xa1\xdf\xef\x83\x10r\x94\xd9=p\xabR\xa9\xe8Y\xb1\\.\ \x7f.\xcb\xf2k\x94\xd2\x11EQ\xd0\xe9t\xd0h4:\xbe\xef\xff\x1bE\x91\x7f\x94\ \xdb\x01x_\x94J%\x99R\xfa\xb5\xe7y\x8f\xb4\xdb\xed\xb3\xaa\xaa\x8a\x8c\xb1\ \xae\xef\xfb\xcb\x8c\xb1\x1f9\xe7w\x8e\xe3X\xb8_p]7\x8c\xa2hmuu\xf5b\xab\xd5\ z7\x8e\xe3;\xdb\xdb\xdboRJ?\x08\xc3p\xcdu\xdd\xfeq\xc0\x07\x1c\x03\x80\xe38Q\ \xa9T"\xc5bqA\x92\xa4\xb7\x18c\xbf\x01H\xb2%0MS\x96e\xf9iUUOI\x92D\x82 \xe8\ \xf4\xfb\xfd[\x9c\xf3\xad\x8d\x8d\r>\x14\x9c:O&\'\'y:\xe6\xd95\xd34eM\xd3\ \x9e7M\xf3C\xd34O+\x8aBj\xb5Z\xdb\xf3\xbc\xef}\xdf\xff\xc2\xb2\xac\xda\x03\ \xc1\x87\x05!\xe4\xb1|>\xff\xde\xdc\xdc\xdc\x99\xa9\xa9)1\x0cC\xd4j5}ii\xe9\ \xf5\xb5\xb5\xb5\xad \x08\xbe<\x0e\xb8h\xdb\xf6\xdbY!\x08\x82\xc7s\xb9\xdc3\ \xa2(\x8a\x8e\xe3 \x8a"\x00\xc0\xd8\xd8\xd8\x98\xa2(O\x8a\xa2\xf8\xd0Q\xe0]\ \x00\x06\x80O\xb2\xe2`\xaf\xaf\xaf\xafC\xd7u\x08\x82\x00\xdf\xf7\xd1h4\xf6\ \x92\x1c\n\xaeT*]\x00\x07N\x84eY\xa7t]\xbf\xaa\xaa\xea+\x85BA\x14E\x11\xbe\ \xef\xa3^\xaf\xdff\x8c\xfd\x1d\xc7q\xf0\xbfj\xcc9\xafSJ?\xaaV\xabz\xb3\xd9|B\ \x96\xe5\x13\x94\xd2\x16\xa5\xf4\x87^\xafw\x9ds~(\x98\xa4-\xc9\xf4\tpo\xaf[\ \x96\xf5\xc7Kw\xef\xbe\xff\xc2\xce\xceV\x04\x18[\x84\x14\xae\x08\xc2"\xe7|\ \xc7u\xdd\x07o\xb7,(\xd3\x0f\x12\xe0Z\x14%"\xd0Q\t\xe9\xc8\x84|\xa3\xc6\xf1\ \xc7\x1b\x8e\xb3w*\x0f\x9c<\xdc\xbb\x94\x00\x00\x9a\xa6\xf5\x00\\H\xdb Q.]>\ \x17\x03\x9b2! @\x91\x00\x1bY\xc80\xc7\xe1\xc0%c\xec\x1c\x80\x85t>\x9f\x82\ \x8d\x1b\x86\xf1,\x80\xef\x04\xe0<\x80+i\xc6}?Y\n\xc3P\x070\x9b\xce\x17\xd2\ \xf1.\x80K\x19(\x00\xfc\x0c`\xfe\xda\xf8\xf8\x1c\x01\xde\xc9\x13\xf2\xb0@\ \xc8\xefQ\x92 \x06\xfeL\x80\x7f\xf6\x81\x05A\x085M\xbb\x0e\x00\x8c12\x18w\ \xbb\xdd\xcbIr\xf0v\xdc\x8e\xe3mK\x96\x93\x08 $I\xc0\x92\xe4&\x807^\xf4\xbc\ \x9b\xfb\x1e\xb4m\xdb\x19R\x0e\xa4\x9f=\x9b\x99\x0f\xea\xfc\xe8\r\xc38\xb3h\ \x18\xadE\xc3p\x16\r\xe3\xf4\xb0\x97\x87\xd5X\x00\xc0\x01\x10M\xd3\x12\xc6\ \xd8|\xaa\xff\x04\x80\x9c\xcf\xe7e\x0e\xdc\x16\x81\xe7\x00\xfc\x02\xe0\xafa\ \xe0\xff\x00\xe4(\xae\xfd\x8d\xec\xeb\xa7\x00\x00\x00\x00IEND\xaeB`\x82' def getMoveLeftBitmap(): return BitmapFromImage(getMoveLeftImage()) def getMoveLeftImage(): stream = cStringIO.StringIO(getMoveLeftData()) return ImageFromStream(stream) def getMoveLeftIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getMoveLeftBitmap()) return icon #---------------------------------------------------------------------- def getMoveRightData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x03eIDAT8\x8d\x9d\x92Mh#u\x18\xc6\x9f\xff|\xe4\xe3\x9f&m\x92\xad\xbbY7\xc6\ \x885\x85\xd2B\xa0Z\xea\x17x\tL{[\x8a.\x8b7=+\x08zP\x0fzs\xeb\xc1\xc3\xeaj\ \x0f\xab,\xe2\xc9\x9b\xe2\x06\x9aCE\x10\xb6\xd2\x83P\xb4RL\x99\xe9l\x9a\xb6i\ \xab\xce$o2\x9dd\xfe\x1eL\xa4\x0c\xc96\xecs\x1a\xe6y\x9f\xdf;<\xf32M\xd3\xf4\ b\xb1\xf88|\x9a\x9a\x9a\x8a\'\x12\x89;\xd9l\xf6\xd9H$\xc2*\x95\x8auxxx\xa3\ \xddn\xdf\xd9\xd8\xd8h\xfa\xe7\xfdR\x06\x19\x81@\xe0\xe3\xa5\xa5\xa5\xc2\xfc\ \xfc|\xb0\xddn\xc30\x8cD\xa9T\xfa`gg\xa7\x0c\xa04\x0c8\xa2i\xda\xab~\xc3q\ \x9c9\xcey`ww\x17\x8e\xe3@\x96e\xa4R\xa9\x04\x11\xf1L&\xc3\x0c\xc3\x10\xe7\ \x81U\x00_\xfb\x8d`0\x88r\xb9,\xe2\xf18dYF\xbd^G\xa5RA\xb3\xd9\x04\x00\t@\ \xe7<\xf0\xdf\xc5bq\xcco\xe4\xf3\xf9\xaf8\xe7\xd7\x93\xc9d@UUX\x96\x85j\xb5\ \xfa\x97m\xdb\x04\xe0\x81_\xdb\x03\xf7U\xa3\xd1xS\xd7\xf5+\xc7\xc7\xc7O+\x8a\ \x12n\xb5Z\x07D\xb4\xe2\xba\xee\x8f\x86ax\x0f\r\xde\xde\xde\xb6&\'\'_\xd9\ \xdb\xdb{\xd1\xb6m\xe4r\xb9\x8df\xb3Y\xdb\xda\xdar\xcf\x83\x02\x004M\xd3\xcf\ [\xce9\xaf\x0e\x05;#i\x88\x19\x06\xe0\xd2\x80l\x84s~\x04`\x01\xc0\x02\xe7\ \xbc\xd7}``\x15g\xc1D\xf4N\xf7\xb97\xdf\x96$)\x14\n\x85\xeaD\xb4\x08\xe0.\ \x00\x10\xd1"\xe7\\\x10\x11\x1b\x06,q\xce\x97\x89\xe8\x17\x00Q\x00\x8f\x00\ \xf8\xce\xf3\xbc%"b\xbe\xd9\xbbD\xb48>>\x1e\x1f\xa6\x8a\xffO\x8bs\xfe}8\x1c\ \xbe\xdd]\xf6\xf9\xa0\x80m\xdbC\xfd\xbc\xbeb\x8c\xf1n\xa7\x0bg^/p\xce\x85$I\ \x8f\rSE_\t!ZD\x14\xe7\x9c\xdf\'\xa2\x97\x01\x80s\xfe\x03\x11\x8d\x02h=4\x18\ \x80\x07\xc0\x8e\x9e\x9e>\xf1\xe5\xe5\xcb\xd7\x14\xc6\xc6\xde\xae\xd5R/\x8d\ \x8e:\xd7b1\xf7\x81\xe0\x99\x99\x99G3\x99\x0c\x8fF\xa3\xacZ\xadv\x8e\x8e\x8e\ j\x9b\x9b\x9bV\xcf_M\xa7U\x00\x8b\x12p\x03@h\xe5\xe2E\x00\xf8\xa4`\x9aN_p&\ \x93a###\xb9l6{kbb"\x1f\x0e\x87%UU\xeb\x8c\xb1\x95\xb9\xb9\xb9O\xd7\xd7\xd7O\ V\xd3i\x19\xc0\xeb\x00n\x86\x19\x83\x0c\xc0\x12\xe2C\x00\x8d\xd5t\xfaV_\xb0a\ \x18bvv\xf6\xfdB\xa1\xf0\\>\x9f\x0f\xb8\xae\x8b\x83\x83\x83\xd8\xda\xda\xda\ \x1b\xa9{\xf7~ZN\xa7\xff\xe8\x00/x\xc0M\x06@\x06\xe0\x02`\xc0\x9a\x00r\x00\ \xc2\n\x801M\xd3\xae\xfb\xe1\xae\xeb>\xc3\x18Su]\x87\xeb\xba`\x8c!\x16\x8b\ \xc5\xaex\x9e\x1bblRb\xec\x02\x80\x8f\x18pU\x00OY\x9eW\x02\xf0\x16\x80\xdf\n\ \xa6)\x94\xee\xb2o\xfc`UUQ.\x97E"\x91\x80\xa2(\xb0,\x0b\x95J\x05\xd9N\'y\n\ \xdc\x96\x85\xb8\xd0=\xf0V\x07\xf8\x16\xc0\xbb\x05\xd3\xfc\xb3\x97W\x004\x8a\ \xc5\xe2\xb8\x1f<==\xfd\x99\xa2(\xaf%\x93\xc9\xa0\xaa\xaa\xb0m\x1b\xfb\xfb\ \xfb\xb5_\x85\xb8\xff\xa4\x10W\x19\xfe;\x0b\x005\x01\x1c\x17L\xb3v6?\xf0*\ \x1c\xc7yO\xd7\xf5K\'\'\'\xcf\x07\x83A\xd6h4\xfe!\xa2\xe5\x9f%\xe9\xf7/L\xb3\ 5(\xd7\xd3\xbf\xc3\x11a\x17\xced\xee\xd3\x00\x00\x00\x00IEND\xaeB`\x82' def getMoveRightBitmap(): return BitmapFromImage(getMoveRightImage()) def getMoveRightImage(): stream = cStringIO.StringIO(getMoveRightData()) return ImageFromStream(stream) def getMoveRightIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getMoveRightBitmap()) return icon #---------------------------------------------------------------------- def getMoveUpData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04&IDAT8\x8d\x85\x94Oh\x1cU\x1c\xc7\xbf\xbfy\xb3\xfffwvS\x93\xd4\x83\x1d\ \xb2k\xda\xc6\xa2\xf8\xe7\xe4)iC\xe9\x96Mz\xf0,\xa2\x07\x11\x0b*\xd6\x83\xd2\ \x8a\xe8\xa1x\x10A!\x9e\n\x82H(\x14\x04\x11\xb5]\xbb D{\xb0\xb9\x94\x1e\x82\ \x15I\xd2M\x9e\x89I\xb31\xbb\x99\x9d\x99\xdd\x9d}\xf3\xf3\x90\xd9\xb0&\xdb\ \xf8\xe01\xbfy\x8f\xf9\xfc\xbe\xef\xcbw\x1e\n\x85B\x19\xff\x1d\xa2S\x18\x86\ \xc1\x00&\xc2\xc9\x9a\xa6\xf5\x01\x10E\xcb\xa2\x92e\x1d+Y\xd6\xef%\xcb"\xf4\ \x18z\x8f5\x15>\xd9u\xddI\x007\xc2\xf7\xc9x<\xbe\xc5\x9e\xf7\x98\x06\xe4\x00\ \\\x07P\x05\xf0$\x80\xb9}`\xa5T2T\x84\x10\xd2\xa9_\xea\x82\x02\xc0\r!\xc4\ \x85K\x03\x03\xe3\x04|\x9c \xca\x08 \xa3\x80\xab%\xcb\xfa\x14\xc0\xdd\xbc\ \x94\xbb\r\xb4 \x08"\x86a\\7\x0c\xe3zx\xfcN\xdd\xde\xab\xc2q\x9c\xc3\xfdB\ \x1c\n\x8f\xcaQ"d4\xedi\x93h:A\xf4Y\xc9\xb2\x9e\xda\x05G"\x91\xaa\xeb\xba\ \xe4\xba.\x01@W}\xadK=\x88\xe8\xbdx<\xfe\xfe\xebkk\xdf2\xf0\x96\xcd\\\xaf\ \x06\xc1\xdfm\xe6\xa9\x08\x11L\xa23q\xa2\xa9\x92e\x1d\x03\x00\xad\x87\xc7\ \xbb\xac\xd0\xc7\t\x00\x13\xcc\xfcI\xd8\xb0rV\xca\x1f\x00\xbc\x12\x00\xd5J\ \x10\\\xae3O\xb5\x01d\x88NF\x89\xa6K\x96u\xf8 p(\x94~\x0b\xbd\xa6p\xb6\xc2\ \xbd\xef\x01\x9c\xcbKYi1\x7f\xb4\x1d\x04W\x14\xa0\x11\xf0<\x80D\xafT`hhH\x13\ Bd\xe3\xf1\xf8\x89D"A\x9e\xe7\xb5\x9a\xcd\xe6<3//..\xb6\x01 /\xa5\x02\xb0\ \x18\xd6U\x00\xe7\x7f\xb1\xac\x91\x8c\xa6\x9d\xdab\xbe\xb7\x0f\x9c\xcdf\xf5h\ 4\xfa\xc4\x91#G.\x1d=z4\x9f\xc9d\xf4\xd5\xd5U\xb7\\.\xdf\xacV\xabS\x00\xee>\ \xecx\x0c8a\xa8\xf7+&\xa2\x81d2y\xfe\xf4\xe9\xd3\xe7\xc6\xc7\xc7\xd3A\x10`cc\ \xa3off\xe6\x85\xd9\xd9\xd9\xcd\x83\xc0\n\xf8\x93\x81\xc9\x00;?H\xbaP(\\\x08\ \xf7"J)\xbf\xddn\x9fL$\x12I)%Z\xad\x164MC\x7f\x7f\xbfi\x9a\xe6\xf0\xc3\xa0\ \xa1\xe2t\xa7\xee(\xfe\xbc\xb3 \x84\x80\xef\xfbs\xe5r\x19\x9e\xe7!\x16\x8b\ \xa1^\xafCJ\x89f\xb3y\x10\x17\xdc\x952\x1d\xc0v\xb1X|\xa4\xb3\x90\xcb\xe5\ \x1e5M\xf3\xe2\xc2\xc2\x82e\xdbv&\x16\x8b\xc1q\x1c\xac\xad\xad\xd5j\xb5\xda\ \x1f\xff\x03\x16\x8c\x1d\xfa>\x8f\x83 \xd8t\x1c\xe7K)e\x7f\xadV\xcb\x1b\x86\ \xa1;\x8e\xe3\xda\xb6\xfd\x93\xe7y\xd7\x0e\x94\x0c\xa4\xc2\x06\xad}\xe0\xa5\ \xa5\xa5v6\x9b\xbdW\xaf\xd7?\xf0\xe1\x01\xdf4\x98\xdf\xceK\xb9\x06\xec\xa4\xc2\x07\xf0u\x07\x1c\ \x89D\xe0y\xde\x9d\xee\x1c\xdb\xb6\r)%\x1a\x8d\x06\x98\x19\x00.\xb7\x81\xe7\ \x88y\x95\x81\xef<\xe67\xb1s\xd1ou8:\x00\xa7X,\x0evy<\x98J\xa5\xde]XXx\xdc\ \xb6\xed\xbeh4\n\xc7q\xb0\xbe\xbe\xbeU\xab\xd5\xe6\x94R[\x00^\xf3\x98\x1b\ \x00\x9a\x00\xeay)\xff\xd9k\xe9>\x8f\x99y\xd3u\xdd+\xcb\xcb\xcb\x87\xaa\xd5\ \xea\xa4a\x18\x11\xd7u\xeb\xdb\xdb\xdb?6\x9b\xcd\xabA\x10T\xceJ\xb9\xbe\xf7\ \xbb\xbd\xe3_-\xa6\xf0\x8d\x16\xb2@s\x00\x00\x00\x00IEND\xaeB`\x82' def getMoveUpBitmap(): return BitmapFromImage(getMoveUpImage()) def getMoveUpImage(): stream = cStringIO.StringIO(getMoveUpData()) return ImageFromStream(stream) def getMoveUpIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getMoveUpBitmap()) return icon #---------------------------------------------------------------------- def getNewData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x02EIDAT8\x8d\xa5\x95Mk\x13Q\x14\x86\x9fsfRi\x8b\x1f4m\xc6 \xb8r!\xe2J\x10[\ \xc1?\xe0\xa6\x0bW\xee\xc4\xadk\x11\xc4nD\xc5\x8f?\xe1\xc2\x8d\xb8\x90\xecE\ \x11\x045\xa5\x1b\x0b\xba\xb2\xd9\xd4\x90X("1\xa6\x99t\x8e\x8b\x99;3\xe9\xc4\ &\xa5\x07\x86\xdc9\xcc}\xce9\xef{/\x11\x0e\x19\x83\xf6\xb2\x00% \xf4\x83\x9a\ \xb9\xbc\xb8\xc5\xe3\xa7\x0f\xef\x03+\x07\x81\xaaD\x94O\xf4\xa8.t\xf0\xd4\ \xd8\xe9\xeb\xf3\xabW\x1a\xb7\xfc\xa0\xd6\xf5s\xdf\xad\xdc\xb9}wb\xa8Y\x08\ \xe1W\xa2\xee[B+c\xcc\xb0\xfd\xf3\xdb\r\xc3{7h/\xbf\xf4\xf7nh4\x1ax\x9e\x87\ \x99!"\x88\xc4C\xe5\xd7`\x94\xa4\xc9\x8c\xbe\xc1+McS\xd7\x10o\x8ec\xf3\xef\ \xb1\xe8\xd5u\xb1_k\xba\x17\xec\x00\x0ebf`\x86\x99a\x91a\x06\xb0\x8bJ\x07\ \x91\x1dL\xe6A\xe7\x00\x05\x8e\x00\xbb3\xc0\xf1\xb1`\x04p9\x15TA\xc4#\x92\ \xa3D, \x83\r\x08?@\xd4\xa6\xdf\xab#\xf6g\x1d\xd8\xfe/XU\xe3_\x11D4+&\x8a\ \x8aG\xc4Iz,\xd1\xb73\xd0_\xc5\x0f_\xb3\xf1}\x13!z\x014\x0b\x1a;h\xaa1\x02\ \x92\xd7X@\x05a\n\x93S\x84\x94\xd9\xe5\x1c\xd3\xb3%\xea\xeb\xbf\xb9p\xb6\xf9\ \x05\xf8[\xe8xu\xad>lV\xae\xfb\xf4\xc1M\xe1a:\x8by\xa7\x91\xa9\xf3t\xba%\xfc\ \xa0\xd6\xf5\x83\x9a\x15\xc0\x97..R\xadV\xf7hJ&\x87J\xf2\x9eL\'\x1aO\x95\x1a\ \x12\xc7H)Z\xadV\xbc\xc94\x96!\x1d\x9ft\x8a\xc4S\x92\x0f\n1\x12\xec\x1e\x13K\ \xbb\x1b\x92\'_@\x84\xc2\xd8\xa3\xc0\xe9&@\x13\xb3bMA4yw\xf9\xa4\xd98?\x1c\ \x85b\x9f>\x7f,t$\x12K\xe1\xa0y\x8d\xc5\x990\x0e\xbc\xb4x\x99J\xa5\x92\x9daM\ LD\x13\xe3\x04AQ\xcd\x9f\x92\xa2\x18#5\xde\xda\xda\x1a:n\xe4\xb4\x05I\x0b\ \xe4\'\x1b\x0b\x1e\xae\xa29\xf3\x12`L\xcbr\x1c\x00\x9cv\xa3\x99q\t\xcfY\x99\ \xddF\x93\xdc9\x9e\xb0\xe3\xd4uw\xb5\x196.\x9e\x82\xc9:\x0e\x82`\xbfZ\x13G\n\ \x8e\xa2\xe8\xc1\x93g\x8f\xee\x1d\x06\xf6c\xb3y\xd3\xadG\\\xc6}\xf3\xe3"\xfd\ 3\xfd\x07#\xfb\x93\xa3F\x9b\xc4\xaf\x00\x00\x00\x00IEND\xaeB`\x82' def getNewBitmap(): return BitmapFromImage(getNewImage()) def getNewImage(): stream = cStringIO.StringIO(getNewData()) return ImageFromStream(stream) def getNewIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getNewBitmap()) return icon #---------------------------------------------------------------------- def getOpenData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x03\x7fIDAT8\x8d\xa5\x95Ol\x1bE\x14\xc6\x7f\xb3\xde8k{\xdd\xc4q\xeb&i\x1a(\ \x8d\xa0\x904\x15*\xa8\xa8 !!qEB\x94"\x0e\x91\x90\x10g@\xaa\xb8\x01\x12p\x05\ n\x1c\xe0P\xa9P jS\t\x89\x1e*\xc1\x81\x03\xa2\x07\xf2\xa7&\tI[H\xa3D\xb6\x93\ \xb8\xc6q\xec$\xb6g\xe7q\xd8\xb5\x13\xd1&\xb4\xf0I\xb3\x9a}o\xf6{\xdf\xcc{oV\ \xb1\x03\xce}u\xf64\x8aaO{\x08\xb2\xd32\x00\x14\nA\x10\xe1\xa3\xd7_{\xe3\xdd\ ]\x17_\xb8\xf4\x8d\xdc\x0fJ\xa5\x92\x9c;\x7f\xb6\xa9\xc0\x1e\x1a\x1a:n\xf0.+\ e\xf9\xc1QD\xa3\x11K\xd7=\x00\xf54\xc5b\x81\xbe\xbe>\x8e\x1cy\x04\ \xcb\n\xf9DF\x10\x91\xe6\x1c\x04\xdb\xb6\xc9dsh\xad\xb7\x11{f\xb5\xd5i#\x99\ \xdc\x0b@2\xd5\xce\xc9\x13\xcfP\xa9T\x98\x9f\x9f\xe7\xd7\xd1Q\x9cHd\x9bF\x9a\ \x04\xad\xe10\x0f\xf4\xf6\xd2\xdf?\xc0\xf2J\x0e\xd7u\xb7\x88\xad\x90\x8a\xd5\ 6Ku\xc7qZ\x96Wr\xecI\xc4\x88D"\xcc\xcd\xdd\xa4\xae5G\x07\x07P\xe2\x9f\xb1\ \xb2\x14b\x04e\x81R\n\xe3\t\xa9\xfd\x9d\xcc\xcc\xce23;C2\xd9\xf1q\x93\xd8q\ \x9ct6\x97y2\x1a\x89\x11s]\x9e{\xf6y\xf2\xf9\x15\xfe\x9c\xbb\xc5Zy\r\x04\xbf\ \xdc\x8cA\x1ai\xb4\x14\xb6\x1d"\xe2DH\xa5R\xfc6u\x8d\x8e\x8e\xc4\'/\xbep\xea\ L3\x03/\xbf\xf2\xd2;\xc7\x06\x8f\xbd\xdf\xd3s0\xeaD[hOt\xf1\xf5\x954\xd3\xc5\ };V\x02\x80\x13\xf2\xabf\xd3\x0b\xdd\xe1{\xd8]\xbaj\x03\xb7\n\x85\xbf\xea\ \x87\x0e?\xc8\xe3\x83O0\xf2\xdde\x86^=\x8dRA\x89)\x05(\x94\xf2\x87\x9f8\xb6\ \xfcw\xc1\xa7_\\|\xd4\x06\n\xd5j\xad\xeey\x1e\xf1x\x9c\xab\x0b\x0eGk\x86\xe9\ LeW\xc5;\xa1;\xe1P\xae\x8a\xb6\x80\xa9|~\xb9\xeeiM&\x97!\x1c2\xff\xda\xc2\ \xbb\xa1T\xb8-\x9b:\xb4h]\x18\x1e\xc9:ND\xe2\xf16\xcak%\x8e?v\x00\xf9\x8f\ \xbcm\xd1\x16*\x1bU\xd3S\xf9\xf1\x8c\x05PZ]\xad\x1a\xd1|\xfb\xfd\xcft\xa5\ \x92\x147\x9a\xf6hk\x88\x85l\xbe\x0eL\xd9\ \x00176\xfa\xc7\x8d\xb9C]=\x87q\xf7\xf5\x92)\xd6\xd8\xd4A{\x06]&\xc1\x1dFc\ \xa6\x1a>\x1f\x1dn\x0b\xda\x13\xd2\xd37\x17~\x1a\x1e\xc9\xda\xfe\xc7\x8c\x97\ \xcb\xe5S\x9d\x0f\x1d\xa4P\xd6d\x0b\xd5\xad\xfd)\x01\xf1\xafE\x15\xcc}[\xe0\ \x03\x10E\xcd\x13\xc6\xc6\xd2\xf5\xd4\xfa/\x1f\x02\xd8@\xeb\xe2b&\x1d\xdf\ \x137\'\xbaS\xd6\xd4\xb2\xdeR\x1bDm<\x1b\x05\xd6\xd0\xde\xf0\xa5\xdaZ\xa9{\ \x86\x99\xe9\xf4\xca\x0f\xc3#_6\x88\xf7NNN\xc6:\xbb:\xad+\xbf\xaf\xdf\x99\ \x11\xf1\x8f\x81mO\xd5T\xea\xfb\xb4\x16X\xcby\xac/]\x04,\xc0\xd8\xc0Z>\x9f\ \xbf~mb\xe2\x83\x98;\xfd\xde\xbdV\xc0?\xa1o_\xbf1q\xe9\xb3\xf3\x80\x0b\x94\ \x1a\xbbs\x80h`t\x83\xa8\xf7\x03\x01j\xc0:P\x006\xee\xd6\x97\x16\xbb\xfd2v\ \x87\x81\xff\xd1]\xf7\x82\xbf\x01\xa89\xd1d\xd8\xd4\x05\x1f\x00\x00\x00\x00I\ END\xaeB`\x82' def getOpenBitmap(): return BitmapFromImage(getOpenImage()) def getOpenImage(): stream = cStringIO.StringIO(getOpenData()) return ImageFromStream(stream) def getOpenIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getOpenBitmap()) return icon #---------------------------------------------------------------------- def getPasteData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x02\xadIDAT8\x8d\xa5\x92MHTQ\x14\x80\xbf\xfb\xe6\'-m\xd4q\xfcI\x84@Pr\x17\ \xe6\xc2MX\xe4\x88\xb4\xc8\xacM`;w\x91\xdb\xa6E0\xd4 m\xb2E\x14\x84\x13\x04\ \tnk\xe3\xec\xcaEI\x90.$\x10\n\x021Cg\xc6t\xde\xf39\xd3\x8c\xe3\xbd-\xe6\xff\ 9\xa3X\x07\x1e\xef\xde{\xee\xf9\xdew\xcf}\x82#btt\xf4\x03\xd0oY\x9e\x9b\x9e\ \x9e\xbetX\x9d(\x9e\xf8\xfdh+s8\x01R\xcd\xd7\xce\xdbO\x9c~\'\xa5\xf2\xf4\xf4\ t!Df\xabR\x8a\xc5\xc5oh\x9a\x88\xa6\x93;#\xce\xf0\xdb\x05\x80\xb3\xfd\xa4\ \xfc~\xe4\x01\xf0\xf8\x80\xed\xb6B>\x93\x92\x1a\x80?\xf5}Zsg\x9fhoo.k\xb4\ \xb6\x16e\xe3\xfb\xbc\xaa\xda\x9a\x97\n\xd0\x04\xa6\x92\xda\xdd\xe7\xef\xf7\ \xdf\x00\xd8s\xa6\xdb\x9f\xe4\xd3\x91\x8b\x1d\xae\xf0^\x13_\x8cn\x12\xc6>n\ \xb7\x87\x8e\x8e\xce\xbcCF:\xf3N&ac\xa3KT\xb7\x9d\xb3\xf5\x9e^\xc6E\xd85;\ \xffc\x12(\x80W\xe6p\xd6\xda\xa9s84\x16\xb6\xba\xf1=x\x8c\x1e\xd3\x99\x9c|\ \xc2\xd2\xd2rY\xe3\xda\xda\x1a|\xbe\xfb\xd47\xd43\xf1\xf0\x1e#-\x9bH%\x1aA\ \x91\x07\xe7\xfb\xa2\x04f\x12\xdc\rn\xec6\x1b\x81@\x80t:]\x16l\xb7\xdb\x11B\ \xe0r\xd5\x11O\x89\xd2\xcb\xb2\x82\xad!\x84\xc0\xe1pT\xcc+\xa5\x8a&G\x80\x8b\ \xf3\xa1P\xe8\x10(\x0c\x0ez+\xe6\x0f5\x1e\x1a\x1a*\x03T\xd9G"\xa5,SU\t\\\xa4\ l5.@\x15\xa0\x18\x18\x18\xf8?\xe3\x82a\xe6\x9d\x83\x1b\x86NSS\xcb\xd1`K\xff\ \x99\x9d\r\x01\xaa\xe4\xf8^\xaf7?6v\x8c\x8a\xb5\x16\xe3BZJ\xc9\xe0\xa0\xb7\ \xc4P\xcaL_sk\xd1H\xb4\xe2i+\xb6\xa2\x18P\xdc\x8a\xf5\xf5_\x98\xe6.\xf1x\x1c\ \xa5\x8esye\xc12k\xacX]\xfd\xc9\xf0\xf0\x8d\xfc>]\x8f\x1d\x17\xbc_\x02\xcd\ \xb7"k\xa9\xeb1\x0c\xc3\xc04w\xfe\xc5\xb8pI\xbb\xa6I$\x12Ae\xff]\xc30\x08\ \x877\x98z5\xc5\xd5\x96\xc5\xca\xe0\xdc\xb5\x9drJ\xa2\x9bQZ[\xdb\xf2\x9b\xda\ ,E\xba\x1e+\x81\xba\x9d\xbbG\x1b\xb7\xcb\xafL<\xf2\x11Oi\x95\x0e\x93\x8f\x9b\ m\x9f9iK\x95\xcd\xd9\x01^\xcf\x91\x1c\xbf\xc2\x96\x99H{.\x9c\xd1\xe9U\x1fK6Y\ \xff\xd1\x03! f\xa6\x01\x15)Z\xca\xc4\x9d\xcb\\\x17\x9a\xf6\x02\xa5<\xd6\x9c\ e\\\xf6\x9b\n\xb1-\xab\x9b\x03{-\xfd/\x83\xc1\x99\xc4\x81\x82\xb1\xb1[U\x80\ \x0b\xa8\x03\x1a\x007\xd0\x98\x1d\xd7\x00\t \x06l\x01\xbf\x81\xed\xec|\x1b0\ \x83\xc1\x19\t\xf0\x17\\\xc1\x87\x8b\xbe\x18\xff{\x00\x00\x00\x00IEND\xaeB`\ \x82' def getPasteBitmap(): return BitmapFromImage(getPasteImage()) def getPasteImage(): stream = cStringIO.StringIO(getPasteData()) return ImageFromStream(stream) def getPasteIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getPasteBitmap()) return icon #---------------------------------------------------------------------- def getRedoData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x02\xbdIDAT8\x8d\xad\xd2Kk\x13Q\x14\x07\xf0\xff\xb9\xf3Hkjk\x9f\xc6Z\xb1QD\ \x94j\xc1\xaaP\x10+\x15\xa5\xad2\x0bADp%2\x9f\xc1\xa5_\xc0\x85\xba\xcb\xc6\ \x85~\x82Y\xf8(\x14\x14\x94\xe2\xa2\xd8v!\x96\xdab-M\xd3\x04\x93\xb4I\xd3\ \xccd\xe6^73a2\x9d\xa4V\xbcp\x08\xcc\xb9\xf3;gN\x0e\xb0\xcf\xa3%T\xa1%\xd4\ \x83{\xddc\xfb\x85\xdd\xb3\xa5%\xd4\xf6\xff\x0e_\x19;\x0f\x00\xd9F\xf8\xbfv\ \xbc\'N\x8d^\xd6\x12j\x14\xc0C\x00\xcf\x83\xe8V%\x8dV\xa5\x07\x9f\xde\xcd\ \x03@\x87\xa1[\xb9\xbf\x82\xb5\x84:\x0e\xe0\xcd\xb8\xda;\xef\\\xee;[j)\xcb^\ \xaeR\xb1Q\xb4\xb20\x0b\x1c\xb1X,\x14\x0f\x85\xb5\x84z\x13\xc0\xfb\xdb\xa3\ \xc3\xd8nv\xb0\x99\xcf\xc1\x12;`\x8c@2\xc12M0\x99\x90Km\x83\x18\x10\x8f\xc7=\ \xfd\xa65\xd8\xd63LNU\xc2\xd0x\ \x08O\x02&\xd6\xe7\xa73E\xe6\xb0,\x01\xd9\x1e\x9e\x0f\x06\xc3k\x03\xc3\x93\ \xcc\x1d\x17\xe3]\x9e\x9dzC\xd7M/ >\x07\x80\x9b5\x15\xde\xf6\xfa\x8a\xb6+5\ \xe5\xe5\x86nm\xfc\xfdJ_\xfb\x89\x1f;\x82\xf1\x0e\x8e\xcc$\r\x97n\x8dB\x918,\ !Xd\xa11\t\xa8\x9aC\x1d\xca\xccH\xae\x8d\xd5\xec\r`\xbc\xcf"\x9bw\xe1\xc4\ \xb4\xd5Ut\xe9\x86yh*\xa0K1\x0e\x05C\xe3!\x08\x00v\x85\xc3\xb2\x88)B\x16\x00\ 0\xdbcK\x88`\xa2\xcb\xf1e\x8c\xc3\xfe\xb3\xae\xab\x8f)\xc2N\xc5,M\x9eZ\x08.\ \xaaj\\\xa5\xc8\xd2\xd9\xea\xb7\x8a\xd4\xa4x\ri\x89Nl.H\x86\xaaH0\x051\x9b\ \xb5\x00\xecHK\xcf9\x8b\xcb\xe2\xcc\xde7\x04\x00\xa0r\xc5\xa2\xf9.\xaajHc\ \xc4\x7f\xb3,\xd2\x8e\xb6\xb4GH\x10\x88\x00\xc2\xf4^\x08\xb2\xe9V@\x00s>\x90\ \xe2\xaa\xa61\x06\xb8\x16\xd1\x00\x10\xc1\xc7\xb8\xd8\xfe\xc4\xe6\xeeq\xf9F\ \x1cO\xab\x01\x00\x85\xa0\xb6\x9f\xda;J\x04\x92\xe7\x1c\x8fk\xf8d\x87l\x939\ \x00\x06\xc6\x80\xb0n\xe2\xe3\xba\xd6\xc8\xfd\x91\xc9\xf7\xaf\x1f\xdf\xdd\ \x1d\xad\x8bL\xdb\xd7)@\xbcVZP\x18v\xc7\xe8\xf1\xdd\xff>,\x1d\x1c}\\G\x84\ \xc4y\xad\x00\x11\xb3\xdbd\\\xb85\x02\x06Bi^\x12\x9a\xce\xdf\x89\x0c\x8c\xfa\ \x8e\xb6\x1d\xdf\xd5\xb0\xd0N\x16\xce\x14I\x15\xc7T\x87\xef\xa7\xc9\xb0H\x9a\ \xf0\xfb\xabl\xb2l\xcd\x9c\x9f3n\xd3\x96\x86)\x90\x91\xe8\x04\x03\xd0\xdd?F\ \x9c\xb1U\xc5\xef4/]\xf4\xdc\x12\x9e\xb3,\xb1a\xd2\x17\xdc}\xfb\xde\xe0\x87\ \xbe@8\x9bq\xdc\x9d\xbd\xf1\xac0\x881\x00kr\xe208\x1e\xc4\x90\x97\xe3\xc8\ \x81-\xf6\xa6\xf3=\xdb\xce]\xe9\xef)\xa9n\xfaJX\xd4\x01b\x03\\\xb1d"\xe9\x88\ CU\xe2z\xee\x0em\xb6)\x12\xb9c5\xc3;\x11\xaa_\x04\x9e\x96f\x08\x86t\xe4/\x89\ E\xc4\xb4\xd0y\xcf\x8bW\n3\xa5\xe2\xfct\xad\xe3\xce\xf0\x07\x9e\xc7\xbe\xb0g\ \xcc\xc7\xc6\'\x82N\xc9\xc6\x90\xe2\xd6\x90\x97\x93\x8c\xc48\'k\xfc\xa5+\xac\ \x99z\xe3"0g\x8c\xdd\x7f4\x85C5\x97&8\x03\xdf\xb1i\xb9m\xcb\xba,\xbb7`\xc2"\ \xa00/M.\xb0R]\x8cM\xf7\xcf\x10\x04\xd3\x14\x98\xf0G\xd0\xf8\xeb\r\xbfe\x18\ \x07/\x9e\xdc\x1b\x9e\x95$"0\xc6\xa4\xf5\x95\rF\xac\xd3\x16\xe8\xef\xba\xb8\ \xc3\xd3q\xe6Q\xee\x96\xca\x9d\xee%\xb9\xd5\xab\x9fO\xcb\xc8\xcfMQ2Sc\x99\ \xd3aC\xc4\x100L\x0b\x93\x01\x1d]\xbd\x1eq\xf5\xe6C=81r\xb8\xfb\xf4\xc1\x1a\ \x00a\x00a"\xd2g\xc0\xf6u\xfb\x1a\xbc~\xcf\xed\xb2\xdes\x9f\xfd\x03\xc0\x11\ \x8d=}\xed\xce5)+\xb7\x95+Z\xfcZp\xa6:U\xc5\x08FL\x89\x08\x10\x11\xdf\x9f\ \xa3}\xad\xc7\x06\xae6u\x03\x08E\x13$\xa2\xe0\x0c\x98\xad\xde}\xec\xcd\x9b\r\ \xfb/\x03\xb0\x03P\xe7D\x89F\x92\x9cn%!\xa3 !\xe8\x1d\xf6\x06F\xfb\xbc\x00\ \xf4\xe8\\G\xa2P\x1f\x80\x08\x11\xd1\xa2\xa5\x891&\xcd\x81\xcdD\x06 a\xfa7oE\ cD\xa3\x030\x89\xc8\x9a\xcb\xf9\x0f)i\\\x9ar\xdc\xdf`\x00\x00\x00\x00IEND\ \xaeB`\x82' def getRefreshBitmap(): return BitmapFromImage(getRefreshImage()) def getRefreshImage(): stream = cStringIO.StringIO(getRefreshData()) return ImageFromStream(stream) def getRefreshIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getRefreshBitmap()) return icon #---------------------------------------------------------------------- def getSaveData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04\x0fIDAT8\x8d\x95\x95]l\x14U\x18\x86\x9f\x99\xed\xfeLg\xdb\xeet\xd9ew\ \xebR\x96\x96\xa5\xc8\xdf\xb6\xa4h\xf1\x07k\xe2\x05F\x88\xc6\x88\x17zc\x88\ \x17\x80A\xaa\x12\x0c\xe8\x85\x18\t`,\xa6\xb1\xbd\x10\xbd\xd0(H"7^\xa01\xc4\ \xd8\x18#\xd2\x04Q\x11\x97Pjm\x8a\xad\xbb\xb4\xd3vw\xf6gvv\xc7\x8bv\xc7\x96\ \n\xc57\x99|\'\xe7{\xbf\xf7\xbc\xe7;\xe7d\x04f\xe1\x85\xb7\xf6}\xf8g:\xf4xr\ \\\xaf\x9d=/\xd9M\xcd\xefN]^,\xff\xde\xd1\xf5\xfa\xe7\xdfs\x07\x10\xca\x83\ \xee\x8f:b\xa7\x7f\x8a\x9c_\x1a]\x99\xaf_\xec\x17S\x05\xd1UW\xed\x12\xffJ\ \xe9\x8cg\xf3L\\9;\x90\xd1r\xce\x88\x12\xdf\xd7\xf3\xc6\x89O\x17\x12\xb6\x95\ E\xcf\xc6\x83\xa7\x97\xac}\xc83\xd8\x1fw\\\x1b\x1c\xb4\x0f\xfdqM\x1c\xba1\ \x86\xbd\xaa\x16\xc5\xe5\xc0\xe5kT&\xb2\xa5\xea\xebI\xd7\xe6-\x8fy/\x9c\xff\ \xf6\xb7\xfe\xdb\t\x8b\x00?^u\x1d\xb9kQ\xc5`\xba\xff\xeb+\x1b|\xe7\x9e\xed\ \xed\xdc)>P\xdf\xb7\xb90y}j\xf8\xda%31\x95"\xa5\xa5Q\xfcAd\x7f\xd8\xf9kr\xdd\ g\xaf\xbc\xb9E^PX\xcdH\x8d\xb6bz\xf2\xc1\xe5\xc3\x8f\x1cz\xf9\x83\x93\x00\ \x87\xf7~\xf2Ukx\xf8`ZU\x05mj\x1c=\x97\x01\xc0\x1f^.\xfad}\xe8\x86\x1e\xe9Y\ \xb0\xc7\xcf\xec\x7f\xe9\x8b\x88\xb3\xf0\xcb\x94Z:0;\xe9\x94\x04\xbe\x1b\xaf\ g\xe9\xaa\x969E\x9e\xecen\xfc=J\xa84q\xb3\xde\xbe\xaew\xbb\x8f\x02T\x00\x84\ \xabS_f\xc6\x1c=\x87\x0f\xbd=o\xe5\x87;\xba\xe7\xcd\xe5\xbc\xf70<\xd0\xcb\ \xc7\xc7\xe6\xf8\xe0\xd5\xfd{\x8f\x00G\xadVdF\x1dW\x15\x8f\x8fLfz\xbb\x9a\ \xa6Y\x9f%\x96\xfdwl\xb3;\xe6\xf0\x86\x86\x87\xd04\r\x9f\xcf\xc7\xee=\xbbb\ \x96c\xa0!\x10\x08\x02\x90\xd6\xd2\xb8e\xf7\x7f:-\xc3,\x95\x00x\xe2\xe0\t\ \x0c]\xe7\xd4\x81m\x00(\x8aB2\x99\x8c\x02\x17\xc5\x19\xee\xd6\xe6u-d\xb3Y\ \x04\x04\xcbiS\xeb&\x9aZ7Q\xa3\xf8\x00\xc8\xe7s\xd31\x9b\xa21v/\xcbV\xb7\x02\ P)U\x02p_\xdb\xfd\x00k\xacV\x00\x8f\x86Bus\\\xbd\xffb;\xfd?\xff\x00\xc0\xc8\ \xf0\x00\x98&E\xa3@.\xab\x91\x9aT\x01\x18\xb8\xd4\xc7{;7Z5\xe1p=\xc0k\x00\ \xe2\xee=\xbbb\x92T\x89\xc3\xe1\xc0\xeb\xf5Z\xa4\xa0\xaf\x9e\xce\xed\xeb\x89\ \xf7\xf5R\xeb\x0bQ2\xcd\x99>\x98T{\xbc\xf4_\x8f\xae\xeb\x98\xa6\x89\xddn\xbf\xad\xf3\x9ba9\x16\x04\x81l6Kss\x0c\xc3(b\ \xb3\xd90\x0c\xc3":\x1c\x8e;\x16\xb5\x84\x13\x89\x84\x19\x08\x04f~S\xde\xdb\ \xf1\x01\xf0x<\x00D"\x91yqdd\xc4\x04\x04\xe1\xa9\xa7\x9f\xdc\x16\x0c\x06N\ \xfd/;\x0b`ddt\xe3?\xe7`\x9fS\xd3\xf9d\xaf\x00\x00\x00\x00IEND\xaeB`\x82' def getSaveBitmap(): return BitmapFromImage(getSaveImage()) def getSaveImage(): stream = cStringIO.StringIO(getSaveData()) return ImageFromStream(stream) def getSaveIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getSaveBitmap()) return icon #---------------------------------------------------------------------- def getTestData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x04iIDAT8\x8d}\x95MlTU\x14\xc7\x7f\xf7\xe3\xcdL\xe7\xcdt^\xcb\x0cHi\x85X"Pl\ E\xe3R\x08Q\x94\x98\x10\xe3\x82D\xe3\x9a\x85\x0b7\x1a\x13\x12\x13cBb\x88,0\ \xc6\x85\xc1\x85\xc4\xc4\x18,\x1f1\x86\x18\xb1|-\x10+\x88\x92\x06E\xd4H[>\ \xec4\xc5v:3\x9d\xce\xfb\xb8\xd7\xc5\x9b\x19\xda\n\xdc\xe4\xe4\xbd\xdc{\xde\ \xef\xfc\xcf9\xf7\xde\'x\xc0\xb0\xd6\x8a\xee\xee\xee\x8e/\x0eN\x9c\xd6\x1aO)\ \x88"\x8b1|\xb8y\x9b\xf9\xe0A\xdf\x8a\xfb\xcc{\x83\x9f\x8b?{zT^\xeb\x04\xdd\ \xab\x1c\xb4\x92hm\xb16bt\xdcgj*\xe4\xdc\xf7\xe6\xcb={\xedk\xc0\xccR\x80\xbe\ \x07t\x97\x94\xf2\x95\'7\x89\xbc\x15\x19\xa4h\xc7\x0f\xda\xc0*,\x10\x845:;\ \xe6(,+s\xe3\x06\xdb\xa5\x9c?b\x8cy\x0b\xb8\xbc\x10\xa2\x96@_\x12B|\xdc\xdb\ \xdb\xebmXo\xb3\x85B\x1a\xa5\x96\xa1\xb4\x8bT)\x94NbL\x12c\xa0^\x0f8\x7f\xc1\ M\x8d\xdf\\\x91.\x97\xcb[\x8c1S\xc0\xef\xf7\x02or\x1c\xe7\xfd\xb5k\xd7\xb69\ \x8e\xb3rz:\xc5\xe6\xa7}\x94J\xa3\xa4D*\x81R\x96\xc8\x18\xa2\xd0\'\x0c\xe6\ \xd8\xb3\xb7\x0b)e\xc6\xf3O\xb5Z\ m\xad/-\x89\xd6:\x99\xcb\xe5\x10\x07>b\xb4\xab\x8b\xd5~\x10\xcb\x15\r\xd9\ \x96\xf8\xfd\xc4\xc9\x04\xa7\xce>\xbc\xa8<\xcfn\x1dg\xfb6?\xce\xce\x02\x02D\ \xe3\xe98p\xea\x0c\x9f\xc9\xc8\xc4e\r\x03\x08C\xf0}\xa8\x07P\xaf\xc3\\\r\x1e\ \xef\x8fH\xb7\xcd\xe3\xfb>\x95J\x85Db\x8e\x8d\xebC\xca\x15\xa8\xd5b?\xdf\x07\ ?\x80 \x88Y\xc6\x80\xda\xd8\xc7_\x8e\xc3\xab\x8e\x8e\'"\x13\x07\x88\xc2\xa6\ \xa3\xa5\xf7\x91\n\xc3\x17|fg}^x~\x8e\x15\xcb\x03\xac\x05k\xee\x82\xac\x05c\ \xe1\xce4\x94\xcb\xbc#\xf7\xed\xe7x\x18A\x18\xc5\xc00\x88\xad\xee7\xac\x0e\ \x97~v\x01\x8fl6\xcb\xe5\x11\x97z=\x9e\xaf\xfb\xb1\xda\xb0\xa1\xb6)h\xdf~\ \x8eK\x80\xd9Y\x8aB\xc6\x0bACi\xeb\x19\xc0\xf0\xc5\xf6V}\xff\x99H26\x9el\xad\ 5}\xc3\x10\xa4\x80z\x9dY\x00\t09\xc9\xaeZ-\xeeC\x14\xc6\xea\xa3\x86\x82\xf3\ \xc3\xd9E[\xcaZ\xcbW\xc7\xf3qv\xe1\xddL\xad\x8d{\xa2\x14{Zw\xc5\xf0\x05\xfe\ \xd8\xd8\xc7\xcb\xaeKA\x88FJ\x06\xc6\xc6\x93\x0c\x9d\xe9X\xb4O[G\x1e\xe8\xee\ \xf2\x11\x02\x94\x8c\x03|;\xa4\xdf8{\xae\xff\x93b\xb1\x18H\x80\x81\x81\x81\ \xf6o\xbe\x1bx\xee\xefQn\xff;\x03ZC\x14\xc1\xf0\xc5,\xf7\x1b\x17/\xb5\x13\ \x998\x80\x1f\xc0\xd88\x13c7\xfa\x0e[c\x9dV)\xac\xb5\x12\x10C\xa7\x07\xb6^\ \x1f\xd5\x07\xc7\xc6\xc1\xd1p\xf3V\xa2l\x97\x1c\xf1\x05\xa7\xb2S\xeaYSJ\x9b\ \x0e\x11\x11\x11\x99}>\xe8\xf7X\x10\xb46h\xd6\x82LBh\x90\x99}\x1c\x80d_;3b\ \x07\x83\x84\xe5)\x12\xf4\xa62\x04\x89\x7f\xc8\x82G\x00\xc8\xa4\x15\x96\xe7\ \xea\x08\xae\x11\x1c\xc7\xb2 \xf8\x99zP\x1d\xc9\xbd\x85YS\x0fPK\xae\x8b\xe2\ \xa7=z\xd4\xd9\xf0.MC\r\xf9M\xb8\x8fz\n\n?\x07\nzj\xd9\xd5\xfe_#\xf3s\xe9\ \xa5\xb83oP{w\x8fz\xc8\xd8Oc\xe5\xd7T\x83\xba\x00\xb8d\x87\xb5\x0f#\xbe\xe1\ \x00\x00\x00\x00IEND\xaeB`\x82' def getToolCheckListBitmap(): return BitmapFromImage(getToolCheckListImage()) def getToolCheckListImage(): stream = cStringIO.StringIO(getToolCheckListData()) return ImageFromStream(stream) def getToolCheckListIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolCheckListBitmap()) return icon #---------------------------------------------------------------------- def getToolChoiceData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x83F(\xc2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00\x7fIDAT8\x8d\xbd\x92K\x0e\xc0 \x08D\x9d\xc6\xcb\x14\xee\xbf\xf6\x14\xda\ \xe3\xd8\x05\x89\xb1\xa0\xf6\xa3\xe9,L\x04\x99<\x10\xe4\x9c\xdd\xb4\x00x\xe7\ \\:\xd2\xbc\xd76o\x11Bh\x1b1\xf1\x07\xbb\x05D"\xaf\xeeL\x1cS\x94\xb3\x04i\'[\ \t\xa0~\xa3\x8dz\xba\xfd\x90Kk\x05D\xa0\x06e2\xe0Z\x8d\xd6\x1e2v\x8d\xd4\\l\ \xc4R\x8c\x88\x9a\x02\xf0\x82H\xe1\xd4\x11\x9b\xb2Z\xb6G\xab\x17r<\xc8_u\x02\ \xbeu.\xab\xa5\xf7\xcf\xc1\x00\x00\x00\x00IEND\xaeB`\x82' def getToolChoiceBitmap(): return BitmapFromImage(getToolChoiceImage()) def getToolChoiceImage(): stream = cStringIO.StringIO(getToolChoiceData()) return ImageFromStream(stream) def getToolChoiceIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolChoiceBitmap()) return icon #---------------------------------------------------------------------- def getToolComboBoxData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x83F(\xc2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00\xb0IDAT8\x8d\xad\x93\xc1\r\xc3 \x0cE\xbf+\x96\t\xab$\xed"\xcd:\xe9 U\ \xee\x9e"d\x1c\xf7\x80J\x89q\x91\x1b\xf5\x1f\x900\xf0\xf8\xd8\x86\xd6\xe7\ \x8a\xef\x1a\xafcg\xb5\x88\x88\x02\x80\xe96\x99\xcb"\x02 \xed\xc9\xc3\n\xf5\ \x99sbf\x00\x97\xd3\xe7\x954\x88\x88\xce\x81\x82gS\x1cb\x1b\\\x1e\xcb|\x9f\ \xb7\xb4\x19 "\x12\x91<\xd6\xf1\xb4\xa78\xc4:\xeb\xcc\\S\xe0\xcfQf\x95\xa9\ \xa2\x1c@\xc5H6\xd5\x81\xe62)\x1d\x1c\xd1[\x1dS\xed\xa3\xb2\x82\xb2\xd3\x1aT\ ,\x93\xa2\x1dydR>\xa0\xf6\xf2_{\xfdo\x9d\xedjH\xb3L\x06\xa8\xf3\n\xff\x8fy\ \x01H\x13XZA\xc5\xd2\xce\x00\x00\x00\x00IEND\xaeB`\x82' def getToolComboBoxBitmap(): return BitmapFromImage(getToolComboBoxImage()) def getToolComboBoxImage(): stream = cStringIO.StringIO(getToolComboBoxData()) return ImageFromStream(stream) def getToolComboBoxIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolComboBoxBitmap()) return icon #---------------------------------------------------------------------- def getToolDefaultData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00\\IDAT(\x91\xc5\x92Q\n\xc00\x08C\x13\xdb\x8f\xde\xffD\x1e\xc3\x8b\x8c\ \xc1`\xeb\xfek\x1d\x0c\x0b\xcdg\xd0\x07&\x92R\x90\x91\xa4\xb6W\x00\xeah\x9c\ \xd7\xd1\xa3\xe1V\x1b(\x85\x9f\x00\x0003\xe7\xa9\xea\x14\xba?\x83\xf5!\x02\ \xf1\xbd3q|\xa4\xfe\xdca\x0b\x00\\\x0b\x0e\xf0W\xfbCL\x03^\xd7\x11\x0f:\xa3\ \xa1\x04w\x00\x00\x00\x00IEND\xaeB`\x82' def getToolDefaultBitmap(): return BitmapFromImage(getToolDefaultImage()) def getToolDefaultImage(): stream = cStringIO.StringIO(getToolDefaultData()) return ImageFromStream(stream) def getToolDefaultIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolDefaultBitmap()) return icon #---------------------------------------------------------------------- def getToolDialogData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00CIDAT(\x91c` \x11020000\xfc Z=\x07\x13\xa96\x90\xac\x81d\xc0\xc8\xc0\xc0\ p\xe1\xca\x05"U\x1b\xe8\x18\xd0\xde\x0fCO\xc3\x81\x03\x07(\xb5\x81\x85\xa0\ \x91\x044888\x90j\'\x01\x00\x00l\xe2\t]3\x1c\x89\xf6\x00\x00\x00\x00IEND\xae\ B`\x82' def getToolDialogBitmap(): return BitmapFromImage(getToolDialogImage()) def getToolDialogImage(): stream = cStringIO.StringIO(getToolDialogData()) return ImageFromStream(stream) def getToolDialogIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolDialogBitmap()) return icon #---------------------------------------------------------------------- def getToolFlexGridSizerData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00?IDAT8\x8dcddbf\x88O\x8a\xfd\xcf@.`dbfHHI\xf8\xcf\xc8\xc4\xcc\x80\ \x8c\xb1\x89aS\xc3D\xb6\xcdP0\xf0\x060\x8e\x06\xe2\xa8\x01\xd40\x80\xe2\x84\ \xc4\xc8\xc8\xc4L\x91\x0b\x00\xb7J\x13\xf6st\x19\xa8\x00\x00\x00\x00IEND\xae\ B`\x82' def getToolFlexGridSizerBitmap(): return BitmapFromImage(getToolFlexGridSizerImage()) def getToolFlexGridSizerImage(): stream = cStringIO.StringIO(getToolFlexGridSizerData()) return ImageFromStream(stream) def getToolFlexGridSizerIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolFlexGridSizerBitmap()) return icon #---------------------------------------------------------------------- def getToolFrameData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x004IDAT(\x91c` \x11020000\xfc Z=\x07\x13\xa96\x90\xac\x81d\xc0\xc8\xc0\xc0\ p\xe1\xca\x05"U\x1b\xe8\x18\xd0\xde\x0f\xa3\x1ah\xa2\x81d\x00\x00*K\x04\x19\ \xfe\xab\xe3r\x00\x00\x00\x00IEND\xaeB`\x82' def getToolFrameBitmap(): return BitmapFromImage(getToolFrameImage()) def getToolFrameImage(): stream = cStringIO.StringIO(getToolFrameData()) return ImageFromStream(stream) def getToolFrameIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolFrameBitmap()) return icon #---------------------------------------------------------------------- def getToolGaugeData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x0e\x08\x02\ \x00\x00\x00\xba\x9aK)\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00TIDAT(\x91c\x9c2u\n\x03U\x00U\x0c\xfa\xff\xff?\x0b\x9c\x85)\xcd\xc8\xc8x\ \xf5\xdaU"\xcdb\x81\xb3\xde\xbf~O\x89\xa3\x98pIl\xdb\xbd\x8d:\x06\x91\nF\r"\ \x0cX\x909\xa4\xc6\x14\x16\x83\x18\x19\x19)r\x0f\xdc \xe2S0>\x83\xb0\xe6\x0f\ R\x01\x00U\xa6\x18\xb4\x82\x95pI\x00\x00\x00\x00IEND\xaeB`\x82' def getToolGaugeBitmap(): return BitmapFromImage(getToolGaugeImage()) def getToolGaugeImage(): stream = cStringIO.StringIO(getToolGaugeData()) return ImageFromStream(stream) def getToolGaugeIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolGaugeBitmap()) return icon #---------------------------------------------------------------------- def getToolGridBagSizerData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00SIDAT8\x8dcddbf\x88O\x8a\xfd\xcf@&`\x811\x16\xce[\xccH\xaa\xe6\xf8\ \xa4\xd8\xffL\xe4\xda\x0c\x03\x03o\x00<\x0c\xc8\x0eHF&f\x86\x84\x94\x84\xff\ \x8cL\xcc\x0c\xc8\x18\x9b\x1865\x03\x1f\x06\xa3\x06P\xc1\x00FJs###\x133E.\ \x00\x00\x9f\x06\x11@\\\xf4\xbaw\x00\x00\x00\x00IEND\xaeB`\x82' def getToolGridBagSizerBitmap(): return BitmapFromImage(getToolGridBagSizerImage()) def getToolGridBagSizerImage(): stream = cStringIO.StringIO(getToolGridBagSizerData()) return ImageFromStream(stream) def getToolGridBagSizerIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolGridBagSizerBitmap()) return icon #---------------------------------------------------------------------- def getToolGridSizerData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00=IDAT8\x8dcddbf\x88O\x8a\xfd\xcf@.`dbfHHI\xf8\xcf\xc8\xc4\xcc\x80\r\ \x13\x92c"\xdbf(\x185\x80\x81\x81q4\x1a\x87\x83\x01\x14G###\x133E.\x00\x00\ \x18\x10\x13\xf65~\x97=\x00\x00\x00\x00IEND\xaeB`\x82' def getToolGridSizerBitmap(): return BitmapFromImage(getToolGridSizerImage()) def getToolGridSizerImage(): stream = cStringIO.StringIO(getToolGridSizerData()) return ImageFromStream(stream) def getToolGridSizerIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolGridSizerBitmap()) return icon #---------------------------------------------------------------------- def getToolListBoxData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x18\x08\x02\ \x00\x00\x00q\xdc\x9a\x1c\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x00\x7fIDAT8\x8d\xd5\x94A\n\xc0 \x0c\x04w\x8b\xff?\xd9\xaf\xd9\xe7\xa4\ \x07!\x14\r\x12\xa3\x856'\x89d\xdd\x8c!\xccg\xc6b,J\x88H\xd2S\xa0\xbe\\\x05\ \xc0a\xde\x91\xf4\x0b\xd9\x12SaH\x90\x14\x11\xbf\x91\x17\\T\x0b\x00\xfcFR\ \x9f\x9ab\xd9J\xa8\x85A\xa6\x8f\xdd,\xfa\x07=#\xd7\xb2x\x82p\x8e\xac\x81S+= \ \xb0\x85\xc5\xe8S\x7f\xd5\xc87Y\x04\xd6\xd7\xbeF\xea\x16\x8cK\xc4v\xaf\xc6\r\ \xf1)>\xb5\x89Y\x88\x02\x00\x00\x00\x00IEND\xaeB`\x82" def getToolListBoxBitmap(): return BitmapFromImage(getToolListBoxImage()) def getToolListBoxImage(): stream = cStringIO.StringIO(getToolListBoxData()) return ImageFromStream(stream) def getToolListBoxIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolListBoxBitmap()) return icon #---------------------------------------------------------------------- def getToolListCtrlData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x18\x08\x02\ \x00\x00\x00q\xdc\x9a\x1c\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x00nIDAT8\x8dc\x9c2u\n\x03\x85\x80B#\xfe\xff\xff\xcf\x02g\x91\xa1\xff\ \xda\xf5k\x0c\x0c\x0cL\x948\x01\x02X\xd0\xf8\x8c\x18*\x08:\x8f\n\xae\x185\ \x02\x01\xd0c\x84\x8c\xe418<\x82\xd3\x08F,\xa9\x8c\x14# \xfa\x894\x05\x8b\ \x11\xc8:\x891\x85\x06a\x81i-A\x87\xd0$i\x91\x9c\xb8\x06G\xd2\x82z\x04R\n\ \x92o\x04ye/\x1c\x00\x00\x83\x9c\x15\xbc\x94tu\xe9\x00\x00\x00\x00IEND\xaeB`\ \x82' def getToolListCtrlBitmap(): return BitmapFromImage(getToolListCtrlImage()) def getToolListCtrlImage(): stream = cStringIO.StringIO(getToolListCtrlData()) return ImageFromStream(stream) def getToolListCtrlIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolListCtrlBitmap()) return icon #---------------------------------------------------------------------- def getToolMenuData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00bIDAT8\x8dcddbf\x80\x81\xef\xbf\xbe\xfeg \x02p\xb0p002132000\xb0\xa0\ K\xde\xb8q\x03\xaf\xe6\x03\x07\x0e\xa0\xf01\x0c\xc0\xa6\x08\x06\x1c\x1c\x1c0\ \xc4\x98\xf0ZG\x04\xa0\xd8\x00\xac^\xc0\xe6T\x92\x0c\x18\r\x83\xd10\xc0\xe5\ \x7f\\\x80\x119;\xff\xff\xf7\x97\xa8\xec\xcc\xc0\xc0\x00\xcf\xce\x00\x8f\x14\ \x1a\x83cs\x82P\x00\x00\x00\x00IEND\xaeB`\x82' def getToolMenuBitmap(): return BitmapFromImage(getToolMenuImage()) def getToolMenuImage(): stream = cStringIO.StringIO(getToolMenuData()) return ImageFromStream(stream) def getToolMenuIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolMenuBitmap()) return icon #---------------------------------------------------------------------- def getToolMenuBarData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00aIDAT8\x8d\xed\x93\xb1\r\x800\x0c\x04\xcf!E\xc6\xca\x98\x19\xc7cx\ \x94\x14HP "7)\x88\x0b(\xb8\xf2\xa5\x7f\xbdmY$mDH!\xf7\'\x02\xa4\xef\xfdX5\ \x97\\\xc8\x00f\xf6\xd8\xac\xaa\x00W\x80\x17<\xb5\xd6\xa9~\xf3\xfe\x12\xc7\ \x08\xbe\x96g\xa6\x8f\x80\xd6Z\xa8\x81\x00\xcbg\x04\x90\xff\x178\x01o\x9c\ \x13?\x8d\xde\xe5M\x00\x00\x00\x00IEND\xaeB`\x82' def getToolMenuBarBitmap(): return BitmapFromImage(getToolMenuBarImage()) def getToolMenuBarImage(): stream = cStringIO.StringIO(getToolMenuBarData()) return ImageFromStream(stream) def getToolMenuBarIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolMenuBarBitmap()) return icon #---------------------------------------------------------------------- def getToolMenuItemData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0c\x00\x00\x00\t\x08\x02\ \x00\x00\x00\x89\xdaZ\x03\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x00>IDAT\x18\x95c\xfc\xf1\xe7\x07\x03^\xc0\xc1\xc2\xc1\xc2\xc0\xc0p\xe3\ \xc6\r\\*\x0e\x1c8\xc0\xc0\xc0\xc0\x84\xdf\x18\x08`A\xd3\x84\x0c\x1c\x1c\x1c\ \x0c\xa2L"\xd1:\xb8\xe1\xd8\x15a\xba\x86\x1c\x00\x00u\xae\r\xe0\x8b\x0b\x7f\ \xe2\x00\x00\x00\x00IEND\xaeB`\x82' def getToolMenuItemBitmap(): return BitmapFromImage(getToolMenuItemImage()) def getToolMenuItemImage(): stream = cStringIO.StringIO(getToolMenuItemData()) return ImageFromStream(stream) def getToolMenuItemIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolMenuItemBitmap()) return icon #---------------------------------------------------------------------- def getToolNotebookData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\ \x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00\xd3IDATH\x89\xed\x96a\n\x830\x0c\x85_\xaa\x97Y{\x04aW\x176\xd4\x13\xe8.\ c\x9b\xfd\x18\xbaj\xad$\x0e\xf7c\xec\x03\x91\xc6\x92\x97\xa4\x8f"\x91)\x10\ \xfc\xc8\x10`\x8a\x92$\xfbb\xca\xe0G\x1e\x1e\x83h3\x07\xcfd\n\x95\x88\xd9\n:\ \xeb\x92X]\xd7\x00\x80\xe0G\xde{\x92\x0e4\xd5\x00@{ow\xbf\xaf\xbbL\x04\x9cu\ \xe8\x87~~oQ]\xab\xc5\xba\xb95/\xf1.\x15Ww\xb0N:\t\xc6\xeb\x98\xc5\x19\xc4UO\ ]|\xca\xe6\x88$\xc4c\xcaU\xbf\x10\xc8\xcd<\x17?4\xa23\x98\x05r\x8e\xc9\xc5\ \xa5\x1cv\x91\xfa\x0c4\xec%\\C\xcc,\xbe\x8b\x00\xc0^\xac<9\x91\xbe\x03M1\xc0\ \x89.\x9a.\xc7\xef\xd9\xf4/\xf0\xbb\x02%\xf0\xb6\xd4\x19\x10\x00\xd1/\xcbQ\ \x9e|\xd6v/g\xd2\x8d{\x00\x00\x00\x00IEND\xaeB`\x82' def getToolNotebookBitmap(): return BitmapFromImage(getToolNotebookImage()) def getToolNotebookImage(): stream = cStringIO.StringIO(getToolNotebookData()) return ImageFromStream(stream) def getToolNotebookIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolNotebookBitmap()) return icon #---------------------------------------------------------------------- def getToolPanelData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x02\ \x00\x00\x00\xa9M\x0b\xdd\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x002IDAT(\x91c\xfc\xf1\xe7\x07\x03\xd1\x80\x83\x85\x83\x85\x81\x81\xe1\ \xc6\x8d\x1b\xc4\xa8>p\xe0\x00\x03\x03\x03\x13\xf1\xc6C\xc0\xa8\x86!\xaa\x81\ \x85\x01\x16\xe7\xb4\x02\x00vv\n&i\xb3\xa3d\x00\x00\x00\x00IEND\xaeB`\x82' def getToolPanelBitmap(): return BitmapFromImage(getToolPanelImage()) def getToolPanelImage(): stream = cStringIO.StringIO(getToolPanelData()) return ImageFromStream(stream) def getToolPanelIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolPanelBitmap()) return icon #---------------------------------------------------------------------- def getToolRadioBoxData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xda}\\\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x01\x0bIDATH\x89\xc5\x94K\x0e\x820\x10@g\xda\x1e\xc0\x85\xa7!\xe1Bt\xeb\ \xf7\x04\x1aw\x06\xf1B&\xde@O\xe1\x82\x03\xd0\x8e\x0b\x1dR\xa0\x14-\x18'iB\ \xa1\xf3^\xa7\x19\x8a($\x84\x82\xac!\x14\x12\x83\x8b\x02!b\x13'\x11\xf0\xee\ \xc9\x1a\x8a\x15\xa8k_\xe7\xc4t\xd4\x7f\xba\xc8\xdd\xe5a\xb7'\xdf\xfbQ\x826\xdc\x95L&`\ \xe8r\xbdl\xcc'\x11\xb8\xf0\xdb\xfd6J\xd2\x11\xb4\xe1\x000J\xd2\x10\xf8\xe0\ \x1c\xb1\x92\xc6\x7f\xb0\xdan\xd0\x9a\x8a\x16\xab\x05\\/W\x98\xcdg\xf5\xb7\ \xf2Q\x02\xd1\x8b;t\x95\xf4V\xe0&'i\x02\xe5\xa3\xac\xe1I\x9a|\r\xf7\n|\x92Xx\ \xaf\xa0-\x89\x85\x07\x05.4\x16>(\x18\x0b\x07\x00\xc0Sq\x8a\xbe\x06\x86Bg\ \x1a\x90\xb8\xf7~\x14O\xab+\x90\x81!\xff\xcd\xf3\x00\x00\x00\x00IEND\xaeB`\ \x82" def getToolRadioBoxBitmap(): return BitmapFromImage(getToolRadioBoxImage()) def getToolRadioBoxImage(): stream = cStringIO.StringIO(getToolRadioBoxData()) return ImageFromStream(stream) def getToolRadioBoxIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolRadioBoxBitmap()) return icon #---------------------------------------------------------------------- def getToolRadioButtonData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0b\x00\x00\x00\x0b\x08\x06\ \x00\x00\x00\xa9\xacw&\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00\x96IDAT\x18\x95m\x90\xc1\r\xc20\x10\x04\xc7g\n\xc8\x83*H\x07\x96RVD\t`\ \xdc\x15(\xe9 T\x91\x87\x0b\x00\xcc#1\xb2\xcd\xadd\xf9t\x9a=\xad\x16#\x96\ \xf6\x05\x1f\x92\xb6\x17\x1a\xdd.\xd7T\xfe\xa5D\x03\xc7\xf3\x88f\x10\r\\\x9e\ \x8bj\x10\r\x04T\x83\t>\xfc\x81\xa5\xfaSO\xf0\x01\x00c\xc4\xf2y\xbf\x12\xc0\ \xfc\x98\xe9\x8e\xdd\x0f\x8ck\xc4\rn\x8b`\x0fF\xf2\x00\xe0\x06G\\\xa3\nn\xa7\ \x8b\x1e\xd3\xae\xe9>\xe5\xb1\xee\xdb\x88\xad2\xe6H\xd5E\xad\xe7\x12hA\x80/\ \x17\xa5W:+\xbbb\xd2\x00\x00\x00\x00IEND\xaeB`\x82' def getToolRadioButtonBitmap(): return BitmapFromImage(getToolRadioButtonImage()) def getToolRadioButtonImage(): stream = cStringIO.StringIO(getToolRadioButtonData()) return ImageFromStream(stream) def getToolRadioButtonIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolRadioButtonBitmap()) return icon #---------------------------------------------------------------------- def getToolRootData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ \xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ \xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ \x00IEND\xaeB`\x82' def getToolRootBitmap(): return BitmapFromImage(getToolRootImage()) def getToolRootImage(): stream = cStringIO.StringIO(getToolRootData()) return ImageFromStream(stream) def getToolRootIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolRootBitmap()) return icon #---------------------------------------------------------------------- def getToolScrollBarData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\r\x00\x00\x00\x18\x08\x02\ \x00\x00\x00\xae\x92\xe0\x03\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\ \x00\x00\x00\xc5IDAT(\x91\x8d\x92\xcd\r\x84 \x10\x85g\x0c\xcd\xac%`\xdc\x84z\ \xd6F6^\xb1\x1e\x13\t\x94\x80M\xec\xc1\x0e\xd8\x03\t\x8e\xccH|'~>\x86y\x0fp\ \xfe\xce\xf0DO\xb8\x94\x92\xca#\xbf\xf9\xb2\xaaG\x1d\\\xa8\xd0\xae\x9a\xebQ\ \xc7=\x0e\xef\xa1\xc5e\x08\x00\xecb+\xb4\xe3\x10\x00\x18c*T\xd1C\xeb\xba\xde\ z\xc9~SJw\x80\xdf\xfc\xe97\xb8@-s\xa9\xd2\x9c\xb8\x8d\x88\xf9\xfc\xd9_1!\xaa\ \xce\x8f\x8a\xdajqB\x7f\xbc\x80\xcc!\xe2\xa3z\xedP\x00H\xce\\v\xb1\xc0s\xa6\ \xef\x9b{\x9d>S\xb9\xe7\xf4\x1b\\\xe8_}\x99R\x08\xeer\xe1\xc6/\\.Y\xdd(\xd7\ \x8b{\xe4\x90\xc0\x1d\xbfC\xccHA\xf3\xf3\x15\xfd\x01\xc5\xac\x80\xf9\xbb\xd3\ \xc3\xb7\x00\x00\x00\x00IEND\xaeB`\x82" def getToolScrollBarBitmap(): return BitmapFromImage(getToolScrollBarImage()) def getToolScrollBarImage(): stream = cStringIO.StringIO(getToolScrollBarData()) return ImageFromStream(stream) def getToolScrollBarIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolScrollBarBitmap()) return icon #---------------------------------------------------------------------- def getToolSeparatorData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x02\x08\x02\ \x00\x00\x00\xe7\xe8z\xfd\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x00\x17IDAT\x08\x99c\x9c2u\n\x03\x11 ;+\x9b\x05B\x11\xa3\x1a\x00\xfb\ \x1c\x04CU\x1cv\xec\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSeparatorBitmap(): return BitmapFromImage(getToolSeparatorImage()) def getToolSeparatorImage(): stream = cStringIO.StringIO(getToolSeparatorData()) return ImageFromStream(stream) def getToolSeparatorIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSeparatorBitmap()) return icon #---------------------------------------------------------------------- def getToolSliderData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x0e\x08\x02\ \x00\x00\x00\xba\x9aK)\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00pIDAT(\x91c\xec\xee\xecf\xa0\n\xa0\x8aA\xff\xff\xffg\x81\xb0\x8e\x1e:jek\ \x85G)##\xe3\xd1CG\xf1(`A\xe6\\\xbb~\x8dlG1a\x15\xdd\xbf\x7f\xff\xfe\xfd\xfb\ \x91\xb9d\x1a\xc4\xc0\xc0\x90\x9d\x95M\x05\x17\x91\x01\x86\x8aA\xa4\x06\x10\ \x03Z\xf43\xc0"\x88\x98h\xc2i\x10###\xa9\x9a\xb1\x1b\x84?\xe1\x12e\xd0\xff\ \xff\xff)1\x02\x02\x00G?!-\x9e\x07b\xab\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSliderBitmap(): return BitmapFromImage(getToolSliderImage()) def getToolSliderImage(): stream = cStringIO.StringIO(getToolSliderData()) return ImageFromStream(stream) def getToolSliderIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSliderBitmap()) return icon #---------------------------------------------------------------------- def getToolSpacerData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x000IDAT8\x8dcddbf\xa0\x040Q\xa4{p\x1a\xf0\xff\xdf\xdf\xff\xc4\xd00\xc0\ H\xf5@D\xb7\x81\x90\xfc\xa8\x0bh\xe9\x82\x81K\x07t7\x00\x00\x1cB?\xcf\xebM\ \xd0P\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSpacerBitmap(): return BitmapFromImage(getToolSpacerImage()) def getToolSpacerImage(): stream = cStringIO.StringIO(getToolSpacerData()) return ImageFromStream(stream) def getToolSpacerIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSpacerBitmap()) return icon #---------------------------------------------------------------------- def getToolSpinButtonData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\xc4HUC\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00\x87IDAT(\x91\x9d\x90\xd1\r\xc3 \x10C\xed\xa3\xd34S0O3\x0e\x99\x87-\xd2e\ \x02\xee\x17\xa8@B\xabX\xe2\xe7x\xba\xb3M\x9a\xc3/Y?\xc8\xe9\xd0\x14\xca\xe9\ \xd0\xfe\xde\xa1\x9ct\n\x15\x00\x00\xc2\x16\x1a\xd0z\x00\x00\xbc\xf7\r\xf8(\ \x1f1\xc6K\xe3\x94$\x92\x93l\x00oUp*M\x14\xb6 \x00"\xcd\r\xe9J\x90\xf5\xb5\ \x82\xe6X=\xf5\xe0\xf2\\@s\xbc\xf44\xd4As\xf55>\xbe\xe6C\x05\xcaI\xe5L]\xf4O\ O\x1fX\xf8l\xb8l\x11n\x9b\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSpinButtonBitmap(): return BitmapFromImage(getToolSpinButtonImage()) def getToolSpinButtonImage(): stream = cStringIO.StringIO(getToolSpinButtonData()) return ImageFromStream(stream) def getToolSpinButtonIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSpinButtonBitmap()) return icon #---------------------------------------------------------------------- def getToolSpinCtrlData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x0c$\xbf\x95\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00\xd7IDAT8\x8d\xadT\xdb\x11\x83 \x10\xdc\x03\x9b\x89]XOtRKF\xad\xc7.\ \xb4\x19a\xf3\x91\xe0(\x03\xe6|\xec\xcc\xfd\x1c\xc7.\xb7\x07H\xd7w\xc4\t4\ \xcdKT\x85?\x81CA\x92b,\xe2H\xe5\x8b D\xea\x1a\x19\xa71\x99\xf7n\xe68\x8d\ \xa0w\x14c\x97\xee\x8c\x8a\xf5\x0f\x029\x00t}\x07z\xb7\x9c6+ \xa2\xb3xM\x0e\ \x00UUmD\x8a\xd4&-y\xc00\x0c\xd9\xb5\xa4\x00I\x95\x88w3\xf7\xea\xe8\x1d\x93\ \x02Z\x18[\x88\x18\xbb_sE@u\x88+\x9b\xbd\x9b\x99\x8b\xb6}\xf3\x16\x8b\xe2[\ \x04|\x87^?k\x88\xb1r\xd9"c\x0b)\x1f\xe5&\x17\xc8\x81\x1d\x8b\xb4/;F|eo\x19r\ \xe8bmMX[f\x90\xfbc\x8e\x88\xc4\xff\xd0"p\xd6\x8e\x1819\x00|\x00\x82\x1a\x92\ \x8c\xef\x85F5\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSpinCtrlBitmap(): return BitmapFromImage(getToolSpinCtrlImage()) def getToolSpinCtrlImage(): stream = cStringIO.StringIO(getToolSpinCtrlData()) return ImageFromStream(stream) def getToolSpinCtrlIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSpinCtrlBitmap()) return icon #---------------------------------------------------------------------- def getToolSplitterWindowData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x83F(\xc2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00JIDAT8\x8d\xed\x8e\xb1\r\x00 \x08\x04\xd1\xb8\x18;\xe2h\xe08oA\xa2\x154Z\ \x19\xaf\x81\xe2r\xf9"]\xe8\nWB\x00\xea\xfa"\xa4\x8b\x9a&\x82\x9a\x12Q=\x9f\ \xe3\xfc\xd0\x0f\xbd\x19j~lXd0s.\xec\x10\x80\xf3E\x13\xd4\xd0K\xe6\xddMz\xb1\ \x00\x00\x00\x00IEND\xaeB`\x82' def getToolSplitterWindowBitmap(): return BitmapFromImage(getToolSplitterWindowImage()) def getToolSplitterWindowImage(): stream = cStringIO.StringIO(getToolSplitterWindowData()) return ImageFromStream(stream) def getToolSplitterWindowIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolSplitterWindowBitmap()) return icon #---------------------------------------------------------------------- def getToolStaticBitmapData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x11\x08\x06\ \x00\x00\x00\xed\xc8\x9d\x9f\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ \x00\x00\x01\xf9IDAT(\x91\x85\x931h\x13Q\x18\xc7\x7fw\xf7\x86\x17p\xb8\x83\ \x0c\x97-\x05\x1dts\xb3N\x9et\x90\xe0\xa0-..N\x1d\xact(\xd1\xa9\xba\x05D\xa5\ \x83Z\x1c\x84,B\xba\x14\x1d\xb4\x8e\xbd\x0e\xc5\x04\x94\xa4\x8b\xb5\xe0\xd0,\ \x85d\x90\xe4\xd4\xc0=\xf0\xda\xcf!\xdc\xd9\xa3Q\xbf\xe9\xbd\xef}\xbf\xef{\ \xdf\xff{\xcf\xb2l\x87\xe3vt\x98\x08\x13\xccv\x94\x95\xdb\x1f\x07R(\xfe\x19\ \xd3\xf9\xd4a8\x1c\xfe5\xa1e\xd9N\xe6ln7y\xb3^gy\xe9,Z\x150\xa3\x98\xe6\xe7\ \x88\xb5w;4^\xbd\xcfU\xce\xc0\xe6v\x93\x92\xafq\t\xf1\xfc\x8b\x80\x0b\xa6E\ \x9c\x18\xa2oC\xee>\xdc\xa3\xb1\xd6\xc8`;\xad\xb6\xf2|\x05_\x85x\xc5\xcb\xa0\ \xa6@yp\xaaBAi\\\xd7cy\xbe\xc4\xdc\xf5\xb9\xec\xaa*]T\xe7+\xa0\x01]\x1a;\x12\ \x03@\x9ch\n\xca\xe0\x155\xae\xa7\xb3~3q\x8c1Y0hP.\xb1\x19\x8b\x13\xa3AiJnz\ \x0ev\xdal\xed\xd9kHb\xc0@\x12\x81\xe9B\xd2\x1b'K\x0c&\x8ah\xac\x87'\xc7Q\ \x7fY\xc7$\x8ca\xa5\x89M\x17\x88 1\xf4\xfb=\xba\x07Cj\x8fV3q\xb2\x1e\xb5\xd6\ hc\x80\x02\xf1\xa8\x0bI\x841Cz\xfd>f\x14S{\xb1G\xb8U\xcf\x8bc;\xca\xba}\xe7\ \x96\xec\xb4B\xa6\xce\xb4X}\x10\x10E\x11\xdd\x83\x1e\xf7\x1f\x87x\xc5s\x84[\ \xcd\xdc\x1c\xb1l\x07\xcbv@!\xb37*\xb2\xfbeW\xda\x1f?H\xe5j \xd5\xc5\x9b\xb2\ \xffu_RKc-\xdb\xf9\x03\xce^\xab\x88\x88H\xbb\xd3\x96`&\x90\xea\xbd\xaa\x0c\ \x06\x83\x13@\x0e\xf4}_6\xc3M\xa9\\\td\xf5\xe9\x13YX\\\x10\xb7\xe8N\x04r \ \xc1\xcc\xb4l\xbc\xdd\x18W\xbc\x14H\xf9t\xf9\xff`\n\x97\xcb\xbeL_8/\xd5\xa5\ \xea?!\xcbv\xc6\x8f\x1c@\x8e\x0e\xc5\xf7]\x8c1|\xff\xf1+\xf7\xf7&\xd9o(\xba\ \xfe\xd4S\x004\x8f\x00\x00\x00\x00IEND\xaeB`\x82" def getToolStaticBitmapBitmap(): return BitmapFromImage(getToolStaticBitmapImage()) def getToolStaticBitmapImage(): stream = cStringIO.StringIO(getToolStaticBitmapData()) return ImageFromStream(stream) def getToolStaticBitmapIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolStaticBitmapBitmap()) return icon #---------------------------------------------------------------------- def getToolStaticBoxData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xda}\\\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00\x9aIDATH\x89\xed\x95[\n\x031\x08E}\xad6\xae\xa6\xcc\xa4\xab\x1dc\ \x7fj\xe9+\x99"-C!\x17\x84\x044GE\t"1\x8c\xe4\xcd\x1c\x89q\xe84\x10e\x03\xbf\ \x02\x88\xec\xbd\x99g\x01\xb2,\xa7\x87`-\n\xc42lI\xb3\xcd\xeb\xb9\xee>\xaeEA\ \xe2\x10\x8a\xc7\xef{\x1fU\xc4\x9dX\xb0\xd9\xf6QU\xb7\x16\x11\x0b>g\xee\xcd<\ \xec%\xf0\xea\xdf\xb3\xa8P\xdeQ{\x93\x93\x99\xa8c\xa6\xa8\x97ef\x1f\x8e\xdd\ \x83\t\x98\x80\t\xf8\x13\x00\xaeuM\xffV{\xd2\xa2\x80\xee\xfe3\x00\x00\xc0\ \x05+eB\x8b9\xd0&\xe6\x00\x00\x00\x00IEND\xaeB`\x82' def getToolStaticBoxBitmap(): return BitmapFromImage(getToolStaticBoxImage()) def getToolStaticBoxImage(): stream = cStringIO.StringIO(getToolStaticBoxData()) return ImageFromStream(stream) def getToolStaticBoxIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolStaticBoxBitmap()) return icon #---------------------------------------------------------------------- def getToolStaticBoxSizerData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00iIDAT8\x8d\xed\x92\xd1\n\x800\x08E\xbd\xdao\x8e\xc9\xd8w\x05\xd1w.{\ \xe9a\xad\xa8\xad\x05\xbdt@\x04\x85\x83\\\x04X\xa8\x07.\x07\xb6${,\xb0%\x19X\ \xd0"\x19\x88\x88|p6\x8d3\xca\x0b|p\xf7"\xb0\x90F\xb5-\x8b]\xcfwg\xa5Q\x8d\ \x0b\x19\xf2^\xc3!\xc4V~\xc1\x0b\x02\x80\xa5\xeea\xae\x04=|\x9f\xc1\n5\x8d!\ \x0c[3\xf5K\x00\x00\x00\x00IEND\xaeB`\x82' def getToolStaticBoxSizerBitmap(): return BitmapFromImage(getToolStaticBoxSizerImage()) def getToolStaticBoxSizerImage(): stream = cStringIO.StringIO(getToolStaticBoxSizerData()) return ImageFromStream(stream) def getToolStaticBoxSizerIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolStaticBoxSizerBitmap()) return icon #---------------------------------------------------------------------- def getToolStaticLineData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x14\x00\x00\x00\x02\x08\x02\ \x00\x00\x00\xd7dk\xdc\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00\x17IDAT\x08\x99c\x9c2u\n\x03Y ;+\x9b\x05B\x91\xa7\x1f\x00gO\x04C>\xbb?\ \x99\x00\x00\x00\x00IEND\xaeB`\x82' def getToolStaticLineBitmap(): return BitmapFromImage(getToolStaticLineImage()) def getToolStaticLineImage(): stream = cStringIO.StringIO(getToolStaticLineData()) return ImageFromStream(stream) def getToolStaticLineIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolStaticLineBitmap()) return icon #---------------------------------------------------------------------- def getToolStaticTextData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\r\x08\x06\ \x00\x00\x00\xad\xa5\x9ec\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00iIDAT8\x8d\xd5SA\n\xc00\x08S\xbb\xff\xffX\xb3\x93\xe0J\x1ct\xa3\x8c\ \xe5f\xb4I\x14\xaajCv\xc0\xb6\xa8~"\x8cp\xdc\xd5\x8f\x85\xdf\x82\n#\x1cjCYJ\ \x84\x83m3sK\x89\xd3\xb0\x9a2\x8e\n\xe7\xa0\x88\xc8<\x9c|\x87\xda?\xbad+\x9b\ 0\\\x84kZf\xd4\xf5\xd9{\x9a\xb8C=\r;W5\xd5\xdf}\xe9\x13!\xebT\x08\xdd\x0f\ \x889\x00\x00\x00\x00IEND\xaeB`\x82' def getToolStaticTextBitmap(): return BitmapFromImage(getToolStaticTextImage()) def getToolStaticTextImage(): stream = cStringIO.StringIO(getToolStaticTextData()) return ImageFromStream(stream) def getToolStaticTextIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolStaticTextBitmap()) return icon #---------------------------------------------------------------------- def getToolTextCtrlData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x83F(\xc2\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x009IDAT8\x8dc\x9c2u\n\x03U\x00U\x0c\xfa\xff\xff?\x0b\x9cE\xb6)\xd7\xae_c``\ `\xa2\xdc9\x100j\xd0\xa8A\xc3\xd3 h^\x83\xe4\x17J\r\xa2$\xc7\xc2\x01\x00\xf4\ \x87\x11\x9b\xfda\x80c\x00\x00\x00\x00IEND\xaeB`\x82' def getToolTextCtrlBitmap(): return BitmapFromImage(getToolTextCtrlImage()) def getToolTextCtrlImage(): stream = cStringIO.StringIO(getToolTextCtrlData()) return ImageFromStream(stream) def getToolTextCtrlIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolTextCtrlBitmap()) return icon #---------------------------------------------------------------------- def getToolToolData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\t\x08\x02\x00\ \x00\x00o\xf3\x91G\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00>\ IDAT\x08\x99c\xfc\xf1\xe7\x07\x036\xc0\xc1\xc2\xc1\xc2\xc0\xc0p\xe3\xc6\r4\ \x89\x03\x07\x0e0000a\xd5\x04\x01,hj\x19\x18\x18\x1c\x1c\x1c \x0c|\xfa\x883\ \x13n\x14\x8a\x1c\xdc&\x12\x00\x00b\xc7\r\xe0y\xf1\x04O\x00\x00\x00\x00IEND\ \xaeB`\x82' def getToolToolBitmap(): return BitmapFromImage(getToolToolImage()) def getToolToolImage(): stream = cStringIO.StringIO(getToolToolData()) return ImageFromStream(stream) def getToolToolIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolToolBitmap()) return icon #---------------------------------------------------------------------- def getToolToolBarData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x08\x08\x02\ \x00\x00\x00\x7f\x14\xe8\xc0\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\ \x00\x00\x00bIDAT\x18\x95c\xfc\xf1\xe7\x07\x03\xd1\x80\x83\x85\x83\x85\x81\ \x81\xe1\xc6\x8d\x1b\xc4\xa8>p\xe0\x00\x03\x03\x03\x13\x84\xa3\xa1c\xa0\xa1c\ \x00\x11\xd2\xd00\xd0\xd0\x80\xb2\r4\x0c\x0c`l\x08`"\xde=\x10\xc0\x02\xa1fL\ \x99\x00\x17\x9a1\x03\xc1\x9e\x80\xc4F\xd1\xe0\xe0\xe0\x00\x17\xc2\xc5\x86j\ \x981c\x06\xa9\xae"\r\x00\x00T$\x1a\xf2\x8e\xbd4\xb3\x00\x00\x00\x00IEND\xae\ B`\x82' def getToolToolBarBitmap(): return BitmapFromImage(getToolToolBarImage()) def getToolToolBarImage(): stream = cStringIO.StringIO(getToolToolBarData()) return ImageFromStream(stream) def getToolToolBarIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolToolBarBitmap()) return icon #---------------------------------------------------------------------- def getToolTreeCtrlData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ \xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ \xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ \x00IEND\xaeB`\x82' def getToolTreeCtrlBitmap(): return BitmapFromImage(getToolTreeCtrlImage()) def getToolTreeCtrlImage(): stream = cStringIO.StringIO(getToolTreeCtrlData()) return ImageFromStream(stream) def getToolTreeCtrlIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolTreeCtrlBitmap()) return icon #---------------------------------------------------------------------- def getToolUnknownData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00XIDAT(\x91c` \x110200\\\xbdv\x95H\xd5\xdaZ\xda,XE\xe1lL\xb3\x98\xf0\xa8\ \xc6\xe4b\xd1\x007\x18\x97;\xb1k\xc0\x03\xd0\xfd@0\x00p\xda\x00q=aO#\xab&\ \xcd\x06\xac\xc6\x13\xd0\x80\x15`\x898\\f\xe3\xb3A[K\x1b\x977h\xef$\x92\x01\ \x00\x93O\x1a\xa4(\x924\xbb\x00\x00\x00\x00IEND\xaeB`\x82' def getToolUnknownBitmap(): return BitmapFromImage(getToolUnknownImage()) def getToolUnknownImage(): stream = cStringIO.StringIO(getToolUnknownData()) return ImageFromStream(stream) def getToolUnknownIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getToolUnknownBitmap()) return icon #---------------------------------------------------------------------- def getTreeCommentData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00AIDAT(\x91cddbf\xa0\x040Q\xa4\x9bf\x06\xfc\xff\xf7\xf7\xff\xff\x7f\x7f\ \xff\xa3\xb3\xe9\xe7\x02R\x00#z,\xe0s.#\x133#A\x17 +\xc2\xc5\xc6k\x00\xa9`\ \x18x\x81\xfaa@*\x00\x00\xb0\xac\x18?Q\xffAR\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeCommentBitmap(): return BitmapFromImage(getTreeCommentImage()) def getTreeCommentImage(): stream = cStringIO.StringIO(getTreeCommentData()) return ImageFromStream(stream) def getTreeCommentIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeCommentBitmap()) return icon #---------------------------------------------------------------------- def getTreeDefaultData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00\\IDAT(\x91\xc5\x92Q\n\xc00\x08C\x13\xdb\x8f\xde\xffD\x1e\xc3\x8b\x8c\ \xc1`\xeb\xfek\x1d\x0c\x0b\xcdg\xd0\x07&\x92R\x90\x91\xa4\xb6W\x00\xeah\x9c\ \xd7\xd1\xa3\xe1V\x1b(\x85\x9f\x00\x0003\xe7\xa9\xea\x14\xba?\x83\xf5!\x02\ \xf1\xbd3q|\xa4\xfe\xdca\x0b\x00\\\x0b\x0e\xf0W\xfbCL\x03^\xd7\x11\x0f:\xa3\ \xa1\x04w\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeDefaultBitmap(): return BitmapFromImage(getTreeDefaultImage()) def getTreeDefaultImage(): stream = cStringIO.StringIO(getTreeDefaultData()) return ImageFromStream(stream) def getTreeDefaultIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeDefaultBitmap()) return icon #---------------------------------------------------------------------- def getTreeDialogData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x00CIDAT(\x91c` \x11020000\xfc Z=\x07\x13\xa96\x90\xac\x81d\xc0\xc8\xc0\xc0\ p\xe1\xca\x05"U\x1b\xe8\x18\xd0\xde\x0fCO\xc3\x81\x03\x07(\xb5\x81\x85\xa0\ \x91\x044888\x90j\'\x01\x00\x00l\xe2\t]3\x1c\x89\xf6\x00\x00\x00\x00IEND\xae\ B`\x82' def getTreeDialogBitmap(): return BitmapFromImage(getTreeDialogImage()) def getTreeDialogImage(): stream = cStringIO.StringIO(getTreeDialogData()) return ImageFromStream(stream) def getTreeDialogIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeDialogBitmap()) return icon #---------------------------------------------------------------------- def getTreeFrameData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\ \x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ \x004IDAT(\x91c` \x11020000\xfc Z=\x07\x13\xa96\x90\xac\x81d\xc0\xc8\xc0\xc0\ p\xe1\xca\x05"U\x1b\xe8\x18\xd0\xde\x0f\xa3\x1ah\xa2\x81d\x00\x00*K\x04\x19\ \xfe\xab\xe3r\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeFrameBitmap(): return BitmapFromImage(getTreeFrameImage()) def getTreeFrameImage(): stream = cStringIO.StringIO(getTreeFrameData()) return ImageFromStream(stream) def getTreeFrameIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeFrameBitmap()) return icon #---------------------------------------------------------------------- def getTreeMenuData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00bIDAT8\x8dcddbf\x80\x81\xef\xbf\xbe\xfeg \x02p\xb0p002132000\xb0\xa0\ K\xde\xb8q\x03\xaf\xe6\x03\x07\x0e\xa0\xf01\x0c\xc0\xa6\x08\x06\x1c\x1c\x1c0\ \xc4\x98\xf0ZG\x04\xa0\xd8\x00\xac^\xc0\xe6T\x92\x0c\x18\r\x83\xd10\xc0\xe5\ \x7f\\\x80\x119;\xff\xff\xf7\x97\xa8\xec\xcc\xc0\xc0\x00\xcf\xce\x00\x8f\x14\ \x1a\x83cs\x82P\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeMenuBitmap(): return BitmapFromImage(getTreeMenuImage()) def getTreeMenuImage(): stream = cStringIO.StringIO(getTreeMenuData()) return ImageFromStream(stream) def getTreeMenuIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeMenuBitmap()) return icon #---------------------------------------------------------------------- def getTreeMenuBarData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00aIDAT8\x8d\xed\x93\xb1\r\x800\x0c\x04\xcf!E\xc6\xca\x98\x19\xc7cx\ \x94\x14HP "7)\x88\x0b(\xb8\xf2\xa5\x7f\xbdmY$mDH!\xf7\'\x02\xa4\xef\xfdX5\ \x97\\\xc8\x00f\xf6\xd8\xac\xaa\x00W\x80\x17<\xb5\xd6\xa9~\xf3\xfe\x12\xc7\ \x08\xbe\x96g\xa6\x8f\x80\xd6Z\xa8\x81\x00\xcbg\x04\x90\xff\x178\x01o\x9c\ \x13?\x8d\xde\xe5M\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeMenuBarBitmap(): return BitmapFromImage(getTreeMenuBarImage()) def getTreeMenuBarImage(): stream = cStringIO.StringIO(getTreeMenuBarData()) return ImageFromStream(stream) def getTreeMenuBarIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeMenuBarBitmap()) return icon #---------------------------------------------------------------------- def getTreeMenuItemData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00gIDAT(\x91\xc5RA\n\x800\x0cK\xbb\x1d\xf6\xac>}\xcf\xe8GD\x10t\x9e*\x0cu\ \x16\xaa\x98S[H\x9a@\x888!\x02\x0e\xb1\x01d\x1b\xe6ej^R\xc9\x05\xc4\x89:\x01\ \x00P\xd5Gr\xad\xb5\xdb\xdf\x8b0\xfab\x10\x91\xd3-\xec\xe0\x9b\x08WV]\x02w\ \xd9G kb\xdbVw\x0f\x00\x1c=\xa0\xdf\xab\x1c\x16\xd8\x01n\xd6\x12\xfe`\x9f\ \xfe\xd6\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeMenuItemBitmap(): return BitmapFromImage(getTreeMenuItemImage()) def getTreeMenuItemImage(): stream = cStringIO.StringIO(getTreeMenuItemData()) return ImageFromStream(stream) def getTreeMenuItemIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeMenuItemBitmap()) return icon #---------------------------------------------------------------------- def getTreePanelData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x02\ \x00\x00\x00\xa9M\x0b\xdd\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ \x00\x002IDAT(\x91c\xfc\xf1\xe7\x07\x03\xd1\x80\x83\x85\x83\x85\x81\x81\xe1\ \xc6\x8d\x1b\xc4\xa8>p\xe0\x00\x03\x03\x03\x13\xf1\xc6C\xc0\xa8\x86!\xaa\x81\ \x85\x01\x16\xe7\xb4\x02\x00vv\n&i\xb3\xa3d\x00\x00\x00\x00IEND\xaeB`\x82' def getTreePanelBitmap(): return BitmapFromImage(getTreePanelImage()) def getTreePanelImage(): stream = cStringIO.StringIO(getTreePanelData()) return ImageFromStream(stream) def getTreePanelIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreePanelBitmap()) return icon #---------------------------------------------------------------------- def getTreeRootData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ \xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ \xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ \x00IEND\xaeB`\x82' def getTreeRootBitmap(): return BitmapFromImage(getTreeRootImage()) def getTreeRootImage(): stream = cStringIO.StringIO(getTreeRootData()) return ImageFromStream(stream) def getTreeRootIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeRootBitmap()) return icon #---------------------------------------------------------------------- def getTreeSeparatorData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x007IDAT(\x91cddbf\xa0\x040Q\xa4{\xd4\x00\x06\x06\x06\x06\x06\x16\x18c\xf2\ \xe4\x89\xff\x89\xd5\x94\x9d\x95\xcd\xc0\xc4\xcc\xc2\x88b\x00L\x82T\xc08\x9a\ \x0e\x06\x81\x01\x00>\xbc\x05k_\x9b\x88\x1d\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeSeparatorBitmap(): return BitmapFromImage(getTreeSeparatorImage()) def getTreeSeparatorImage(): stream = cStringIO.StringIO(getTreeSeparatorData()) return ImageFromStream(stream) def getTreeSeparatorIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSeparatorBitmap()) return icon #---------------------------------------------------------------------- def getTreeSizerFlexGridData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00?IDAT8\x8dcddbf\x88O\x8a\xfd\xcf@.`dbfHHI\xf8\xcf\xc8\xc4\xcc\x80\ \x8c\xb1\x89aS\xc3D\xb6\xcdP0\xf0\x060\x8e\x06\xe2\xa8\x01\xd40\x80\xe2\x84\ \xc4\xc8\xc8\xc4L\x91\x0b\x00\xb7J\x13\xf6st\x19\xa8\x00\x00\x00\x00IEND\xae\ B`\x82' def getTreeSizerFlexGridBitmap(): return BitmapFromImage(getTreeSizerFlexGridImage()) def getTreeSizerFlexGridImage(): stream = cStringIO.StringIO(getTreeSizerFlexGridData()) return ImageFromStream(stream) def getTreeSizerFlexGridIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSizerFlexGridBitmap()) return icon #---------------------------------------------------------------------- def getTreeSizerGridData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00=IDAT8\x8dcddbf\x88O\x8a\xfd\xcf@.`dbfHHI\xf8\xcf\xc8\xc4\xcc\x80\r\ \x13\x92c"\xdbf(\x185\x80\x81\x81q4\x1a\x87\x83\x01\x14G###\x133E.\x00\x00\ \x18\x10\x13\xf65~\x97=\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeSizerGridBitmap(): return BitmapFromImage(getTreeSizerGridImage()) def getTreeSizerGridImage(): stream = cStringIO.StringIO(getTreeSizerGridData()) return ImageFromStream(stream) def getTreeSizerGridIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSizerGridBitmap()) return icon #---------------------------------------------------------------------- def getTreeSizerGridBagData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00SIDAT8\x8dcddbf\x88O\x8a\xfd\xcf@&`\x811\x16\xce[\xccH\xaa\xe6\xf8\ \xa4\xd8\xffL\xe4\xda\x0c\x03\x03o\x00<\x0c\xc8\x0eHF&f\x86\x84\x94\x84\xff\ \x8cL\xcc\x0c\xc8\x18\x9b\x1865\x03\x1f\x06\xa3\x06P\xc1\x00FJs###\x133E.\ \x00\x00\x9f\x06\x11@\\\xf4\xbaw\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeSizerGridBagBitmap(): return BitmapFromImage(getTreeSizerGridBagImage()) def getTreeSizerGridBagImage(): stream = cStringIO.StringIO(getTreeSizerGridBagData()) return ImageFromStream(stream) def getTreeSizerGridBagIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSizerGridBagBitmap()) return icon #---------------------------------------------------------------------- def getTreeSizerHData(): return \ "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00CIDAT8\x8dcddbf\xa0\x040Q\xa4\x9b\x1a\x06\xb00000\xc4'\xc5\xfe'\xdb\ \x04F&f\x86\x84\x94\x84\xff\x8cL\xcc\x0c\xd80!\xb9\x81\x0f\x83Q\x03\xa8`\x00\ ##\x133E\t\x89q\xe8g&\x00\xf6\x1a\x0b!P\x84!\x1e\x00\x00\x00\x00IEND\xaeB`\ \x82" def getTreeSizerHBitmap(): return BitmapFromImage(getTreeSizerHImage()) def getTreeSizerHImage(): stream = cStringIO.StringIO(getTreeSizerHData()) return ImageFromStream(stream) def getTreeSizerHIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSizerHBitmap()) return icon #---------------------------------------------------------------------- def getTreeSizerVData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00?IDAT8\x8dcddbf@\x06\xf1I\xb1\xff\x19\x08\x80\x85\xf3\x163\xc2\xd8,\ \x84\x14\xa0\x03t\x0b\x98\x08\xd9F\x08\x8c\x1a\x80#\x16\x88\x89J\xbc\x06\x8c\ F#\x9d\r\xa08\x1a\x19\xd1\xb33\xa9\x00\x00\xdc)\x10m\x19%\xbb-\x00\x00\x00\ \x00IEND\xaeB`\x82' def getTreeSizerVBitmap(): return BitmapFromImage(getTreeSizerVImage()) def getTreeSizerVImage(): stream = cStringIO.StringIO(getTreeSizerVData()) return ImageFromStream(stream) def getTreeSizerVIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeSizerVBitmap()) return icon #---------------------------------------------------------------------- def getTreeStaticBoxSizerHData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00iIDAT8\x8d\xed\x92\xd1\n\x800\x08E\xbd\xdao\x8e\xc9\xd8w\x05\xd1w.{\ \xe9a\xad\xa8\xad\x05\xbdt@\x04\x85\x83\\\x04X\xa8\x07.\x07\xb6${,\xb0%\x19X\ \xd0"\x19\x88\x88|p6\x8d3\xca\x0b|p\xf7"\xb0\x90F\xb5-\x8b]\xcfwg\xa5Q\x8d\ \x0b\x19\xf2^\xc3!\xc4V~\xc1\x0b\x02\x80\xa5\xeea\xae\x04=|\x9f\xc1\n5\x8d!\ \x0c[3\xf5K\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeStaticBoxSizerHBitmap(): return BitmapFromImage(getTreeStaticBoxSizerHImage()) def getTreeStaticBoxSizerHImage(): stream = cStringIO.StringIO(getTreeStaticBoxSizerHData()) return ImageFromStream(stream) def getTreeStaticBoxSizerHIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeStaticBoxSizerHBitmap()) return icon #---------------------------------------------------------------------- def getTreeStaticBoxSizerVData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00gIDAT8\x8d\xdd\x91A\n\xc0 \x0c\x047\xb1\xdf\x14\xc1\x87\t\xe2;5=)\ \xd2\x1a\xaa\xedAh \x97\x90\x1d\x92]"6\xd0JJ\x16bC\xea\x02\x00~\x12K\xc9\xb2\ \x04p\xde6A/v\xdeJ\xed\xa9\x0b\x00\xa0??\x86D1\xa4\xdb;*\xa0\x8a_{0[?\x00\ \x1c\xa3\xe15\xaae\xc0(.\r\xbe\xdf\x83\xfd\x80\xcf)\x9cv)$\xa7\x1d\x96\xa3\ \x0e\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeStaticBoxSizerVBitmap(): return BitmapFromImage(getTreeStaticBoxSizerVImage()) def getTreeStaticBoxSizerVImage(): stream = cStringIO.StringIO(getTreeStaticBoxSizerVData()) return ImageFromStream(stream) def getTreeStaticBoxSizerVIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeStaticBoxSizerVBitmap()) return icon #---------------------------------------------------------------------- def getTreeToolData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x00fIDAT(\x91cddbf\xa0\x040Q\xa4\x9b\x1a\x06\xb0\xa0\x0b|\xff\xf5\xf5?>\r\ \x1c,\x1c\x0c\x8cL\xcc\x8c8\r````\xb8q\xe3\x06V\xcd\x07\x0e\x1c\xc0\x10\xa3\ \xbe\x17p\xd9\xe8\xe0\xe0\x80U\xcd \x8c\x05d\x80\xcb\xd9\x04\r\xc0\x16\xda\ \xb8\x00#zR\xfe\xff\xef/\xdet\xc0\xc0\xc0\x80\x92\x0e0\x0c \x15P\x1c\x88\x00\ 4\x07\x12\xfeH\x0e\x8bL\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeToolBitmap(): return BitmapFromImage(getTreeToolImage()) def getTreeToolImage(): stream = cStringIO.StringIO(getTreeToolData()) return ImageFromStream(stream) def getTreeToolIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeToolBitmap()) return icon #---------------------------------------------------------------------- def getTreeToolBarData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ \x00\x00\x7fIDAT8\x8d\xed\x93\xb1\r\xc30\x0c\x04\x8f\xb6\n\x8f\xc2\xc2\x05G\ \xd0\x88.Rp\x1c\x8d\xa1QT\x04\xb0+\xdbR\x02\xc4\x88\xd5\xa4\xc8W:<\xfe!\x89\ \xa0\xc80\xd2\xa3\xa1+\xfd\x13\x05R\x9ee\xbd\x1b\x9e\xc2D\x00\xc89\x7f\x1dN)\ \x01\xd5\x13t6t\xb6\xc3P5TO65\xac\xe2]\xdd\x7f\x10\xf6\x83?\x96\xc6poyy\xe1\ \xb7\x82\x18cc\\\xf1Q\xe0\xee\x97\xd7\xfc$\x01n\x8f\x11@\xfe\xbb\xc0\x06\xdd\ \xdc\x1d\x0ba6\x83o\x00\x00\x00\x00IEND\xaeB`\x82' def getTreeToolBarBitmap(): return BitmapFromImage(getTreeToolBarImage()) def getTreeToolBarImage(): stream = cStringIO.StringIO(getTreeToolBarData()) return ImageFromStream(stream) def getTreeToolBarIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getTreeToolBarBitmap()) return icon #---------------------------------------------------------------------- def getUndoData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ \x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ \x03\x87IDAT8\x8d\x9d\x94Ml\x1bE\x18\x86\xdf\xd9\x1f\xef&\x1b;q\x88\x89\xb7\ \xc6I\x9c:\xa5\x81r(\x97\x08\xb5AJ\x88\x00\x81P\xa3\xc2\xa5\x08UUU\xa4\x9cz\ \x04q\x01\t\x158"@p\xa0Rd\xe5\xd2\xaa\x08)\x08T\t\xd1\xba\x8d1\x14\x1fZ(*\ \x12m\t\x10\xe7\xcfnj\xd7\xf2\xef\xda;;\xc3\x81\xddh\xeb\x9f\x1c2\xd2\xa7\ \x9d\xd9\xf9\xf4|\xef\xf7\xceh\x80\x1d\xc6\xe5\xf3\xa3\xa7\x921\xf0\x9dr:\r\ \xa1\xd3\xc6\xe2|xJ1\xfe>\xbb\x1bhG\xf0\xe2|xj@X\x8dO\xbc\xf8\xc2n\xb9\xad\ \xe0m\xe8\xcc\x18`\xad\xed\x1a,u\x82\x9a|\x18\xb2\xd4\r\xe0\x0f$c\xe0u\x137\ \r\x13\xbf\xd6\x19\xb9pcCN\x9c\xf9\xb0Q\xd9\t,\xb6\x83r\xba\x02x\x9e\x06!\ \x14{F4\x84FC\x08\x84\xf4`\x9fO,\x17r\xc5\xbdO\x01r\xf8\x04H\xbe\xa4\x1e+\xe4\xeeo\xd5*\x83\xdc\xa2\x168L\x98L\xec\ \xa1\xd9#:\xcd\x1e\xd1;\x82m\xf8\xd5\xb5\x9a\xfer\xea\xd2]@\x1au\xe7\to\x9c\ \xbe\x7f!\x93\'o\xae\xaf\x17\xa0t\xf5rj\xe68\xb3\x0cP\xa6\x822\xb5Eus!\x11\ \x80\xbc\xf0i\xf0\x95d\x0c\xdc~\x84<\xae\x90\x7f\x88\xf9\x0b\xb9\xdb\x07\xac\ \xbfRAz\xf1K/\x87\xeb\xac\x9a\x15\x13G\x15\xfe\xf7\xdds\xfct&~+;\xf8\xaa\xbd\ \xef\x06+"\xe1\x10\x04\xb9Q,u7,\xab\xbei\x8by\xa8{\xa9\t,\xdbI\x12\x00a\xee\ \xed\xec\x12\x80\x01\x00\xaa[U\x8d)\x19"iz)\xf7\xa7`R\xb2b\x17\xa4v0\x07L\ \xda(\x96\\*\x9c9\x01@\xce\x9e\xe9\x9d\xf5zI\xb0A\xe5\x8d\xb5M\x16\xa8\x14\ \xea\xe7\x01t\x03\xa8\xd9P\x0e\x80\xbb\x1f!\xd2\xa6\x88\xec\xeaB\xf4z!E\xf7i\ \xefD\xa2\xd5\xcc\xd7_-\xc9\xf7\xb2\xfc\x83\xf7>\xc1w\x00\x14\x00\xa6\x1d\ \x0c\x00\x17\x9b\xa0\xce\xe1\xb9\x8b\x89\x00H4*h\x0b\x1f\xfb?\xf7\xf7\x19\ \xa5\xf8R\xd9\xdaXa\xef\xbe\xff\x05\x12v\xfb\x0e\xd4\xb1\x82\x13\x17\xc0\xdd\ \xb6\x04@\x94eH\x93\x87\x14\xff\xe4AQ\xf7i\xac_U\xac\xf1J\x95\no}\xc4cv\xcb\ \x96\x1d\r;\xa8\xbdf\x8e\xc7x\xfd\x98\x87tuq\x8faH\xe4\xce\x1d\xc6,\x8b\x11p\ X\xafM\x9aZ\x7f?\x0b,\xa7\xcd\xf4\xbf\xcb\xb8\xf9\xd99<\xb0\xa1\xb0\xd51W\ \x01\xc7\xe3\x96\xfbG\xd0\xea\xb5\xbb+\xf7\x97\xbb\xc2)\xe0\xac\xf1\x1f\xd5\ \xbdu1\x93\x87\x18&\x00\x00\x00\x00IEND\xaeB`\x82' def getUndoBitmap(): return BitmapFromImage(getUndoImage()) def getUndoImage(): stream = cStringIO.StringIO(getUndoData()) return ImageFromStream(stream) def getUndoIcon(): icon = EmptyIcon() icon.CopyFromBitmap(getUndoBitmap()) return icon spe-0.8.4.h/_spe/plugins/XRCed/tree.py0000644000175000017500000016325410763311540016456 0ustar stanistani# Name: tree.py # Purpose: XRC editor, XML_tree class # Author: Roman Rolinsky # Created: 02.12.2002 # RCS-ID: $Id: tree.py,v 1.59 2007/05/14 12:24:44 ROL Exp $ from xxx import * # xxx imports globals and params import types import traceback # Constant to define standart window name STD_NAME = '_XRCED_T_W' # Icons import images class MemoryFile: def __init__(self, name): self.name = name self.buffer = '' def write(self, data): if g.currentEncoding: encoding = g.currentEncoding else: encoding = wx.GetDefaultPyEncoding() try: self.buffer += data.encode(encoding) except UnicodeEncodeError: self.buffer += data.encode(encoding, 'xmlcharrefreplace') def close(self): wx.MemoryFSHandler.AddFile(self.name, self.buffer) ################################################################################ # Redefine writing to include encoding class MyDocument(minidom.Document): def __init__(self): minidom.Document.__init__(self) self.encoding = '' def writexml(self, writer, indent="", addindent="", newl="", encoding=""): if encoding: encdstr = 'encoding="%s"' % encoding else: encdstr = '' writer.write('\n' % encdstr) for node in self.childNodes: node.writexml(writer, indent, addindent, newl) ################################################################################ # Ids for menu commands class ID_NEW: PANEL = wx.NewId() DIALOG = wx.NewId() FRAME = wx.NewId() TOOL_BAR = wx.NewId() TOOL = wx.NewId() MENU_BAR = wx.NewId() MENU = wx.NewId() STATUS_BAR = wx.NewId() STATIC_TEXT = wx.NewId() TEXT_CTRL = wx.NewId() BUTTON = wx.NewId() BITMAP_BUTTON = wx.NewId() RADIO_BUTTON = wx.NewId() SPIN_BUTTON = wx.NewId() TOGGLE_BUTTON = wx.NewId() STATIC_BOX = wx.NewId() CHECK_BOX = wx.NewId() RADIO_BOX = wx.NewId() COMBO_BOX = wx.NewId() LIST_BOX = wx.NewId() STATIC_LINE = wx.NewId() STATIC_BITMAP = wx.NewId() CHOICE = wx.NewId() SLIDER = wx.NewId() GAUGE = wx.NewId() SCROLL_BAR = wx.NewId() TREE_CTRL = wx.NewId() LIST_CTRL = wx.NewId() CHECK_LIST = wx.NewId() NOTEBOOK = wx.NewId() CHOICEBOOK = wx.NewId() LISTBOOK = wx.NewId() SPLITTER_WINDOW = wx.NewId() GRID = wx.NewId() SCROLLED_WINDOW = wx.NewId() HTML_WINDOW = wx.NewId() CALENDAR_CTRL = wx.NewId() DATE_CTRL = wx.NewId() FILE_PICKER_CTRL = wx.NewId() GENERIC_DIR_CTRL = wx.NewId() SPIN_CTRL = wx.NewId() UNKNOWN = wx.NewId() WIZARD = wx.NewId() WIZARD_PAGE = wx.NewId() WIZARD_PAGE_SIMPLE = wx.NewId() BITMAP = wx.NewId() ICON = wx.NewId() STATUS_BAR = wx.NewId() BOX_SIZER = wx.NewId() STATIC_BOX_SIZER = wx.NewId() GRID_SIZER = wx.NewId() FLEX_GRID_SIZER = wx.NewId() GRID_BAG_SIZER = wx.NewId() STD_DIALOG_BUTTON_SIZER = wx.NewId() SPACER = wx.NewId() TOOL_BAR = wx.NewId() TOOL = wx.NewId() MENU = wx.NewId() MENU_ITEM = wx.NewId() SEPARATOR = wx.NewId() OK_BUTTON = wx.NewId() YES_BUTTON = wx.NewId() SAVE_BUTTON = wx.NewId() APPLY_BUTTON = wx.NewId() NO_BUTTON = wx.NewId() CANCEL_BUTTON = wx.NewId() HELP_BUTTON = wx.NewId() CONTEXT_HELP_BUTTON = wx.NewId() REF = wx.NewId() COMMENT = wx.NewId() CUSTOM = wx.NewId() for i in range(99): wx.NewId() # reserve IDs for custom controls LAST = wx.NewId() class PullDownMenu: ID_EXPAND = wx.NewId() ID_COLLAPSE = wx.NewId() ID_PASTE_SIBLING = wx.NewId() ID_TOOL_PASTE = wx.NewId() ID_SUBCLASS = wx.NewId() def __init__(self, parent): self.ID_DELETE = parent.ID_DELETE wx.EVT_MENU_RANGE(parent, ID_NEW.PANEL, ID_NEW.LAST, parent.OnCreate) wx.EVT_MENU_RANGE(parent, 1000 + ID_NEW.PANEL, 1000 + ID_NEW.LAST, parent.OnReplace) wx.EVT_MENU(parent, self.ID_COLLAPSE, parent.OnCollapse) wx.EVT_MENU(parent, self.ID_EXPAND, parent.OnExpand) wx.EVT_MENU(parent, self.ID_PASTE_SIBLING, parent.OnPaste) wx.EVT_MENU(parent, self.ID_SUBCLASS, parent.OnSubclass) # We connect to tree, but process in frame wx.EVT_MENU_HIGHLIGHT_ALL(g.tree, parent.OnPullDownHighlight) # Mapping from IDs to element names self.createMap = { ID_NEW.PANEL: 'wxPanel', ID_NEW.DIALOG: 'wxDialog', ID_NEW.FRAME: 'wxFrame', ID_NEW.WIZARD: 'wxWizard', ID_NEW.WIZARD_PAGE: 'wxWizardPage', ID_NEW.WIZARD_PAGE_SIMPLE: 'wxWizardPageSimple', ID_NEW.TOOL_BAR: 'wxToolBar', ID_NEW.TOOL: 'tool', ID_NEW.STATUS_BAR: 'wxStatusBar', ID_NEW.MENU_BAR: 'wxMenuBar', ID_NEW.MENU: 'wxMenu', ID_NEW.MENU_ITEM: 'wxMenuItem', ID_NEW.BITMAP: 'wxBitmap', ID_NEW.ICON: 'wxIcon', ID_NEW.SEPARATOR: 'separator', ID_NEW.STATIC_TEXT: 'wxStaticText', ID_NEW.TEXT_CTRL: 'wxTextCtrl', ID_NEW.BUTTON: 'wxButton', ID_NEW.BITMAP_BUTTON: 'wxBitmapButton', ID_NEW.RADIO_BUTTON: 'wxRadioButton', ID_NEW.SPIN_BUTTON: 'wxSpinButton', ID_NEW.TOGGLE_BUTTON: 'wxToggleButton', ID_NEW.STATIC_BOX: 'wxStaticBox', ID_NEW.CHECK_BOX: 'wxCheckBox', ID_NEW.RADIO_BOX: 'wxRadioBox', ID_NEW.COMBO_BOX: 'wxComboBox', ID_NEW.LIST_BOX: 'wxListBox', ID_NEW.CHECK_LIST: 'wxCheckListBox', ID_NEW.STATIC_LINE: 'wxStaticLine', ID_NEW.STATIC_BITMAP: 'wxStaticBitmap', ID_NEW.CHOICE: 'wxChoice', ID_NEW.SLIDER: 'wxSlider', ID_NEW.GAUGE: 'wxGauge', ID_NEW.SCROLL_BAR: 'wxScrollBar', ID_NEW.TREE_CTRL: 'wxTreeCtrl', ID_NEW.LIST_CTRL: 'wxListCtrl', ID_NEW.NOTEBOOK: 'wxNotebook', ID_NEW.CHOICEBOOK: 'wxChoicebook', ID_NEW.LISTBOOK: 'wxListbook', ID_NEW.SPLITTER_WINDOW: 'wxSplitterWindow', ID_NEW.GRID: 'wxGrid', ID_NEW.SCROLLED_WINDOW: 'wxScrolledWindow', ID_NEW.HTML_WINDOW: 'wxHtmlWindow', ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl', ID_NEW.DATE_CTRL: 'wxDatePickerCtrl', ID_NEW.FILE_PICKER_CTRL: 'wxFilePickerCtrl', ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl', ID_NEW.SPIN_CTRL: 'wxSpinCtrl', ID_NEW.BOX_SIZER: 'wxBoxSizer', ID_NEW.STATIC_BOX_SIZER: 'wxStaticBoxSizer', ID_NEW.GRID_SIZER: 'wxGridSizer', ID_NEW.FLEX_GRID_SIZER: 'wxFlexGridSizer', ID_NEW.GRID_BAG_SIZER: 'wxGridBagSizer', ID_NEW.STD_DIALOG_BUTTON_SIZER: 'wxStdDialogButtonSizer', ID_NEW.SPACER: 'spacer', ID_NEW.UNKNOWN: 'unknown', ID_NEW.OK_BUTTON: 'wxButton', ID_NEW.YES_BUTTON: 'wxButton', ID_NEW.SAVE_BUTTON: 'wxButton', ID_NEW.APPLY_BUTTON: 'wxButton', ID_NEW.NO_BUTTON: 'wxButton', ID_NEW.CANCEL_BUTTON: 'wxButton', ID_NEW.HELP_BUTTON: 'wxButton', ID_NEW.CONTEXT_HELP_BUTTON: 'wxButton', } self.topLevel = [ (ID_NEW.PANEL, 'Panel', 'Create panel'), (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), (ID_NEW.FRAME, 'Frame', 'Create frame'), (ID_NEW.WIZARD, 'Wizard', 'Create wizard'), None, (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), (ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar'), (ID_NEW.MENU, 'Menu', 'Create menu'), None, (ID_NEW.BITMAP, 'Bitmap', 'Create bitmap'), (ID_NEW.ICON, 'Icon', 'Create icon'), ] self.containers = [ (ID_NEW.PANEL, 'Panel', 'Create panel'), (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), (ID_NEW.CHOICEBOOK, 'Choicebook', 'Create choicebook control'), (ID_NEW.LISTBOOK, 'Listbook', 'Create listbook control'), (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), (ID_NEW.STATUS_BAR, 'StatusBar', 'Create status bar'), # (ID_NEW.WIZARD_PAGE, 'WizardPage', 'Create wizard page'), (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), ] self.sizers = [ (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', 'Create static box sizer'), (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', 'Create flexgrid sizer'), (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', 'Create gridbag sizer'), # (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', # 'Create standard button sizer'), (ID_NEW.SPACER, 'Spacer', 'Create spacer'), ] self.controls = [ ['control', 'Various controls', (ID_NEW.STATIC_TEXT, 'Label', 'Create label'), (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'), (ID_NEW.STATIC_LINE, 'Line', 'Create line'), (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'), (ID_NEW.CHOICE, 'Choice', 'Create choice'), (ID_NEW.SLIDER, 'Slider', 'Create slider'), (ID_NEW.GAUGE, 'Gauge', 'Create gauge'), (ID_NEW.SPIN_CTRL, 'SpinCtrl', 'Create spin'), (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'), (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'), # (ID_NEW.GRID, 'Grid', 'Create grid'), (ID_NEW.SCROLLED_WINDOW, 'ScrolledWindow', 'Create scrolled window'), (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'), (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'), (ID_NEW.DATE_CTRL, 'DatePickerCtrl', 'Create date picker control'), # (ID_NEW.FILE_PICKER_CTRL, 'FilePickerCtrl', 'Create file picker control'), (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'), (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'), ], ['button', 'Buttons', (ID_NEW.BUTTON, 'Button', 'Create button'), (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), (ID_NEW.TOGGLE_BUTTON, 'ToggleButton', 'Create toggle button'), ], ['box', 'Boxes', (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), (ID_NEW.CHECK_LIST, 'CheckListBox', 'Create checklist box'), ], ['container', 'Containers', (ID_NEW.PANEL, 'Panel', 'Create panel'), (ID_NEW.NOTEBOOK, 'Notebook', 'Create notebook control'), (ID_NEW.CHOICEBOOK, 'Choicebook', 'Create choicebook control'), (ID_NEW.LISTBOOK, 'Listbook', 'Create listbook control'), (ID_NEW.SPLITTER_WINDOW, 'SplitterWindow', 'Create splitter window'), (ID_NEW.TOOL_BAR, 'ToolBar', 'Create toolbar'), (ID_NEW.STATUS_BAR, 'StatusBar', 'Create status bar'), (ID_NEW.MENU_BAR, 'MenuBar', 'Create menubar'), # (ID_NEW.WIZARD_PAGE, 'Wizard Page', 'Create wizard page'), (ID_NEW.WIZARD_PAGE_SIMPLE, 'WizardPageSimple', 'Create simple wizard page'), ], ['sizer', 'Sizers', (ID_NEW.BOX_SIZER, 'BoxSizer', 'Create box sizer'), (ID_NEW.STATIC_BOX_SIZER, 'StaticBoxSizer', 'Create static box sizer'), (ID_NEW.GRID_SIZER, 'GridSizer', 'Create grid sizer'), (ID_NEW.FLEX_GRID_SIZER, 'FlexGridSizer', 'Create flexgrid sizer'), (ID_NEW.GRID_BAG_SIZER, 'GridBagSizer', 'Create gridbag sizer'), (ID_NEW.SPACER, 'Spacer', 'Create spacer'), (ID_NEW.STD_DIALOG_BUTTON_SIZER, 'StdDialogButtonSizer', 'Create standard button sizer'), ] ] self.menuControls = [ (ID_NEW.MENU, 'Menu', 'Create menu'), (ID_NEW.MENU_ITEM, 'MenuItem', 'Create menu item'), (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), ] self.toolBarControls = [ (ID_NEW.TOOL, 'Tool', 'Create tool'), (ID_NEW.SEPARATOR, 'Separator', 'Create separator'), ['control', 'Various controls', (ID_NEW.STATIC_TEXT, 'Label', 'Create label'), (ID_NEW.STATIC_BITMAP, 'Bitmap', 'Create bitmap'), (ID_NEW.STATIC_LINE, 'Line', 'Create line'), (ID_NEW.TEXT_CTRL, 'TextBox', 'Create text box'), (ID_NEW.CHOICE, 'Choice', 'Create choice'), (ID_NEW.SLIDER, 'Slider', 'Create slider'), (ID_NEW.GAUGE, 'Gauge', 'Create gauge'), (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list control'), ], ['button', 'Buttons', (ID_NEW.BUTTON, 'Button', 'Create button'), (ID_NEW.BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'), (ID_NEW.RADIO_BUTTON, 'RadioButton', 'Create radio button'), (ID_NEW.SPIN_BUTTON, 'SpinButton', 'Create spin button'), ], ['box', 'Boxes', (ID_NEW.STATIC_BOX, 'StaticBox', 'Create static box'), (ID_NEW.CHECK_BOX, 'CheckBox', 'Create check box'), (ID_NEW.RADIO_BOX, 'RadioBox', 'Create radio box'), (ID_NEW.COMBO_BOX, 'ComboBox', 'Create combo box'), (ID_NEW.LIST_BOX, 'ListBox', 'Create list box'), (ID_NEW.CHECK_LIST, 'CheckListBox', 'Create checklist box'), ], ] self.stdButtons = [ (ID_NEW.OK_BUTTON, 'OK Button', 'Create standard button'), (ID_NEW.YES_BUTTON, 'YES Button', 'Create standard button'), (ID_NEW.SAVE_BUTTON, 'SAVE Button', 'Create standard button'), (ID_NEW.APPLY_BUTTON, 'APPLY Button', 'Create standard button'), (ID_NEW.NO_BUTTON, 'NO Button', 'Create standard button'), (ID_NEW.CANCEL_BUTTON, 'CANCEL Button', 'Create standard button'), (ID_NEW.HELP_BUTTON, 'HELP Button', 'Create standard button'), (ID_NEW.CONTEXT_HELP_BUTTON, 'CONTEXT HELP Button', 'Create standard button'), ] self.stdButtonIDs = { ID_NEW.OK_BUTTON: ('wxID_OK', '&Ok'), ID_NEW.YES_BUTTON: ('wxID_YES', '&Yes'), ID_NEW.SAVE_BUTTON: ('wxID_SAVE', '&Save'), ID_NEW.APPLY_BUTTON: ('wxID_APPLY', '&Apply'), ID_NEW.NO_BUTTON: ('wxID_NO', '&No'), ID_NEW.CANCEL_BUTTON: ('wxID_CANCEL', '&Cancel'), ID_NEW.HELP_BUTTON: ('wxID_HELP', '&Help'), ID_NEW.CONTEXT_HELP_BUTTON: ('wxID_CONTEXT_HELP', '&Help'), } self.custom = ['custom', 'User-defined controls'] self.customMap = {} def addCustom(self, klass): n = len(self.custom)-2 self.custom.append((ID_NEW.CUSTOM + n, klass)) self.customMap[ID_NEW.CUSTOM + n] = klass ################################################################################ # Set menu to list items. # Each menu command is a tuple (id, label, help) # submenus are lists [id, label, help, submenu] # and separators are any other type. Shift is for making # alternative sets of IDs. (+1000). def SetMenu(m, list, shift=False): for l in list: if type(l) == types.TupleType: # Shift ID if shift: l = (1000 + l[0],) + l[1:] apply(m.Append, l) elif type(l) == types.ListType: subMenu = wx.Menu() SetMenu(subMenu, l[2:], shift) m.AppendMenu(wx.NewId(), l[0], subMenu, l[1]) else: # separator m.AppendSeparator() ################################################################################ class HighLightBox: colour = None def __init__(self, pos, size): colour = g.tree.COLOUR_HL if size.width == -1: size.width = 0 if size.height == -1: size.height = 0 w = g.testWin.panel l1 = wx.Window(w, -1, pos, wx.Size(size.width, 2)) l1.SetBackgroundColour(colour) l2 = wx.Window(w, -1, pos, wx.Size(2, size.height)) l2.SetBackgroundColour(colour) l3 = wx.Window(w, -1, wx.Point(pos.x + size.width - 2, pos.y), wx.Size(2, size.height)) l3.SetBackgroundColour(colour) l4 = wx.Window(w, -1, wx.Point(pos.x, pos.y + size.height - 2), wx.Size(size.width, 2)) l4.SetBackgroundColour(colour) self.lines = [l1, l2, l3, l4] if wx.Platform == '__WXMSW__': for l in self.lines: l.Bind(wx.EVT_PAINT, self.OnPaint) g.testWin.highLight = self self.size = size # Repainting is not always done for these windows on Windows def OnPaint(self, evt): w = evt.GetEventObject() dc = wx.PaintDC(w) w.ClearBackground() dc.Destroy() # Move highlight to a new position def Replace(self, pos, size): if size.width == -1: size.width = 0 if size.height == -1: size.height = 0 self.lines[0].SetDimensions(pos.x, pos.y, size.width, 2) self.lines[1].SetDimensions(pos.x, pos.y, 2, size.height) self.lines[2].SetDimensions(pos.x + size.width - 2, pos.y, 2, size.height) self.lines[3].SetDimensions(pos.x, pos.y + size.height - 2, size.width, 2) self.size = size def Remove(self): map(wx.Window.Destroy, self.lines) g.testWin.highLight = None def Refresh(self): map(wx.Window.Refresh, self.lines) # Same for drop target class HighLightDTBox(HighLightBox): colour = None def __init__(self, pos, size): colour = g.tree.COLOUR_DT if size.width == -1: size.width = 0 if size.height == -1: size.height = 0 w = g.testWin.panel l1 = wx.Window(w, -1, pos, wx.Size(size.width, 2)) l1.SetBackgroundColour(colour) l2 = wx.Window(w, -1, pos, wx.Size(2, size.height)) l2.SetBackgroundColour(colour) l3 = wx.Window(w, -1, wx.Point(pos.x + size.width - 2, pos.y), wx.Size(2, size.height)) l3.SetBackgroundColour(colour) l4 = wx.Window(w, -1, wx.Point(pos.x, pos.y + size.height - 2), wx.Size(size.width, 2)) l4.SetBackgroundColour(colour) self.lines = [l1, l2, l3, l4] self.item = None self.size = size # Remove it def Remove(self): map(wx.Window.Destroy, self.lines) g.testWin.highLightDT = None def updateHL(hl, hlClass, pos, size): # Need to recreate window if size did not change to force update if hl and hl.size == size: hl.Remove() hl = None if hl: hl.Replace(pos, size) else: hl = hlClass(pos, size) hl.Refresh() return hl ################################################################################ class XML_Tree(wx.TreeCtrl): def __init__(self, parent, id): # Item colour self.COLOUR_COMMENT = wx.Colour(0, 0, 255) self.COLOUR_REF = wx.Colour(0, 0, 128) self.COLOUR_HIDDEN = wx.Colour(128, 128, 128) self.COLOUR_HL = wx.Colour(255, 0, 0) self.COLOUR_DT = wx.Colour(0, 64, 0) wx.TreeCtrl.__init__(self, parent, id, style = wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE | wx.TR_EDIT_LABELS) self.SetBackgroundColour(wx.Colour(224, 248, 224)) self.fontComment = wx.FFont(self.GetFont().GetPointSize(), self.GetFont().GetFamily(), wx.FONTFLAG_ITALIC) # Register events wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) # One works on Linux, another on Windows if wx.Platform == '__WXGTK__': # !!! MAC too? wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated) else: wx.EVT_LEFT_DCLICK(self, self.OnDClick) wx.EVT_RIGHT_DOWN(self, self.OnRightDown) wx.EVT_TREE_ITEM_EXPANDED(self, self.GetId(), self.OnItemExpandedCollapsed) wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemExpandedCollapsed) self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginLabelEdit) self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndLabelEdit) self.selection = None self.selectionChanging = False self.needUpdate = False self.pendingHighLight = None self.ctrl = self.shift = False self.dom = None # Create image list il = wx.ImageList(16, 16, True) self.rootImage = il.Add(images.getTreeRootImage().Scale(16,16).ConvertToBitmap()) xxxComment.image = il.Add(images.getTreeCommentImage().Scale(16,16).ConvertToBitmap()) xxxObject.image = il.Add(images.getTreeDefaultImage().Scale(16,16).ConvertToBitmap()) xxxPanel.image = il.Add(images.getTreePanelImage().Scale(16,16).ConvertToBitmap()) xxxDialog.image = il.Add(images.getTreeDialogImage().Scale(16,16).ConvertToBitmap()) xxxFrame.image = il.Add(images.getTreeFrameImage().Scale(16,16).ConvertToBitmap()) xxxMenuBar.image = il.Add(images.getTreeMenuBarImage().Scale(16,16).ConvertToBitmap()) xxxMenu.image = il.Add(images.getTreeMenuImage().Scale(16,16).ConvertToBitmap()) xxxMenuItem.image = il.Add(images.getTreeMenuItemImage().Scale(16,16).ConvertToBitmap()) xxxToolBar.image = il.Add(images.getTreeToolBarImage().Scale(16,16).ConvertToBitmap()) xxxTool.image = il.Add(images.getTreeToolImage().Scale(16,16).ConvertToBitmap()) xxxSeparator.image = il.Add(images.getTreeSeparatorImage().Scale(16,16).ConvertToBitmap()) xxxSizer.imageH = il.Add(images.getTreeSizerHImage().Scale(16,16).ConvertToBitmap()) xxxSizer.imageV = il.Add(images.getTreeSizerVImage().Scale(16,16).ConvertToBitmap()) xxxStaticBoxSizer.imageH = il.Add(images.getTreeStaticBoxSizerHImage().Scale(16,16).ConvertToBitmap()) xxxStaticBoxSizer.imageV = il.Add(images.getTreeStaticBoxSizerVImage().Scale(16,16).ConvertToBitmap()) xxxGridSizer.image = il.Add(images.getTreeSizerGridImage().Scale(16,16).ConvertToBitmap()) xxxFlexGridSizer.image = il.Add(images.getTreeSizerFlexGridImage().Scale(16,16).ConvertToBitmap()) self.il = il self.SetImageList(il) def RegisterKeyEvents(self): wx.EVT_KEY_DOWN(self, g.tools.OnKeyDown) wx.EVT_KEY_UP(self, g.tools.OnKeyUp) wx.EVT_ENTER_WINDOW(self, g.tools.OnMouse) wx.EVT_LEAVE_WINDOW(self, g.tools.OnMouse) def ExpandAll(self, item): if self.ItemHasChildren(item): self.Expand(item) i, cookie = self.GetFirstChild(item) children = [] while i.IsOk(): children.append(i) i, cookie = self.GetNextChild(item, cookie) for i in children: self.ExpandAll(i) def CollapseAll(self, item): if self.ItemHasChildren(item): i, cookie = self.GetFirstChild(item) children = [] while i.IsOk(): children.append(i) i, cookie = self.GetNextChild(item, cookie) for i in children: self.CollapseAll(i) self.Collapse(item) # Clear tree def Clear(self): self.UnselectAll() self.DeleteAllItems() # Add minimal structure if self.dom: self.dom.unlink() self.dom = MyDocument() self.dummyNode = self.dom.createComment('dummy node') # Create main node self.mainNode = self.dom.createElement('resource') self.dom.appendChild(self.mainNode) self.rootObj = xxxMainNode(self.dom) self.root = self.AddRoot('XML tree', self.rootImage, data=wx.TreeItemData(self.rootObj)) self.itemColour = self.GetItemTextColour(self.root) self.SetItemHasChildren(self.root) self.testElem = self.dom.createElement('dummy') self.mainNode.appendChild(self.testElem) self.Expand(self.root) # Clear old data and set new def SetData(self, dom): self.UnselectAll() self.DeleteAllItems() # Add minimal structure if self.dom: self.dom.unlink() self.dom = dom self.dummyNode = self.dom.createComment('dummy node') # Find 'resource' child, add it's children self.mainNode = dom.documentElement self.rootObj = xxxMainNode(self.dom) self.root = self.AddRoot('XML tree', self.rootImage, data=wx.TreeItemData(self.rootObj)) self.SetItemHasChildren(self.root) nodes = self.mainNode.childNodes[:] for node in nodes: if IsObject(node): self.AddNode(self.root, None, node) else: self.mainNode.removeChild(node) node.unlink() if self.mainNode.firstChild: self.testElem = self.dom.createElement('dummy') self.mainNode.insertBefore(self.testElem, self.mainNode.firstChild) else: self.testElem = self.dom.createElement('dummy') self.mainNode.appendChild(self.testElem) self.Expand(self.root) # Add tree item for given parent item if node is DOM element node with # object/object_ref tag. xxxParent is parent xxx object def AddNode(self, itemParent, xxxParent, node): # Set item data to current node try: xxx = MakeXXXFromDOM(xxxParent, node) except: print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent, node) raise treeObj = xxx.treeObject() # Append tree item item = self.AppendItem(itemParent, treeObj.treeName(), image=treeObj.treeImage(), data=wx.TreeItemData(xxx)) # Different color for comments and references if xxx.className == 'comment': self.SetItemTextColour(item, self.COLOUR_COMMENT) self.SetItemFont(item, self.fontComment) elif treeObj.ref: self.SetItemTextColour(item, self.COLOUR_REF) elif treeObj.hasStyle and treeObj.params.get('hidden', False): self.SetItemTextColour(item, self.COLOUR_HIDDEN) # Try to find children objects if treeObj.hasChildren: nodes = treeObj.node.childNodes[:] for n in nodes: if IsObject(n): self.AddNode(item, treeObj, n) elif n.nodeType != minidom.Node.ELEMENT_NODE: treeObj.node.removeChild(n) n.unlink() # Insert new item at specific position def InsertNode(self, itemParent, parent, elem, nextItem): # Insert in XML tree and wxWin xxx = MakeXXXFromDOM(parent, elem) # If nextItem is None, we append to parent, otherwise insert before it if nextItem.IsOk(): node = self.GetPyData(nextItem).node parent.node.insertBefore(elem, node) # Inserting before is difficult, se we insert after or first child index = self.ItemIndex(nextItem) newItem = self.InsertItemBefore(itemParent, index, xxx.treeName(), image=xxx.treeImage()) self.SetPyData(newItem, xxx) else: parent.node.appendChild(elem) newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(), data=wx.TreeItemData(xxx)) treeObj = xxx.treeObject() # Different color for references and comments if xxx.className == 'comment': self.SetItemTextColour(newItem, self.COLOUR_COMMENT) self.SetItemFont(newItem, self.fontComment) elif treeObj.ref: self.SetItemTextColour(newItem, self.COLOUR_REF) elif treeObj.hasStyle and treeObj.params.get('hidden', False): self.SetItemTextColour(newItem, self.COLOUR_HIDDEN) # Add children items if xxx.hasChildren: treeObj = xxx.treeObject() for n in treeObj.node.childNodes: if IsObject(n): self.AddNode(newItem, treeObj, n) return newItem # Remove leaf of tree, return it's data object def RemoveLeaf(self, leaf): xxx = self.GetPyData(leaf) node = xxx.node parent = node.parentNode parent.removeChild(node) self.Delete(leaf) return node # Find position relative to the top-level window def FindNodePos(self, item, obj=None): # Root at (0,0) if item == g.testWin.item: return wx.Point(0, 0) itemParent = self.GetItemParent(item) # Select book page if not obj: obj = self.FindNodeObject(item) if self.GetPyData(itemParent).treeObject().__class__ in \ [xxxNotebook, xxxChoicebook, xxxListbook]: book = self.FindNodeObject(itemParent) # Find position for i in range(book.GetPageCount()): if book.GetPage(i) == obj: if book.GetSelection() != i: book.SetSelection(i) # Remove highlight - otherwise highlight window won't be visible if g.testWin.highLight: g.testWin.highLight.Remove() break # For sizers and notebooks we must select the first window-like parent winParent = itemParent while self.GetPyData(winParent).isSizer: winParent = self.GetItemParent(winParent) # Notebook children are layed out in a little strange way # wxGTK places NB panels relative to the NB parent if wx.Platform == '__WXGTK__': if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: winParent = self.GetItemParent(winParent) parentPos = self.FindNodePos(winParent) pos = obj.GetPosition() # Position (-1,-1) is really (0,0) if pos == (-1,-1): pos = (0,0) return parentPos + pos # Find window (or sizer) corresponding to a tree item. def FindNodeObject(self, item): testWin = g.testWin # If top-level, return testWin (or panel its panel) if item == testWin.item: return testWin.panel itemParent = self.GetItemParent(item) xxx = self.GetPyData(item).treeObject() parentWin = self.FindNodeObject(itemParent) # Top-level sizer? return window's sizer if xxx.isSizer and isinstance(parentWin, wx.Window): return parentWin.GetSizer() elif xxx.__class__ in [xxxMenu, xxxMenuItem, xxxSeparator]: return None elif xxx.__class__ in [xxxToolBar, xxxMenuBar]: # If it's the main toolbar or menubar, we can't really select it if xxx.parent.__class__ == xxxFrame: return None elif isinstance(xxx.parent, xxxToolBar): # Select complete toolbar return parentWin elif isinstance(xxx.parent, xxxStdDialogButtonSizer): # This sizer returns non-existing children for ch in parentWin.GetChildren(): if ch.GetWindow() and ch.GetWindow().GetName() == xxx.name: return ch.GetWindow() return None elif xxx.parent.__class__ in [xxxChoicebook, xxxListbook]: # First window is controld return parentWin.GetChildren()[self.ItemIndex(item)+1] # Otherwise get parent's object and it's child child = parentWin.GetChildren()[self.WindowIndex(item)] # Return window or sizer for sizer items if child.GetClassName() == 'wxSizerItem': if child.IsWindow(): child = child.GetWindow() elif child.IsSizer(): child = child.GetSizer() return child def OnSelChanged(self, evt): if self.selectionChanging: return self.selectionChanging = True wx.TreeCtrl.UnselectAll(self) self.ChangeSelection(evt.GetItem()) wx.TreeCtrl.SelectItem(self, evt.GetItem()) self.selectionChanging = False g.frame.SetStatusText('') evt.Skip() # Override to use like single-selection tree def GetSelection(self): return self.selection def SelectItem(self, item): self.UnselectAll() self.ChangeSelection(item) wx.TreeCtrl.SelectItem(self, item) def UnselectAll(self): self.selection = None g.tools.UpdateUI() wx.TreeCtrl.UnselectAll(self) #wx.Yield() def ChangeSelection(self, item): # Apply changes # !!! problem with wxGTK - GetOldItem is Ok if nothing selected #oldItem = evt.GetOldItem() status = '' oldItem = self.selection if oldItem: xxx = self.GetPyData(oldItem) # If some data was modified, apply changes if g.panel.IsModified(): self.Apply(xxx, oldItem) if g.testWin: if g.testWin.highLight: g.testWin.highLight.Remove() self.needUpdate = True status = 'Changes were applied' if status: g.frame.SetStatusText(status) # Generate view if not item: self.selection = None return else: self.selection = item xxx = self.GetPyData(item) # Update panel g.panel.SetData(xxx) # Update tools g.tools.UpdateUI() # Highlighting is done in OnIdle self.pendingHighLight = self.selection # Check if item is in testWin subtree def IsHighlatable(self, item): if item == g.testWin.item: return False while item != self.root: item = self.GetItemParent(item) if item == g.testWin.item: return True return False # Highlight selected item def HighLight(self, item): self.pendingHighLight = None # Can highlight only with some top-level windows if not g.testWin or self.GetPyData(g.testWin.item).treeObject().__class__ \ not in [xxxDialog, xxxPanel, xxxFrame]: return # If a control from another window is selected, remove highlight if not self.IsHighlatable(item): if g.testWin.highLight: g.testWin.highLight.Remove() return # Get window/sizer object obj = self.FindNodeObject(item) xxx = self.GetPyData(item).treeObject() # Remove existing HL if item not found or is hidden if not obj or xxx.hasStyle and xxx.params.get('hidden', False): if g.testWin.highLight: g.testWin.highLight.Remove() return pos = self.FindNodePos(item, obj) size = obj.GetSize() # Highlight # Negative positions are not working quite well # If highlight object has the same size SetDimension does not repaint it # so we must remove the old HL window g.testWin.highLight = updateHL(g.testWin.highLight, HighLightBox, pos, size) g.testWin.highLight.item = item g.testWin.highLight.obj = obj def ShowTestWindow(self, item): xxx = self.GetPyData(item) if g.panel.IsModified(): self.Apply(xxx, item) # apply changes availableViews = ['wxFrame', 'wxPanel', 'wxDialog', 'wxMenuBar', 'wxToolBar', 'wxWizard', 'wxWizardPageSimple'] originalItem = item # Walk up the tree until we find an item that has a view while item and self.GetPyData(item).treeObject().className not in availableViews: item = self.GetItemParent(item) if not item or not item.IsOk(): wx.LogMessage('No view for this element (yet)') return # Show item in bold if g.testWin: # Reset old self.UnselectAll() self.SetItemBold(g.testWin.item, False) try: wx.BeginBusyCursor() self.CreateTestWin(item) finally: wx.EndBusyCursor() # Maybe an error occurred, so we need to test if g.testWin: self.SetItemBold(g.testWin.item) # Select original item self.ChangeSelection(originalItem) # Double-click on Linux def OnItemActivated(self, evt): if evt.GetItem() != self.root: self.ShowTestWindow(evt.GetItem()) # Double-click on Windows def OnDClick(self, evt): item, flags = self.HitTest(evt.GetPosition()) if flags in [wx.TREE_HITTEST_ONITEMBUTTON, wx.TREE_HITTEST_ONITEMLABEL]: if item != self.root: self.ShowTestWindow(item) else: evt.Skip() def OnItemExpandedCollapsed(self, evt): # Update tool palette g.tools.UpdateUI() evt.Skip() # (re)create test window def CreateTestWin(self, item): testWin = g.testWin # Create a window with this resource xxx = self.GetPyData(item).treeObject() # Close old window, remember where it was highLight = None if testWin: pos = testWin.GetPosition() if item == testWin.item: # Remember highlight if same top-level window if testWin.highLight: highLight = testWin.highLight.item if xxx.className == 'wxPanel': if testWin.highLight: testWin.pendingHighLight = highLight testWin.highLight.Remove() testWin.panel.Destroy() testWin.panel = None else: testWin.Destroy() testWin = g.testWin = None else: testWin.Destroy() testWin = g.testWin = None else: pos = g.testWinPos # Save in memory FS memFile = MemoryFile('xxx.xrc') # Create memory XML file elem = xxx.node.cloneNode(True) if not xxx.name: name = 'noname' else: name = xxx.name elem.setAttribute('name', STD_NAME) oldTestNode = self.testElem self.testElem = elem self.mainNode.replaceChild(elem, oldTestNode) oldTestNode.unlink() # Replace wizard page class temporarily if xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: oldCl = elem.getAttribute('class') elem.setAttribute('class', 'wxPanel') parent = elem.parentNode encd = self.rootObj.params['encoding'].value() if not encd: encd = None try: self.dom.writexml(memFile, encoding=encd) except: inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error writing temporary file') memFile.close() # write to wxMemoryFS xmlFlags = xrc.XRC_NO_SUBCLASSING # Use translations if encoding is not specified if not g.currentEncoding: xmlFlags != xrc.XRC_USE_LOCALE res = xrc.XmlResource('', xmlFlags) res.InitAllHandlers() xrc.XmlResource.Set(res) # set as global # Register handlers addHandlers() # Same module list res.Load('memory:xxx.xrc') try: if xxx.__class__ == xxxFrame: # Frame can't have many children, # but it's first child possibly can... # child = self.GetFirstChild(item)[0] # if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel: # # Clean-up before recursive call or error # wx.MemoryFSHandler.RemoveFile('xxx.xrc') # wx.EndBusyCursor() # self.CreateTestWin(child) # return # This currently works under GTK, but not under MSW testWin = g.testWin = wx.PreFrame() res.LoadOnFrame(testWin, g.frame, STD_NAME) # Create status bar testWin.panel = testWin #testWin.CreateStatusBar() testWin.SetClientSize(testWin.GetBestSize()) testWin.SetPosition(pos) testWin.Show(True) elif xxx.__class__ == xxxPanel: # Create new frame if not testWin: testWin = g.testWin = wx.Frame(g.frame, -1, 'Panel: ' + name, pos=pos, name=STD_NAME) testWin.panel = res.LoadPanel(testWin, STD_NAME) testWin.panel.SetSize(testWin.GetClientSize()) #testWin.SetClientSize(testWin.GetSize()) testWin.Show(True) elif xxx.__class__ == xxxDialog: testWin = g.testWin = res.LoadDialog(g.frame, STD_NAME) testWin.panel = testWin testWin.Layout() testWin.SetPosition(pos) testWin.Show(True) # Dialog's default code does not produce wx.EVT_CLOSE wx.EVT_BUTTON(testWin, wx.ID_OK, self.OnCloseTestWin) wx.EVT_BUTTON(testWin, wx.ID_CANCEL, self.OnCloseTestWin) elif xxx.__class__ == xxxWizard: wiz = wx.wizard.PreWizard() res.LoadOnObject(wiz, g.frame, STD_NAME, 'wxWizard') # Find first page (don't know better way) firstPage = None for w in wiz.GetChildren(): if isinstance(w, wx.wizard.WizardPage): firstPage = w break if not firstPage: wx.LogError('Wizard is empty') else: # Wizard should be modal self.SetItemBold(item) wiz.RunWizard(w) self.SetItemBold(item, False) wiz.Destroy() elif xxx.__class__ in [xxxWizardPage, xxxWizardPageSimple]: # Create new frame if not testWin: testWin = g.testWin = wx.Frame(g.frame, -1, 'Wizard page: ' + name, pos=pos, name=STD_NAME) testWin.panel = wx.PrePanel() res.LoadOnObject(testWin.panel, testWin, STD_NAME, 'wxPanel') testWin.SetClientSize(testWin.GetBestSize()) testWin.Show(True) elif xxx.__class__ == xxxMenuBar: testWin = g.testWin = wx.Frame(g.frame, -1, 'MenuBar: ' + name, pos=pos, name=STD_NAME) testWin.panel = None # Set status bar to display help testWin.CreateStatusBar() testWin.menuBar = res.LoadMenuBar(STD_NAME) testWin.SetMenuBar(testWin.menuBar) testWin.Show(True) elif xxx.__class__ == xxxToolBar: testWin = g.testWin = wx.Frame(g.frame, -1, 'ToolBar: ' + name, pos=pos, name=STD_NAME) testWin.panel = None # Set status bar to display help testWin.CreateStatusBar() testWin.toolBar = res.LoadToolBar(testWin, STD_NAME) testWin.SetToolBar(testWin.toolBar) testWin.Show(True) # Catch some events, set highlight if testWin: testWin.item = item wx.EVT_CLOSE(testWin, self.OnCloseTestWin) wx.EVT_SIZE(testWin, self.OnSizeTestWin) # Add drop target if testWin.panel: testWin.panel.SetDropTarget(DropTarget()) else: testWin.SetDropTarget(DropTarget()) # Reset highlights testWin.highLight = testWin.highLightDT = None if highLight and not self.pendingHighLight: self.HighLight(highLight) except: if g.testWin: self.SetItemBold(item, False) g.testWinPos = g.testWin.GetPosition() g.testWin.Destroy() g.testWin = None inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error loading resource') # Cleanup res.Unload('xxx.xrc') xrc.XmlResource.Set(None) wx.MemoryFSHandler.RemoveFile('xxx.xrc') def CloseTestWindow(self): if not g.testWin: return self.SetItemBold(g.testWin.item, False) g.frame.tb.ToggleTool(g.frame.ID_TOOL_LOCATE, False) g.testWinPos = g.testWin.GetPosition() g.testWin.Destroy() g.testWin = None def OnCloseTestWin(self, evt): self.CloseTestWindow() def OnSizeTestWin(self, evt): # Update highlight after size change hl = g.testWin.highLight if hl: hl.Replace(self.FindNodePos(hl.item), hl.obj.GetSize()) hl.Refresh() #self.HighLight(g.testWin.highLight.item) evt.Skip() # Return index in parent, for real window children def WindowIndex(self, item): n = 0 # index of sibling prev = self.GetPrevSibling(item) while prev.IsOk(): # MenuBar and sizers are not real children (who else?) if not isinstance(self.GetPyData(prev), xxxMenuBar) and not \ isinstance(self.GetPyData(prev), xxxSizer): n += 1 prev = self.GetPrevSibling(prev) return n # Return item index in parent def ItemIndex(self, item): n = 0 # index of sibling prev = self.GetPrevSibling(item) while prev.IsOk(): prev = self.GetPrevSibling(prev) n += 1 return n # Full tree index of an item - list of positions def ItemFullIndex(self, item): if not item.IsOk(): return None l = [] while item != self.root: l.insert(0, self.ItemIndex(item)) item = self.GetItemParent(item) return l # Get item position from full index def ItemAtFullIndex(self, index): if index is None: return wx.TreeItemId() item = self.root for i in index: item = self.GetFirstChild(item)[0] for k in range(i): item = self.GetNextSibling(item) return item # True if next item should be inserted after current (vs. appended to it) def NeedInsert(self, item): xxx = self.GetPyData(item) if item == self.root: return False # root item if xxx.hasChildren and not self.GetChildrenCount(item, False): return False return not (self.IsExpanded(item) and self.GetChildrenCount(item, False)) # Pull-down def OnRightDown(self, evt): pullDownMenu = g.pullDownMenu # select this item pt = evt.GetPosition(); item, flags = self.HitTest(pt) if item.Ok() and flags & wx.TREE_HITTEST_ONITEM: self.SelectItem(item) # Setup menu menu = wx.Menu() item = self.selection if not item: menu.Append(g.pullDownMenu.ID_EXPAND, 'Expand', 'Expand tree') menu.Append(g.pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse tree') else: # self.ctrl = evt.ControlDown() # save Ctrl state # self.shift = evt.ShiftDown() # and Shift too m = wx.Menu() # create menu if self.ctrl: needInsert = True else: needInsert = self.NeedInsert(item) if item == self.root or needInsert and self.GetItemParent(item) == self.root: SetMenu(m, pullDownMenu.topLevel) m.AppendSeparator() m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') else: xxx = self.GetPyData(item).treeObject() # Check parent for possible child nodes if inserting sibling if needInsert: xxx = xxx.parent if xxx.__class__ == xxxMenuBar: m.Append(ID_NEW.MENU, 'Menu', 'Create menu') elif xxx.__class__ in [xxxToolBar, xxxTool] or \ xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar: SetMenu(m, pullDownMenu.toolBarControls) elif xxx.__class__ in [xxxMenu, xxxMenuItem]: SetMenu(m, pullDownMenu.menuControls) elif xxx.__class__ == xxxStdDialogButtonSizer: SetMenu(m, pullDownMenu.stdButtons) else: SetMenu(m, pullDownMenu.controls) if xxx.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]: m.Enable(m.FindItem('sizer'), False) elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer): m.Enable(ID_NEW.SPACER, False) if xxx.__class__ is not xxxFrame: m.Enable(ID_NEW.MENU_BAR, False) # Add custom controls menu if len(pullDownMenu.custom) > 2: SetMenu(m, [pullDownMenu.custom]) m.AppendSeparator() m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') # Select correct label for create menu if not needInsert: if self.shift: menu.AppendMenu(wx.NewId(), 'Insert Child', m, 'Create child object as the first child') else: menu.AppendMenu(wx.NewId(), 'Append Child', m, 'Create child object as the last child') else: if self.shift: menu.AppendMenu(wx.NewId(), 'Create Sibling', m, 'Create sibling before selected object') else: menu.AppendMenu(wx.NewId(), 'Create Sibling', m, 'Create sibling after selected object') # Build replace menu if item != self.root: xxx = self.GetPyData(item).treeObject() m = wx.Menu() # create replace menu if xxx.__class__ == xxxMenuBar: m.Append(1000 + ID_NEW.MENU, 'Menu', 'Create menu') elif xxx.__class__ in [xxxMenu, xxxMenuItem]: SetMenu(m, pullDownMenu.menuControls, shift=True) elif xxx.__class__ == xxxToolBar and \ self.GetItemParent(item) == self.root: SetMenu(m, [], shift=True) elif xxx.__class__ in [xxxFrame, xxxDialog, xxxPanel]: SetMenu(m, [ (ID_NEW.PANEL, 'Panel', 'Create panel'), (ID_NEW.DIALOG, 'Dialog', 'Create dialog'), (ID_NEW.FRAME, 'Frame', 'Create frame')], shift=True) elif xxx.isSizer and self.ItemHasChildren(item): SetMenu(m, pullDownMenu.sizers, shift=True) else: SetMenu(m, pullDownMenu.controls, shift=True) if xxx.isElement: id = wx.NewId() menu.AppendMenu(id, 'Replace With', m) if not m.GetMenuItemCount(): menu.Enable(id, False) menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', 'Set "subclass" property') menu.AppendSeparator() # Not using standart IDs because we don't want to show shortcuts menu.Append(wx.ID_CUT, 'Cut', 'Cut to the clipboard') menu.Append(wx.ID_COPY, 'Copy', 'Copy to the clipboard') if self.ctrl and item != self.root: menu.Append(pullDownMenu.ID_PASTE_SIBLING, 'Paste Sibling', 'Paste from the clipboard as a sibling') else: menu.Append(wx.ID_PASTE, 'Paste', 'Paste from the clipboard') menu.Append(pullDownMenu.ID_DELETE, 'Delete', 'Delete object') if self.ItemHasChildren(item): menu.AppendSeparator() menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand subtree') menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse subtree') self.PopupMenu(menu, evt.GetPosition()) menu.Destroy() # Apply changes def Apply(self, xxx, item): g.panel.Apply() # Update tree view xxx = xxx.treeObject() if xxx.hasName and self.GetItemText(item) != xxx.name: self.SetItemText(item, xxx.treeName()) # Item width may have changed # !!! Tric to update tree width (wxGTK, ??) self.SetIndent(self.GetIndent()) elif xxx.className == 'comment': self.SetItemText(item, xxx.treeName()) # Change tree icon for sizers if isinstance(xxx, xxxBoxSizer): self.SetItemImage(item, xxx.treeImage()) # Set global modified state g.frame.SetModified() def OnBeginLabelEdit(self, evt): xxx = self.GetPyData(evt.GetItem()) if xxx.isElement: evt.Veto() else: evt.Skip() def OnEndLabelEdit(self, evt): xxx = self.GetPyData(evt.GetItem()) node = xxx.node if not xxx.isElement: node.data = evt.GetLabel() g.panel.SetData(xxx) evt.Skip() ################################################################################ # DragAndDrop class DropTarget(wx.PyDropTarget): def __init__(self): self.do = MyDataObject() wx.DropTarget.__init__(self, self.do) # Find best object for dropping def WhereToDrop(self, x, y, d): # Find object by position obj = wx.FindWindowAtPoint(g.testWin.ClientToScreen((x,y))) if not obj: return wx.DragNone, () item = g.frame.FindObject(g.testWin.item, obj) if not item: return wx.DragNone, () xxx = g.tree.GetPyData(item).treeObject() parentItem = None # Check if window has a XRC sizer, then use it as parent if obj.GetSizer(): sizer = obj.GetSizer() sizerItem = g.frame.FindObject(g.testWin.item, sizer) if sizerItem: parentItem = sizerItem obj = sizer item = wx.TreeItemId() # if not sizer but can have children, it is parent with free placement elif xxx.hasChildren: parentItem = item item = wx.TreeItemId() # Otherwise, try to add to item's parent if not parentItem: parentItem = g.tree.GetItemParent(item) obj = g.tree.FindNodeObject(parentItem) parent = g.tree.GetPyData(parentItem).treeObject() return d,(obj,parent,parentItem,item) # Drop def OnData(self, x, y, d): self.GetData() id = int(self.do.GetDataHere()) d,other = self.WhereToDrop(x, y, d) if d != wx.DragNone: obj,parent,parentItem,item = other g.tree.selection = parentItem xxx = g.frame.CreateXXX(parent, parentItem, item, id) # Set coordinates if parent is not sizer if not parent.isSizer: xxx.set('pos', '%d,%d' % (x, y)) g.panel.SetData(xxx) g.frame.SetStatusText('Object created') self.RemoveHL() return d def OnDragOver(self, x, y, d): d,other = self.WhereToDrop(x, y, d) if d != wx.DragNone: obj,parent,parentItem,item = other pos, size = g.tree.FindNodePos(parentItem, obj), obj.GetSize() hl = g.testWin.highLightDT # Set color of highlighted item back to normal if hl and hl.item: if hl.item != parentItem: g.tree.SetItemTextColour(hl.item, g.tree.itemColour) # Highlight future parent g.tree.itemColour = g.tree.GetItemTextColour(parentItem) # save current if not hl or hl.item != parentItem: g.testWin.highLightDT = updateHL(hl, HighLightDTBox, pos, size) g.testWin.highLightDT.item = parentItem g.tree.SetItemTextColour(parentItem, g.tree.COLOUR_DT) g.tree.EnsureVisible(parentItem) g.frame.SetStatusText('Drop target: %s' % parent.treeName()) else: g.frame.SetStatusText('Inappropriate drop target') self.RemoveHL() return d def OnLeave(self): self.RemoveHL() def RemoveHL(self): hl = g.testWin.highLightDT if hl: if hl.item: g.tree.SetItemTextColour(hl.item, g.tree.itemColour) hl.Remove() spe-0.8.4.h/_spe/plugins/XRCed/encode_bitmaps.py0000644000175000017500000000137010763311540020461 0ustar stanistani""" A simple script to encode all the images the XRCed needs into a Python module """ import sys, os, glob from wx.tools import img2py def main(): output = 'images.py' # get the list of PNG files files = glob.glob('src-images/*.png') files.sort() # Truncate the inages module open(output, 'w') # call img2py on each file for file in files: # extract the basename to be used as the image name name = os.path.splitext(os.path.basename(file))[0] # encode it if file == files[0]: cmd = "-u -i -n %s %s %s" % (name, file, output) else: cmd = "-a -u -i -n %s %s %s" % (name, file, output) img2py.main(cmd.split()) if __name__ == "__main__": main() spe-0.8.4.h/_spe/plugins/XRCed/xrced.sh0000644000175000017500000000005110763311540016567 0ustar stanistanipython2.2 YOUR_PATH_TO_XRCED/xrced.py $* spe-0.8.4.h/_spe/plugins/XRCed/__init__.py0000644000175000017500000000000510763311540017236 0ustar stanistani# spe-0.8.4.h/_spe/plugins/XRCed/TODO.txt0000644000175000017500000000114310763311540016437 0ustar stanistaniTODO for XRCed ============== - undo for Replace op - better help + undo/redo + tree icons + replace object with another, keeping children + write tmp file for current dialog/panel/etc. + XML indents + select same notebook pages after update - put some default values in tree ctrl etc. - special (fast) update for some values: pos/size, value/content, sizeritem stuff (?), well, as much as possible - highlighting with better method - import XRC/WXR files + disable some window creation when it's not valid + selecting object by clicking in test window + hidden items should not be highlighted spe-0.8.4.h/_spe/plugins/XRCed/tools.py0000644000175000017500000003556110763311540016656 0ustar stanistani# Name: tools.py # Purpose: XRC editor, toolbar # Author: Roman Rolinsky # Created: 19.03.2003 # RCS-ID: $Id: tools.py,v 1.19 2007/05/07 22:25:57 ROL Exp $ from xxx import * # xxx imports globals and params from tree import ID_NEW # Icons import images # Groups of controls GROUPNUM = 4 GROUP_WINDOWS, GROUP_MENUS, GROUP_SIZERS, GROUP_CONTROLS = range(GROUPNUM) # States depending on current selection and Control/Shift keys STATE_ROOT, STATE_MENUBAR, STATE_TOOLBAR, STATE_MENU, STATE_STDDLGBTN, STATE_ELSE = range(6) # Left toolbar for GUI elements class Tools(wx.Panel): TOOL_SIZE = (30, 30) def __init__(self, parent): if wx.Platform == '__WXGTK__': wx.Panel.__init__(self, parent, -1, style=wx.RAISED_BORDER|wx.WANTS_CHARS) else: wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) # Create sizer for groups self.sizer = wx.BoxSizer(wx.VERTICAL) # Data to create buttons pullDownMenu = g.pullDownMenu self.groups = [] self.ctrl = self.shift = False # Current state (what to enable/disable) self.state = None groups = [ ["Windows", (ID_NEW.FRAME, images.getToolFrameBitmap()), (ID_NEW.DIALOG, images.getToolDialogBitmap()), (ID_NEW.PANEL, images.getToolPanelBitmap())], ["Menus", (ID_NEW.TOOL_BAR, images.getToolToolBarBitmap()), (ID_NEW.MENU_BAR, images.getToolMenuBarBitmap()), (ID_NEW.MENU, images.getToolMenuBitmap()), (ID_NEW.TOOL, images.getToolToolBitmap()), (ID_NEW.MENU_ITEM, images.getToolMenuItemBitmap()), (ID_NEW.SEPARATOR, images.getToolSeparatorBitmap())], ["Sizers", (ID_NEW.BOX_SIZER, images.getToolBoxSizerBitmap()), (ID_NEW.STATIC_BOX_SIZER, images.getToolStaticBoxSizerBitmap()), (ID_NEW.GRID_SIZER, images.getToolGridSizerBitmap()), (ID_NEW.FLEX_GRID_SIZER, images.getToolFlexGridSizerBitmap()), (ID_NEW.GRID_BAG_SIZER, images.getToolGridBagSizerBitmap()), (ID_NEW.SPACER, images.getToolSpacerBitmap())], ["Controls", (ID_NEW.STATIC_TEXT, images.getToolStaticTextBitmap()), (ID_NEW.STATIC_BITMAP, images.getToolStaticBitmapBitmap()), (ID_NEW.STATIC_LINE, images.getToolStaticLineBitmap()), (ID_NEW.BUTTON, images.getToolButtonBitmap()), (ID_NEW.BITMAP_BUTTON, images.getToolBitmapButtonBitmap()), (ID_NEW.STATIC_BOX, images.getToolStaticBoxBitmap()), (ID_NEW.TEXT_CTRL, images.getToolTextCtrlBitmap()), (ID_NEW.COMBO_BOX, images.getToolComboBoxBitmap()), (ID_NEW.CHOICE, images.getToolChoiceBitmap()), (ID_NEW.RADIO_BUTTON, images.getToolRadioButtonBitmap()), (ID_NEW.CHECK_BOX, images.getToolCheckBoxBitmap()), (ID_NEW.RADIO_BOX, images.getToolRadioBoxBitmap()), (ID_NEW.SPIN_CTRL, images.getToolSpinCtrlBitmap()), (ID_NEW.SPIN_BUTTON, images.getToolSpinButtonBitmap()), (ID_NEW.SCROLL_BAR, images.getToolScrollBarBitmap()), (ID_NEW.SLIDER, images.getToolSliderBitmap()), (ID_NEW.GAUGE, images.getToolGaugeBitmap()), (ID_NEW.TREE_CTRL, images.getToolTreeCtrlBitmap()), (ID_NEW.LIST_BOX, images.getToolListBoxBitmap()), (ID_NEW.CHECK_LIST, images.getToolCheckListBitmap()), (ID_NEW.LIST_CTRL, images.getToolListCtrlBitmap()), (ID_NEW.NOTEBOOK, images.getToolNotebookBitmap()), (ID_NEW.SPLITTER_WINDOW, images.getToolSplitterWindowBitmap()), (ID_NEW.UNKNOWN, images.getToolUnknownBitmap())] ] self.boxes = {} for grp in groups: self.AddGroup(grp[0]) for b in grp[1:]: self.AddButton(b[0], b[1], g.pullDownMenu.createMap[b[0]]) self.SetSizerAndFit(self.sizer) # Allow to be resized in vertical direction only self.SetSizeHints(self.GetSize()[0], -1) # Events wx.EVT_COMMAND_RANGE(self, ID_NEW.PANEL, ID_NEW.LAST, wx.wxEVT_COMMAND_BUTTON_CLICKED, g.frame.OnCreate) wx.EVT_KEY_DOWN(self, self.OnKeyDown) wx.EVT_KEY_UP(self, self.OnKeyUp) # wxMSW does not generate click events for StaticBox if wx.Platform == '__WXMSW__': self.Bind(wx.EVT_LEFT_DOWN, self.OnClickBox) self.drag = None def AddButton(self, id, image, text): from wx.lib import buttons button = buttons.GenBitmapButton(self, id, image, size=self.TOOL_SIZE, style=wx.NO_BORDER|wx.WANTS_CHARS) button.SetBezelWidth(0) wx.EVT_KEY_DOWN(button, self.OnKeyDown) wx.EVT_KEY_UP(button, self.OnKeyUp) wx.EVT_LEFT_DOWN(button, self.OnLeftDownOnButton) wx.EVT_MOTION(button, self.OnMotionOnButton) button.SetToolTipString(text) self.curSizer.Add(button) self.groups[-1][1][id] = button def AddGroup(self, name): # Each group is inside box id = wx.NewId() box = wx.StaticBox(self, id, '[+] '+name, style=wx.WANTS_CHARS) box.SetForegroundColour(wx.Colour(64, 64, 64)) # box.SetFont(g.smallerFont()) box.show = True box.name = name box.gnum = len(self.groups) box.Bind(wx.EVT_LEFT_DOWN, self.OnClickBox) boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) boxSizer.Add((0, 0)) self.boxes[id] = box self.curSizer = wx.GridSizer(0, 3, 3, 3) boxSizer.Add(self.curSizer) self.sizer.Add(boxSizer, 0, wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, 4) self.groups.append((box,{})) # Enable/disable group def EnableGroup(self, gnum, enable = True): grp = self.groups[gnum] for b in grp[1].values(): b.Enable(enable) # Show/hide group def ShowGroup(self, gnum, show = True): grp = self.groups[gnum] grp[0].show = show for b in grp[1].values(): b.Show(show) # Enable/disable group item def EnableGroupItem(self, gnum, id, enable = True): grp = self.groups[gnum] grp[1][id].Enable(enable) # Enable/disable group items def EnableGroupItems(self, gnum, ids, enable = True): grp = self.groups[gnum] for id in ids: grp[1][id].Enable(enable) def OnClickBox(self, evt): if wx.Platform == '__WXMSW__': box = None for id,b in self.boxes.items(): # How to detect a click on a label? if b.GetRect().Inside(evt.GetPosition()): box = b break if not box: evt.Skip() return else: box = self.boxes[evt.GetId()] # Collapse/restore static box, change label self.ShowGroup(box.gnum, not box.show) if box.show: box.SetLabel('[+] ' + box.name) else: box.SetLabel('[-] ' + box.name) self.Layout() self.Refresh() #for b in self.boxes.items(): # DaD def OnLeftDownOnButton(self, evt): self.posDown = evt.GetPosition() self.idDown = evt.GetId() self.btnDown = evt.GetEventObject() evt.Skip() def OnMotionOnButton(self, evt): # Detect dragging if evt.Dragging() and evt.LeftIsDown(): d = evt.GetPosition() - self.posDown if max(abs(d[0]), abs(d[1])) >= 5: if self.btnDown.HasCapture(): # Generate up event to release mouse evt = wx.MouseEvent(wx.EVT_LEFT_UP.typeId) evt.SetId(self.idDown) # Set flag to prevent normal button operation this time self.drag = True self.btnDown.ProcessEvent(evt) self.StartDrag() evt.Skip() def StartDrag(self): do = MyDataObject() do.SetData(str(self.idDown)) bm = self.btnDown.GetBitmapLabel() # wxGTK requires wxIcon cursor, wxWIN and wxMAC require wxCursor if wx.Platform == '__WXGTK__': icon = wx.EmptyIcon() icon.CopyFromBitmap(bm) dragSource = wx.DropSource(self, icon) else: curs = wx.CursorFromImage(wx.ImageFromBitmap(bm)) dragSource = wx.DropSource(self, curs) dragSource.SetData(do) g.frame.SetStatusText('Release the mouse button over the test window') dragSource.DoDragDrop() # Process key events def OnKeyDown(self, evt): if evt.GetKeyCode() == wx.WXK_CONTROL: g.tree.ctrl = True elif evt.GetKeyCode() == wx.WXK_SHIFT: g.tree.shift = True self.UpdateIfNeeded() evt.Skip() def OnKeyUp(self, evt): if evt.GetKeyCode() == wx.WXK_CONTROL: g.tree.ctrl = False elif evt.GetKeyCode() == wx.WXK_SHIFT: g.tree.shift = False self.UpdateIfNeeded() evt.Skip() def OnMouse(self, evt): # Update control and shift states g.tree.ctrl = evt.ControlDown() g.tree.shift = evt.ShiftDown() self.UpdateIfNeeded() evt.Skip() # Update UI after key presses, if necessary def UpdateIfNeeded(self): tree = g.tree if self.ctrl != tree.ctrl or self.shift != tree.shift: # Enabling is needed only for ctrl if self.ctrl != tree.ctrl: self.UpdateUI() self.ctrl = tree.ctrl self.shift = tree.shift if tree.ctrl: status = 'SBL' elif tree.shift: status = 'INS' else: status = '' g.frame.SetStatusText(status, 1) # Update interface def UpdateUI(self): if not self.IsShown(): return # Update status bar pullDownMenu = g.pullDownMenu tree = g.tree item = tree.selection # If nothing selected, disable everything and return if not item: # Disable everything for grp in range(GROUPNUM): self.EnableGroup(grp, False) self.state = None return if tree.ctrl: needInsert = True else: needInsert = tree.NeedInsert(item) # Enable depending on selection if item == tree.root or needInsert and tree.GetItemParent(item) == tree.root: state = STATE_ROOT else: xxx = tree.GetPyData(item).treeObject() # Check parent for possible child nodes if inserting sibling if needInsert: xxx = xxx.parent if xxx.__class__ == xxxMenuBar: state = STATE_MENUBAR elif xxx.__class__ in [xxxToolBar, xxxTool] or \ xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar: state = STATE_TOOLBAR elif xxx.__class__ in [xxxMenu, xxxMenuItem]: state = STATE_MENU elif xxx.__class__ == xxxStdDialogButtonSizer: state = STATE_STDDLGBTN else: state = STATE_ELSE # Enable depending on selection if state != self.state: # Disable everything for grp in range(GROUPNUM): self.EnableGroup(grp, False) # Enable some if state == STATE_ROOT: self.EnableGroup(GROUP_WINDOWS, True) self.EnableGroup(GROUP_MENUS, True) # But disable items self.EnableGroupItems(GROUP_MENUS, [ ID_NEW.TOOL, ID_NEW.MENU_ITEM, ID_NEW.SEPARATOR ], False) elif state == STATE_STDDLGBTN: pass # nothing can be added from toolbar elif state == STATE_MENUBAR: self.EnableGroup(GROUP_MENUS) self.EnableGroupItems(GROUP_MENUS, [ ID_NEW.TOOL_BAR, ID_NEW.MENU_BAR, ID_NEW.TOOL ], False) elif state == STATE_TOOLBAR: self.EnableGroup(GROUP_MENUS) self.EnableGroupItems(GROUP_MENUS, [ ID_NEW.TOOL_BAR, ID_NEW.MENU, ID_NEW.MENU_BAR, ID_NEW.MENU_ITEM ], False) self.EnableGroup(GROUP_CONTROLS) self.EnableGroupItems(GROUP_CONTROLS, [ ID_NEW.TREE_CTRL, ID_NEW.NOTEBOOK, ID_NEW.SPLITTER_WINDOW ], False) elif state == STATE_MENU: self.EnableGroup(GROUP_MENUS) self.EnableGroupItems(GROUP_MENUS, [ ID_NEW.TOOL_BAR, ID_NEW.MENU_BAR, ID_NEW.TOOL ], False) else: self.EnableGroup(GROUP_WINDOWS) self.EnableGroupItems(GROUP_WINDOWS, [ ID_NEW.FRAME, ID_NEW.DIALOG ], False) self.EnableGroup(GROUP_MENUS) self.EnableGroupItems(GROUP_MENUS, [ ID_NEW.MENU_BAR, ID_NEW.MENU_BAR, ID_NEW.MENU, ID_NEW.MENU_ITEM, ID_NEW.TOOL, ID_NEW.SEPARATOR ], False) self.EnableGroup(GROUP_SIZERS) self.EnableGroup(GROUP_CONTROLS) # Special case for *book (always executed) if state == STATE_ELSE: if xxx.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]: self.EnableGroup(GROUP_SIZERS, False) else: self.EnableGroup(GROUP_SIZERS) if not (xxx.isSizer or xxx.parent and xxx.parent.isSizer): self.EnableGroupItem(GROUP_SIZERS, ID_NEW.SPACER, False) if xxx.__class__ == xxxFrame: self.EnableGroupItem(GROUP_MENUS, ID_NEW.MENU_BAR) # Save state self.state = state self.Refresh() spe-0.8.4.h/_spe/plugins/XRCed/xxx.py0000644000175000017500000014072710763311540016346 0ustar stanistani# Name: xxx.py ('xxx' is easy to distinguish from 'wx' :) ) # Purpose: XML interface classes # Author: Roman Rolinsky # Created: 22.08.2001 # RCS-ID: $Id: xxx.py,v 1.41 2007/06/23 20:49:37 RD Exp $ from xml.dom import minidom from globals import * from params import * import traceback, types # Base class for interface parameter classes class xxxNode: def __init__(self, node): self.node = node def remove(self): self.node.parentNode.removeChild(self.node) self.node.unlink() # Generic (text) parameter class class xxxParam(xxxNode): # Standard use: for text nodes def __init__(self, node): xxxNode.__init__(self, node) if not node.hasChildNodes(): # If does not have child nodes, create empty text node text = g.tree.dom.createTextNode('') node.appendChild(text) else: text = node.childNodes[0] # first child must be text node assert text.nodeType == minidom.Node.TEXT_NODE # Append other text nodes if present and delete them extraText = '' for n in node.childNodes[1:]: if n.nodeType == minidom.Node.TEXT_NODE: extraText += n.data node.removeChild(n) n.unlink() else: break if extraText: text.data = text.data + extraText # Use convertion from unicode to current encoding self.textNode = text # Value returns string if wx.USE_UNICODE: # no conversion is needed def value(self): return self.textNode.data def update(self, value): self.textNode.data = value else: def value(self): try: return self.textNode.data.encode(g.currentEncoding) except LookupError: return self.textNode.data.encode() def update(self, value): try: # handle exception if encoding is wrong self.textNode.data = unicode(value, g.currentEncoding) except UnicodeDecodeError: self.textNode.data = unicode(value) #wx.LogMessage("Unicode error: set encoding in file\nglobals.py to something appropriate") # Integer parameter class xxxParamInt(xxxParam): # Standard use: for text nodes def __init__(self, node): xxxParam.__init__(self, node) # Value returns string def value(self): try: return int(self.textNode.data) except ValueError: return -1 # invalid value def update(self, value): self.textNode.data = str(value) # Content parameter class xxxParamContent(xxxNode): def __init__(self, node): xxxNode.__init__(self, node) data, l = [], [] # data is needed to quicker value retrieval nodes = node.childNodes[:] # make a copy of the child list for n in nodes: if n.nodeType == minidom.Node.ELEMENT_NODE: assert n.tagName == 'item', 'bad content content' if not n.hasChildNodes(): # If does not have child nodes, create empty text node text = g.tree.dom.createTextNode('') node.appendChild(text) else: # !!! normalize? text = n.childNodes[0] # first child must be text node assert text.nodeType == minidom.Node.TEXT_NODE l.append(text) data.append(text.data) else: # remove other node.removeChild(n) n.unlink() self.l, self.data = l, data def value(self): return self.data def update(self, value): # If number if items is not the same, recreate children if len(value) != len(self.l): # remove first if number of items has changed childNodes = self.node.childNodes[:] for n in childNodes: self.node.removeChild(n) l = [] for str in value: itemElem = g.tree.dom.createElement('item') itemText = g.tree.dom.createTextNode(str) itemElem.appendChild(itemText) self.node.appendChild(itemElem) l.append(itemText) self.l = l else: for i in range(len(value)): self.l[i].data = value[i] self.data = value # Content parameter for checklist class xxxParamContentCheckList(xxxNode): def __init__(self, node): xxxNode.__init__(self, node) data, l = [], [] # data is needed to quicker value retrieval nodes = node.childNodes[:] # make a copy of the child list for n in nodes: if n.nodeType == minidom.Node.ELEMENT_NODE: assert n.tagName == 'item', 'bad content content' checked = n.getAttribute('checked') if not checked: checked = 0 if not n.hasChildNodes(): # If does not have child nodes, create empty text node text = g.tree.dom.createTextNode('') node.appendChild(text) else: # !!! normalize? text = n.childNodes[0] # first child must be text node assert text.nodeType == minidom.Node.TEXT_NODE l.append((text, n)) data.append((str(text.data), int(checked))) else: # remove other node.removeChild(n) n.unlink() self.l, self.data = l, data def value(self): return self.data def update(self, value): # If number if items is not the same, recreate children if len(value) != len(self.l): # remove first if number of items has changed childNodes = self.node.childNodes[:] for n in childNodes: self.node.removeChild(n) l = [] for s,ch in value: itemElem = g.tree.dom.createElement('item') # Add checked only if True if ch: itemElem.setAttribute('checked', '1') itemText = g.tree.dom.createTextNode(s) itemElem.appendChild(itemText) self.node.appendChild(itemElem) l.append((itemText, itemElem)) self.l = l else: for i in range(len(value)): self.l[i][0].data = value[i][0] self.l[i][1].setAttribute('checked', str(value[i][1])) self.data = value # Bitmap parameter class xxxParamBitmap(xxxParam): def __init__(self, node): xxxParam.__init__(self, node) self.stock_id = node.getAttribute('stock_id') def value(self): return [self.stock_id, xxxParam.value(self)] def update(self, value): self.stock_id = value[0] if self.stock_id: self.node.setAttribute('stock_id', self.stock_id) elif self.node.hasAttribute('stock_id'): self.node.removeAttribute('stock_id') xxxParam.update(self, value[1]) ################################################################################ # Classes to interface DOM objects class xxxObject: # Default behavior hasChildren = False # has children elements? hasStyle = True # almost everyone hasName = True # has name attribute? isSizer = hasChild = False isElement = True allParams = [] # Some nodes have no parameters # Style parameters (all optional) styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'tooltip'] # Special parameters specials = [] # Bitmap tags bitmapTags = ['bitmap', 'bitmap2', 'icon', 'selected', 'focus', 'disabled'] # Required paremeters: none by default required = [] # Default parameters with default values default = {} # Parameter types paramDict = {} # Window styles and extended styles winStyles = [] # Tree icon index #image = -1 # Construct a new xxx object from DOM element # parent is parent xxx object (or None if none), element is DOM element object def __init__(self, parent, element, refElem=None): self.parent = parent self.node = element self.refElem = refElem self.undo = None # Reference are dereferenced if element.tagName == 'object_ref': # Find original object self.ref = element.getAttribute('ref') if refElem: self.className = self.refElem.getAttribute('class') else: self.className = 'xxxUnknown' self.required = [] else: # Get attributes self.ref = None self.className = element.getAttribute('class') self.subclass = element.getAttribute('subclass') if self.hasName: self.name = element.getAttribute('name') # Set parameters (text element children) self.params = {} for n in element.childNodes[:]: if n.nodeType == minidom.Node.ELEMENT_NODE: tag = n.tagName if tag in ['object', 'object_ref']: continue # do nothing for object children here elif tag not in self.allParams and tag not in self.styles: print 'WARNING: unknown parameter for %s: %s' % \ (self.className, tag) elif tag in self.specials: self.special(tag, n) elif tag == 'content': if self.className == 'wxCheckListBox': self.params[tag] = xxxParamContentCheckList(n) else: self.params[tag] = xxxParamContent(n) elif tag == 'font': # has children self.params[tag] = xxxParamFont(element, n) elif tag in self.bitmapTags: # Can have attributes self.params[tag] = xxxParamBitmap(n) else: # simple parameter self.params[tag] = xxxParam(n) elif n.nodeType == minidom.Node.TEXT_NODE and n.data.isspace(): # Remove empty text nodes element.removeChild(n) n.unlink() # Check that all required params are set for param in self.required: if not self.params.has_key(param): # If default is specified, set it if self.default.has_key(param): elem = g.tree.dom.createElement(param) if param == 'content': if self.className == 'wxCheckListBox': self.params[param] = xxxParamContentCheckList(elem) else: self.params[param] = xxxParamContent(elem) else: self.params[param] = xxxParam(elem) # Find place to put new element: first present element after param found = False paramStyles = self.allParams + self.styles for p in paramStyles[paramStyles.index(param) + 1:]: # Content params don't have same type if self.params.has_key(p) and p != 'content': found = True break if found: nextTextElem = self.params[p].node self.node.insertBefore(elem, nextTextElem) else: self.node.appendChild(elem) else: wx.LogWarning('Required parameter %s of %s missing' % (param, self.className)) # Returns real tree object def treeObject(self): if self.hasChild: return self.child return self # Returns tree image index def treeImage(self): if self.hasChild: return self.child.treeImage() return self.image # Class name plus wx name def treeName(self): if self.hasChild: return self.child.treeName() if self.subclass: className = self.subclass else: className = self.className if self.hasName and self.name: return className + ' "' + self.name + '"' return className # Class name or subclass def panelName(self): if self.subclass: name = self.subclass + '(' + self.className + ')' name = self.className if self.ref: name = 'ref: ' + self.ref + ', ' + name return name # Sets name of tree object def setTreeName(self, name): if self.hasChild: obj = self.child else: obj = self obj.name = name obj.node.setAttribute('name', name) # Set normal (text) params def set(self, param, value): try: self.params[param].update(value) except KeyError: elem = g.tree.dom.createElement(param) p = xxxParam(elem) p.update(value) self.params[param] = p self.node.appendChild(elem) # Special processing for growablecols-like parameters # represented by several nodes def special(self, tag, node): if not self.params.has_key(tag): # Create new multi-group self.params[tag] = xxxParamMulti(node) self.params[tag].append(xxxParamInt(node)) def setSpecial(self, param, value): # Straightforward implementation: remove, add again self.params[param].remove() del self.params[param] for i in value: node = g.tree.dom.createElement(param) text = g.tree.dom.createTextNode(str(i)) node.appendChild(text) self.node.appendChild(node) self.special(param, node) # Imitation of FindResource/DoFindResource from xmlres.cpp def DoFindResource(parent, name, classname, recursive): for n in parent.childNodes: if n.nodeType == minidom.Node.ELEMENT_NODE and \ n.tagName in ['object', 'object_ref'] and \ n.getAttribute('name') == name: cls = n.getAttribute('class') if not classname or cls == classname: return n if not cls or n.tagName == 'object_ref': refName = n.getAttribute('ref') if not refName: continue refNode = FindResource(refName) if refName and refNode.getAttribute('class') == classname: return n if recursive: for n in parent.childNodes: if n.nodeType == minidom.Node.ELEMENT_NODE and \ n.tagName in ['object', 'object_ref']: found = DoFindResource(n, name, classname, True) if found: return found def FindResource(name, classname='', recursive=True): found = DoFindResource(g.tree.mainNode, name, classname, recursive) if found: return found wx.LogError('XRC resource "%s" not found!' % name) ################################################################################ # This is a little special: it is both xxxObject and xxxNode class xxxParamFont(xxxObject, xxxNode): allParams = ['size', 'family', 'style', 'weight', 'underlined', 'face', 'encoding'] def __init__(self, parent, element): xxxObject.__init__(self, parent, element) xxxNode.__init__(self, element) self.parentNode = parent # required to behave similar to DOM node v = [] for p in self.allParams: try: v.append(str(self.params[p].value())) except KeyError: v.append('') self.data = v def update(self, value): # `value' is a list of strings corresponding to all parameters elem = self.node # Remove old elements first childNodes = elem.childNodes[:] for node in childNodes: elem.removeChild(node) i = 0 self.params.clear() v = [] for param in self.allParams: if value[i]: fontElem = g.tree.dom.createElement(param) textNode = g.tree.dom.createTextNode(value[i]) self.params[param] = textNode fontElem.appendChild(textNode) elem.appendChild(fontElem) v.append(value[i]) i += 1 self.data = v def value(self): return self.data ################################################################################ class xxxContainer(xxxObject): hasChildren = True exStyles = [] # Simulate normal parameter for encoding class xxxEncoding: def value(self): return g.currentEncoding def update(self, val): g.currentEncoding = val # Special class for root node class xxxMainNode(xxxContainer): allParams = ['encoding'] hasStyle = hasName = False def __init__(self, dom): xxxContainer.__init__(self, None, dom.documentElement) self.className = 'XML tree' # Reset required parameters after processing XML, because encoding is # a little special self.required = ['encoding'] self.params['encoding'] = xxxEncoding() ################################################################################ # Top-level windwows class xxxPanel(xxxContainer): allParams = ['pos', 'size', 'style'] winStyles = ['wxNO_3D', 'wxTAB_TRAVERSAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] class xxxDialog(xxxContainer): allParams = ['title', 'centered', 'pos', 'size', 'style'] paramDict = {'centered': ParamBool} required = ['title'] default = {'title': ''} winStyles = ['wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX', 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX', 'wxDIALOG_MODAL', 'wxDIALOG_MODELESS', 'wxDIALOG_NO_PARENT' 'wxNO_3D', 'wxTAB_TRAVERSAL'] exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxDIALOG_EX_METAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] class xxxFrame(xxxContainer): allParams = ['title', 'centered', 'pos', 'size', 'style'] paramDict = {'centered': ParamBool} required = ['title'] default = {'title': ''} winStyles = ['wxDEFAULT_FRAME_STYLE', 'wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME', 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX', 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX', 'wxFRAME_NO_TASKBAR', 'wxFRAME_SHAPED', 'wxFRAME_TOOL_WINDOW', 'wxFRAME_FLOAT_ON_PARENT', 'wxNO_3D', 'wxTAB_TRAVERSAL'] exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxFRAME_EX_METAL'] styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle', 'tooltip'] class xxxTool(xxxObject): allParams = ['bitmap', 'bitmap2', 'radio', 'toggle', 'tooltip', 'longhelp', 'label'] required = ['bitmap'] paramDict = {'bitmap2': ParamBitmap, 'radio': ParamBool, 'toggle': ParamBool} hasStyle = False class xxxToolBar(xxxContainer): allParams = ['bitmapsize', 'margins', 'packing', 'separation', 'dontattachtoframe', 'pos', 'size', 'style'] hasStyle = False paramDict = {'bitmapsize': ParamPosSize, 'margins': ParamPosSize, 'packing': ParamUnit, 'separation': ParamUnit, 'dontattachtoframe': ParamBool, 'style': ParamNonGenericStyle} winStyles = ['wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_VERTICAL', 'wxTB_HORIZONTAL', 'wxTB_3DBUTTONS','wxTB_TEXT', 'wxTB_NOICONS', 'wxTB_NODIVIDER', 'wxTB_NOALIGN', 'wxTB_HORZ_LAYOUT', 'wxTB_HORZ_TEXT'] class xxxStatusBar(xxxObject): hasStyle = False allParams = ['fields', 'widths', 'styles', 'style'] paramDict = {'fields': ParamIntNN, 'widths': ParamText, 'styles': ParamText, 'style': ParamNonGenericStyle} winStyles = ['wxST_SIZEGRIP'] class xxxWizard(xxxContainer): allParams = ['title', 'bitmap', 'pos'] required = ['title'] default = {'title': ''} winStyles = [] exStyles = ['wxWIZARD_EX_HELPBUTTON'] styles = ['fg', 'bg', 'font', 'exstyle'] class xxxWizardPage(xxxContainer): allParams = ['bitmap'] winStyles = [] exStyles = [] class xxxWizardPageSimple(xxxContainer): allParams = ['bitmap'] winStyles = [] exStyles = [] ################################################################################ # Bitmap, Icon class xxxBitmap(xxxObject): allParams = ['bitmap'] required = ['bitmap'] # Just like bitmap class xxxIcon(xxxObject): allParams = [] ################################################################################ # Controls class xxxStaticText(xxxObject): allParams = ['label', 'pos', 'size', 'style'] required = ['label'] default = {'label': ''} winStyles = ['wxALIGN_LEFT', 'wxALIGN_RIGHT', 'wxALIGN_CENTRE', 'wxST_NO_AUTORESIZE'] class xxxStaticLine(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxLI_HORIZONTAL', 'wxLI_VERTICAL'] class xxxStaticBitmap(xxxObject): allParams = ['bitmap', 'pos', 'size', 'style'] required = ['bitmap'] class xxxTextCtrl(xxxObject): allParams = ['value', 'pos', 'size', 'style'] winStyles = ['wxTE_NO_VSCROLL', 'wxTE_AUTO_SCROLL', 'wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE', 'wxTE_PASSWORD', 'wxTE_READONLY', 'wxHSCROLL', 'wxTE_RICH', 'wxTE_RICH2', 'wxTE_AUTO_URL', 'wxTE_NOHIDESEL', 'wxTE_LEFT', 'wxTE_CENTRE', 'wxTE_RIGHT', 'wxTE_DONTWRAP', 'wxTE_LINEWRAP', 'wxTE_WORDWRAP'] paramDict = {'value': ParamMultilineText} class xxxChoice(xxxObject): allParams = ['content', 'selection', 'pos', 'size', 'style'] required = ['content'] default = {'content': '[]'} winStyles = ['wxCB_SORT'] class xxxSlider(xxxObject): allParams = ['value', 'min', 'max', 'pos', 'size', 'style', 'tickfreq', 'pagesize', 'linesize', 'thumb', 'tick', 'selmin', 'selmax'] paramDict = {'value': ParamInt, 'tickfreq': ParamIntNN, 'pagesize': ParamIntNN, 'linesize': ParamIntNN, 'thumb': ParamUnit, 'tick': ParamInt, 'selmin': ParamInt, 'selmax': ParamInt} required = ['value', 'min', 'max'] winStyles = ['wxSL_HORIZONTAL', 'wxSL_VERTICAL', 'wxSL_AUTOTICKS', 'wxSL_LABELS', 'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP', 'wxSL_BOTTOM', 'wxSL_BOTH', 'wxSL_SELRANGE', 'wxSL_INVERSE'] class xxxGauge(xxxObject): allParams = ['range', 'pos', 'size', 'style', 'value', 'shadow', 'bezel'] paramDict = {'range': ParamIntNN, 'value': ParamIntNN, 'shadow': ParamIntNN, 'bezel': ParamIntNN} winStyles = ['wxGA_HORIZONTAL', 'wxGA_VERTICAL', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH'] class xxxScrollBar(xxxObject): allParams = ['pos', 'size', 'style', 'value', 'thumbsize', 'range', 'pagesize'] paramDict = {'value': ParamIntNN, 'range': ParamIntNN, 'thumbsize': ParamIntNN, 'pagesize': ParamIntNN} winStyles = ['wxSB_HORIZONTAL', 'wxSB_VERTICAL'] class xxxListCtrl(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON', 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE', 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER', 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING', 'wxLC_VIRTUAL', 'wxLC_HRULES', 'wxLC_VRULES', 'wxLC_NO_SORT_HEADER'] class xxxTreeCtrl(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxTR_EDIT_LABELS', 'wxTR_NO_BUTTONS', 'wxTR_HAS_BUTTONS', 'wxTR_TWIST_BUTTONS', 'wxTR_NO_LINES', 'wxTR_FULL_ROW_HIGHLIGHT', 'wxTR_LINES_AT_ROOT', 'wxTR_HIDE_ROOT', 'wxTR_ROW_LINES', 'wxTR_HAS_VARIABLE_ROW_HEIGHT', 'wxTR_SINGLE', 'wxTR_MULTIPLE', 'wxTR_EXTENDED', 'wxTR_DEFAULT_STYLE'] class xxxHtmlWindow(xxxObject): allParams = ['pos', 'size', 'style', 'borders', 'url', 'htmlcode'] paramDict = {'htmlcode':ParamMultilineText} winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO', 'wxHW_NO_SELECTION'] class xxxCalendarCtrl(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxCAL_SUNDAY_FIRST', 'wxCAL_MONDAY_FIRST', 'wxCAL_SHOW_HOLIDAYS', 'wxCAL_NO_YEAR_CHANGE', 'wxCAL_NO_MONTH_CHANGE', 'wxCAL_SEQUENTIAL_MONTH_SELECTION', 'wxCAL_SHOW_SURROUNDING_WEEKS'] class xxxNotebook(xxxContainer): allParams = ['pos', 'size', 'style'] winStyles = ['wxNB_TOP', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM', 'wxNB_FIXEDWIDTH', 'wxNB_MULTILINE', 'wxNB_NOPAGETHEME', 'wxNB_FLAT'] class xxxChoicebook(xxxContainer): allParams = ['pos', 'size', 'style'] winStyles = ['wxCHB_DEFAULT', 'wxCHB_LEFT', 'wxCHB_RIGHT', 'wxCHB_TOP', 'wxCHB_BOTTOM'] class xxxListbook(xxxContainer): allParams = ['pos', 'size', 'style'] winStyles = ['wxLB_DEFAULT', 'wxLB_LEFT', 'wxLB_RIGHT', 'wxLB_TOP', 'wxLB_BOTTOM'] class xxxSplitterWindow(xxxContainer): allParams = ['orientation', 'sashpos', 'minsize', 'pos', 'size', 'style'] paramDict = {'orientation': ParamOrientation, 'sashpos': ParamUnit, 'minsize': ParamUnit } winStyles = ['wxSP_3D', 'wxSP_3DSASH', 'wxSP_3DBORDER', 'wxSP_FULLSASH', 'wxSP_NOBORDER', 'wxSP_PERMIT_UNSPLIT', 'wxSP_LIVE_UPDATE', 'wxSP_NO_XP_THEME' ] class xxxGenericDirCtrl(xxxObject): allParams = ['defaultfolder', 'filter', 'defaultfilter', 'pos', 'size', 'style'] paramDict = {'defaultfilter': ParamIntNN} winStyles = ['wxDIRCTRL_DIR_ONLY', 'wxDIRCTRL_3D_INTERNAL', 'wxDIRCTRL_SELECT_FIRST', 'wxDIRCTRL_SHOW_FILTERS'] class xxxScrolledWindow(xxxContainer): allParams = ['pos', 'size', 'style'] winStyles = ['wxHSCROLL', 'wxVSCROLL', 'wxNO_3D', 'wxTAB_TRAVERSAL'] class xxxDateCtrl(xxxObject): allParams = ['pos', 'size', 'style', 'borders'] winStyles = ['wxDP_DEFAULT', 'wxDP_SPIN', 'wxDP_DROPDOWN', 'wxDP_ALLOWNONE', 'wxDP_SHOWCENTURY'] class xxxGrid(xxxObject): allParams = ['pos', 'size', 'style'] class xxxFilePickerCtrl(xxxObject): allParams = ['value', 'message', 'wildcard', 'pos', 'size', 'style'] winStyles = ['wxFLP_OPEN', 'wxFLP_SAVE', 'wxFLP_OVERWRITE_PROMPT', 'wxFLP_FILE_MUST_EXIST', 'wxFLP_CHANGE_DIR', 'wxFLP_DEFAULT_STYLE'] ################################################################################ # Buttons class xxxButton(xxxObject): allParams = ['label', 'default', 'pos', 'size', 'style'] paramDict = {'default': ParamBool} required = ['label'] winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM', 'wxBU_EXACTFIT', 'wxNO_BORDER'] class xxxBitmapButton(xxxObject): allParams = ['bitmap', 'selected', 'focus', 'disabled', 'default', 'pos', 'size', 'style'] paramDict = {'selected': ParamBitmap, 'focus': ParamBitmap, 'disabled': ParamBitmap, 'default': ParamBool} required = ['bitmap'] winStyles = ['wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_RIGHT', 'wxBU_TOP', 'wxBU_BOTTOM'] class xxxRadioButton(xxxObject): allParams = ['label', 'value', 'pos', 'size', 'style'] paramDict = {'value': ParamBool} required = ['label'] winStyles = ['wxRB_GROUP', 'wxRB_SINGLE'] class xxxSpinButton(xxxObject): allParams = ['value', 'min', 'max', 'pos', 'size', 'style'] paramDict = {'value': ParamInt} winStyles = ['wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP'] class xxxSpinCtrl(xxxObject): allParams = ['value', 'min', 'max', 'pos', 'size', 'style'] paramDict = {'value': ParamInt} winStyles = ['wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP'] class xxxToggleButton(xxxObject): allParams = ['label', 'checked', 'pos', 'size', 'style'] paramDict = {'checked': ParamBool} required = ['label'] ################################################################################ # Boxes class xxxStaticBox(xxxObject): allParams = ['label', 'pos', 'size', 'style'] required = ['label'] class xxxRadioBox(xxxObject): allParams = ['label', 'content', 'selection', 'dimension', 'pos', 'size', 'style'] paramDict = {'dimension': ParamIntNN} required = ['label', 'content'] default = {'content': '[]'} winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS', 'wxRA_HORIZONTAL', 'wxRA_VERTICAL'] class xxxCheckBox(xxxObject): allParams = ['label', 'checked', 'pos', 'size', 'style'] paramDict = {'checked': ParamBool} winStyles = ['wxCHK_2STATE', 'wxCHK_3STATE', 'wxCHK_ALLOW_3RD_STATE_FOR_USER', 'wxALIGN_RIGHT'] required = ['label'] class xxxComboBox(xxxObject): allParams = ['content', 'selection', 'value', 'pos', 'size', 'style'] required = ['content'] default = {'content': '[]'} winStyles = ['wxCB_SIMPLE', 'wxCB_SORT', 'wxCB_READONLY', 'wxCB_DROPDOWN'] class xxxListBox(xxxObject): allParams = ['content', 'selection', 'pos', 'size', 'style'] required = ['content'] default = {'content': '[]'} winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL', 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT'] class xxxCheckList(xxxObject): allParams = ['content', 'pos', 'size', 'style'] required = ['content'] default = {'content': '[]'} winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL', 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT'] paramDict = {'content': ParamContentCheckList} ################################################################################ # Sizers class xxxSizer(xxxContainer): hasName = hasStyle = False paramDict = {'orient': ParamOrient} isSizer = True itemTag = 'sizeritem' # different for some sizers class xxxBoxSizer(xxxSizer): allParams = ['orient'] required = ['orient'] default = {'orient': 'wxVERTICAL'} # Tree icon depends on orientation def treeImage(self): if self.params['orient'].value() == 'wxHORIZONTAL': return self.imageH else: return self.imageV class xxxStaticBoxSizer(xxxBoxSizer): allParams = ['label', 'orient'] required = ['label', 'orient'] class xxxGridSizer(xxxSizer): allParams = ['cols', 'rows', 'vgap', 'hgap'] required = ['cols'] default = {'cols': '2', 'rows': '2'} class xxxStdDialogButtonSizer(xxxSizer): allParams = [] itemTag = 'button' # For repeated parameters class xxxParamMulti: def __init__(self, node): self.node = node self.l, self.data = [], [] def append(self, param): self.l.append(param) self.data.append(param.value()) def value(self): return self.data def remove(self): for param in self.l: param.remove() self.l, self.data = [], [] class xxxFlexGridSizer(xxxGridSizer): specials = ['growablecols', 'growablerows'] allParams = ['cols', 'rows', 'vgap', 'hgap'] + specials paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList} class xxxGridBagSizer(xxxSizer): specials = ['growablecols', 'growablerows'] allParams = ['vgap', 'hgap'] + specials paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList} # Container with only one child. # Not shown in tree. class xxxChildContainer(xxxObject): hasName = hasStyle = False hasChild = True def __init__(self, parent, element, refElem=None): xxxObject.__init__(self, parent, element, refElem) # Must have one child with 'object' tag, but we don't check it nodes = element.childNodes[:] # create copy for node in nodes: if node.nodeType == minidom.Node.ELEMENT_NODE: if node.tagName in ['object', 'object_ref']: # Create new xxx object for child node self.child = MakeXXXFromDOM(self, node) self.child.parent = parent # Copy hasChildren and isSizer attributes self.hasChildren = self.child.hasChildren self.isSizer = self.child.isSizer return # success else: element.removeChild(node) node.unlink() assert 0, 'no child found' def resetChild(self, xxx): '''Reset child info (for replacing with another class).''' self.child = xxx self.hasChildren = xxx.hasChildren self.isSizer = xxx.isSizer class xxxSizerItem(xxxChildContainer): allParams = ['option', 'flag', 'border', 'minsize', 'ratio'] paramDict = {'option': ParamInt, 'minsize': ParamPosSize, 'ratio': ParamPosSize} defaults_panel = {} defaults_control = {} def __init__(self, parent, element, refElem=None): # For GridBag sizer items, extra parameters added if isinstance(parent, xxxGridBagSizer): self.allParams = self.allParams + ['cellpos', 'cellspan'] xxxChildContainer.__init__(self, parent, element, refElem) # Remove pos parameter - not needed for sizeritems if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('pos') def resetChild(self, xxx): xxxChildContainer.resetChild(self, xxx) # Remove pos parameter - not needed for sizeritems if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('pos') class xxxSizerItemButton(xxxSizerItem): allParams = [] paramDict = {} def __init__(self, parent, element, refElem=None): xxxChildContainer.__init__(self, parent, element, refElem=None) # Remove pos parameter - not needed for sizeritems if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('pos') class xxxPage(xxxChildContainer): allParams = ['label', 'selected'] paramDict = {'selected': ParamBool} required = ['label'] def __init__(self, parent, element, refElem=None): xxxChildContainer.__init__(self, parent, element, refElem) # pos and size dont matter for notebookpages if 'pos' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('pos') if 'size' in self.child.allParams: self.child.allParams = self.child.allParams[:] self.child.allParams.remove('size') class xxxSpacer(xxxObject): hasName = hasStyle = False allParams = ['size', 'option', 'flag', 'border'] paramDict = {'option': ParamInt} default = {'size': '0,0'} def __init__(self, parent, element, refElem=None): # For GridBag sizer items, extra parameters added if isinstance(parent, xxxGridBagSizer): self.allParams = self.allParams + ['cellpos', 'cellspan'] xxxObject.__init__(self, parent, element, refElem) class xxxMenuBar(xxxContainer): allParams = ['style'] paramDict = {'style': ParamNonGenericStyle} # no generic styles winStyles = ['wxMB_DOCKABLE'] class xxxMenu(xxxContainer): allParams = ['label', 'help', 'style'] default = {'label': ''} paramDict = {'style': ParamNonGenericStyle} # no generic styles winStyles = ['wxMENU_TEAROFF'] class xxxMenuItem(xxxObject): allParams = ['label', 'bitmap', 'accel', 'help', 'checkable', 'radio', 'enabled', 'checked'] default = {'label': ''} hasStyle = False class xxxSeparator(xxxObject): hasName = hasStyle = False ################################################################################ # Unknown control class xxxUnknown(xxxObject): allParams = ['pos', 'size', 'style'] winStyles = ['wxNO_FULL_REPAINT_ON_RESIZE'] ################################################################################ # Comment _handlers = [] # custom handler classes/funcs def getHandlers(): return _handlers def setHandlers(handlers): global _handlers _handlers = handlers _CFuncPtr = None # ctypes function type def register(hndlr): """Register hndlr function or XmlResourceHandler class.""" if _CFuncPtr and isinstance(hndlr, _CFuncPtr): _handlers.append(hndlr) return if not isinstance(hndlr, type): wx.LogError('handler is not a type: %s' % hndlr) elif not issubclass(hndlr, wx.xrc.XmlResourceHandler): wx.LogError('handler is not a XmlResourceHandler: %s' % hndlr) else: _handlers.append(hndlr) def load_dl(path, localname=''): """Load shared/dynamic library into xxx namespace. If path is not absolute or relative, try to find in the module's directory. """ if not localname: localname = os.path.basename(os.path.splitext(path)[0]) try: import ctypes global _CFuncPtr _CFuncPtr = ctypes._CFuncPtr # use as a flag of loaded ctypes #if not os.path.dirname(path) and os.path.isfile(path): except ImportError: wx.LogError('ctypes module not found') globals()[localname] = None return try: dl = ctypes.CDLL(path) globals()[localname] = dl # Register AddXmlHandlers() if exists try: register(dl.AddXmlHandlers) except: pass except: wx.LogError('error loading dynamic library: %s' % path) print traceback.print_exc() # Called when creating test window def addHandlers(): for h in _handlers: if _CFuncPtr and isinstance(h, _CFuncPtr): try: apply(h, ()) except: wx.LogError('error calling DL func: "%s"' % h) print traceback.print_exc() else: try: xrc.XmlResource.Get().AddHandler(apply(h, ())) except: wx.LogError('error adding XmlHandler: "%s"' % h) print traceback.print_exc() def custom(klassName, klass='unknown'): """Define custom control based on xrcClass. klass: new object name xrcClass: name of an existing XRC object class or a class object defining class parameters. """ if type(klass) is str: # Copy correct xxx class under new name kl = xxxDict[klass] xxxClass = types.ClassType('xxx' + klassName, kl.__bases__, kl.__dict__) else: xxxClass = klass # Register param IDs for param in klass.allParams + klass.paramDict.keys(): if not paramIDs.has_key(param): paramIDs[param] = wx.NewId() # Insert in dictionaty xxxDict[klassName] = xxxClass # Add to menu g.pullDownMenu.addCustom(klassName) class xxxParamComment(xxxParam): locals = {} # namespace for comment directives allow = None # undefined initial state for current file def __init__(self, node): xxxNode.__init__(self, node) self.textNode = node # Parse "pragma" comments if enabled if node.data and node.data[0] == '%' and g.conf.allowExec != 'no' and \ xxxParamComment.allow is not False: # Show warning if g.conf.allowExec == 'ask' and xxxParamComment.allow is None: flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CENTRE dlg = wx.MessageDialog(g.frame, ''' This file contains executable %comment directives. Allow to execute?''', 'Warning', flags) say = dlg.ShowModal() dlg.Destroy() if say == wx.ID_YES: xxxParamComment.allow = True else: xxxParamComment.allow = False try: code = node.data[1:] exec code in globals(), self.locals except: wx.LogError('exec error: "%s"' % code) print traceback.print_exc() class xxxComment(xxxObject): hasStyle = hasName = False allParams = required = ['comment'] def __init__(self, parent, node): self.parent = parent self.node = node self.isElement = False self.undo = None self.className = 'comment' self.ref = self.subclass = None self.params = {'comment': xxxParamComment(node)} def treeName(self): # Replace newlines by \n to avoid tree item resizing return self.params['comment'].value().replace('\n', r'\n') ################################################################################ # Mapping of XRC names to xxx classes xxxDict = { 'wxPanel': xxxPanel, 'wxDialog': xxxDialog, 'wxFrame': xxxFrame, 'tool': xxxTool, 'wxToolBar': xxxToolBar, 'wxStatusBar': xxxStatusBar, 'wxWizard': xxxWizard, 'wxWizardPage': xxxWizardPage, 'wxWizardPageSimple': xxxWizardPageSimple, 'wxBitmap': xxxBitmap, 'wxIcon': xxxIcon, 'wxButton': xxxButton, 'wxBitmapButton': xxxBitmapButton, 'wxRadioButton': xxxRadioButton, 'wxSpinButton': xxxSpinButton, 'wxToggleButton' : xxxToggleButton, 'wxStaticBox': xxxStaticBox, 'wxStaticBitmap': xxxStaticBitmap, 'wxRadioBox': xxxRadioBox, 'wxComboBox': xxxComboBox, 'wxCheckBox': xxxCheckBox, 'wxListBox': xxxListBox, 'wxStaticText': xxxStaticText, 'wxStaticLine': xxxStaticLine, 'wxTextCtrl': xxxTextCtrl, 'wxChoice': xxxChoice, 'wxSlider': xxxSlider, 'wxGauge': xxxGauge, 'wxScrollBar': xxxScrollBar, 'wxTreeCtrl': xxxTreeCtrl, 'wxListCtrl': xxxListCtrl, 'wxCheckListBox': xxxCheckList, 'notebookpage': xxxPage, 'choicebookpage': xxxPage, 'listbookpage': xxxPage, 'wxNotebook': xxxNotebook, 'wxChoicebook': xxxChoicebook, 'wxListbook': xxxListbook, 'wxSplitterWindow': xxxSplitterWindow, 'wxHtmlWindow': xxxHtmlWindow, 'wxCalendarCtrl': xxxCalendarCtrl, 'wxGenericDirCtrl': xxxGenericDirCtrl, 'wxSpinCtrl': xxxSpinCtrl, 'wxScrolledWindow': xxxScrolledWindow, 'wxGrid': xxxGrid, 'wxFilePickerCtrl': xxxFilePickerCtrl, 'wxDatePickerCtrl': xxxDateCtrl, 'wxBoxSizer': xxxBoxSizer, 'wxStaticBoxSizer': xxxStaticBoxSizer, 'wxGridSizer': xxxGridSizer, 'wxFlexGridSizer': xxxFlexGridSizer, 'wxGridBagSizer': xxxGridBagSizer, 'wxStdDialogButtonSizer': xxxStdDialogButtonSizer, 'sizeritem': xxxSizerItem, 'button': xxxSizerItemButton, 'spacer': xxxSpacer, 'wxMenuBar': xxxMenuBar, 'wxMenu': xxxMenu, 'wxMenuItem': xxxMenuItem, 'separator': xxxSeparator, 'unknown': xxxUnknown, 'comment': xxxComment, } # Create IDs for all parameters of all classes paramIDs = {'fg': wx.NewId(), 'bg': wx.NewId(), 'exstyle': wx.NewId(), 'font': wx.NewId(), 'enabled': wx.NewId(), 'focused': wx.NewId(), 'hidden': wx.NewId(), 'tooltip': wx.NewId(), 'encoding': wx.NewId(), 'cellpos': wx.NewId(), 'cellspan': wx.NewId(), 'text': wx.NewId() } for cl in xxxDict.values(): if cl.allParams: for param in cl.allParams + cl.paramDict.keys(): if not paramIDs.has_key(param): paramIDs[param] = wx.NewId() ################################################################################ # Helper functions # Test for object elements def IsObject(node): return node.nodeType == minidom.Node.ELEMENT_NODE and \ node.tagName in ['object', 'object_ref'] or \ node.nodeType == minidom.Node.COMMENT_NODE # Make XXX object from some DOM object, selecting correct class def MakeXXXFromDOM(parent, node): if node.nodeType == minidom.Node.COMMENT_NODE: return xxxComment(parent, node) if node.tagName == 'object_ref': ref = node.getAttribute('ref') refElem = FindResource(ref) if refElem: cls = refElem.getAttribute('class') else: return xxxUnknown(parent, node) else: refElem = None cls = node.getAttribute('class') try: klass = xxxDict[cls] except KeyError: # If we encounter a weird class, use unknown template print 'WARNING: unsupported class:', node.getAttribute('class') klass = xxxUnknown return klass(parent, node, refElem) # Make empty DOM element def MakeEmptyDOM(className): elem = g.tree.dom.createElement('object') elem.setAttribute('class', className) # Set required and default parameters xxxClass = xxxDict[className] defaultNotRequired = filter(lambda x, l=xxxClass.required: x not in l, xxxClass.default.keys()) for param in xxxClass.required + defaultNotRequired: textElem = g.tree.dom.createElement(param) try: textNode = g.tree.dom.createTextNode(xxxClass.default[param]) except KeyError: textNode = g.tree.dom.createTextNode('') textElem.appendChild(textNode) elem.appendChild(textElem) return elem # Make empty XXX object def MakeEmptyXXX(parent, className): # Make corresponding DOM object first elem = MakeEmptyDOM(className) # Special handling, e.g. if parent is a sizer, we should create # sizeritem object, except for spacers, etc. if parent: if parent.isSizer and className != 'spacer': sizerItemElem = MakeEmptyDOM(parent.itemTag) sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook): pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxChoicebook): pageElem = MakeEmptyDOM('choicebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxListbook): pageElem = MakeEmptyDOM('listbookpage') pageElem.appendChild(elem) elem = pageElem # Now just make object xxx = MakeXXXFromDOM(parent, elem) # Special defaults for new panels and controls if isinstance(xxx, xxxSizerItem): if isinstance(xxx.child, xxxContainer) and not xxx.child.isSizer: for param,v in xxxSizerItem.defaults_panel.items(): xxx.set(param, v) elif isinstance(xxx.child, xxxObject): for param,v in xxxSizerItem.defaults_control.items(): xxx.set(param, v) return xxx # Make empty DOM element for reference def MakeEmptyRefDOM(ref): elem = g.tree.dom.createElement('object_ref') elem.setAttribute('ref', ref) return elem # Make empty XXX object def MakeEmptyRefXXX(parent, ref): # Make corresponding DOM object first elem = MakeEmptyRefDOM(ref) # If parent is a sizer, we should create sizeritem object, except for spacers if parent: if parent.isSizer: sizerItemElem = MakeEmptyDOM(parent.itemTag) sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook): pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxChoicebook): pageElem = MakeEmptyDOM('choicebookpage') pageElem.appendChild(elem) elem = pageElem elif isinstance(parent, xxxListbook): pageElem = MakeEmptyDOM('listbookpage') pageElem.appendChild(elem) elem = pageElem # Now just make object xxx = MakeXXXFromDOM(parent, elem) # Label is not used for references xxx.allParams = xxx.allParams[:] #xxx.allParams.remove('label') return xxx # Make empty comment node def MakeEmptyCommentDOM(): node = g.tree.dom.createComment('') return node # Make empty xxxComment def MakeEmptyCommentXXX(parent): node = MakeEmptyCommentDOM() # Now just make object xxx = MakeXXXFromDOM(parent, node) return xxx spe-0.8.4.h/_spe/plugins/XRCed/README.txt0000644000175000017500000000714510763311540016637 0ustar stanistani******************************************************************************** XRCed README ******************************************************************************** System requirements ------------------- wxPython version must be recent enough to support all features (a warning message is shown if not). User requirements ----------------- To use XRCed it is really important to be familiar with wxWindows class names and at least partially with XRC resource format (read wxWindows/doc/tech/tn0014.txt for reference). Short manual ------------ XRCed's idea is very straightforward: it is a visual tool for editing an XML file conforming to XRC format. Every operation performed in XRCed has direct correspondence to XML structure. So it is not really a usual point-and-click GUI builder, but don't let that scare you. To start xrced, change to the directory where you installed it and run "python2.2 xrced.py". On UNIX you can edit wrapper script "xrced.sh" to point to your installation directory. To create an object, first you should select some object in the tree (or the root item if it's empty) then press the right mouse button and select an appropriate command. The pulldown menu is context-dependent on the selected object. XRCed tries to guess if new object should be added as a next sibling or a child of current object, depending on the possibility of the object to have child objects and expanded state (if tree item is collapsed, new object will be sibling). You can change this behavior to create siblings by pressing and holding the Shift and Control keys before clicking the mouse. Pressed Control key while pressing right button makes next item a sibling of selected item regardless of its expanded state. Pressed Shift key changes the place for inserting new child to be before selected child, not after as by default. Panel on the right contains object properties. Properties which are optional should be "checked" first. This panel can be made separate by unchecking "Embed Panel" in View menu. All properties can be edited as text, and some are supplied with special editing controls. When no 'Edit' button is provided for editing a property's value, it is supposed to be copied verbatim to XRC file. The names of the properties are exactly as in XRC file, and it's usually not hard to guess what they do. "XML ID" is the name of the window, and must be present for top-level windows (though this is not enforced by XRCed). To display the preview window double-click a top-level object (you should assign an XMLID to it first), press "Test" toolbar button or select command from View menu, or press F5. After that, if you select a child object, it becomes highlighted, and if you change it, preview is updated when you select another item or press Ctrl-R (refresh). To turn off automatic update, toggle "View->Auto-refresh" or toolbar auto-refresh button (to the right of the refresh button). If you double-click a non-window object (a button for example), then test view is created for a closest ancestor which is a window. Bugs ---- - Some combinations of parent/child windows are not valid but possible to put into XML tree by using XRCed. Usually this produces a meaningful error message from XRC library when test view is opened. - Be careful when replacing a non-empty container control with another class, and check parameters which can be copied from the previous object but not valid for the new one. Is it not possible to undo replacement yet. -------------------------------------------------------------------------------- Copyright 2001-2005 Roman Rolinsky spe-0.8.4.h/_spe/plugins/XRCed/undo.py0000644000175000017500000002670310763311540016461 0ustar stanistani# Name: undo.py # Purpose: XRC editor, undo/redo module # Author: Roman Rolinsky # Created: 01.12.2002 # RCS-ID: $Id: undo.py,v 1.13 2007/05/14 12:24:44 ROL Exp $ from globals import * from xxx import MakeXXXFromDOM from tree import * #from panel import * # Undo/redo classes class UndoManager: # Undo/redo stacks undo = [] redo = [] def RegisterUndo(self, undoObj): self.undo.append(undoObj) for i in self.redo: i.destroy() self.redo = [] def Undo(self): undoObj = self.undo.pop() undoObj.undo() self.redo.append(undoObj) g.frame.SetModified() g.frame.SetStatusText('Undone') def Redo(self): undoObj = self.redo.pop() undoObj.redo() self.undo.append(undoObj) g.frame.SetModified() g.frame.SetStatusText('Redone') def Clear(self): for i in self.undo: i.destroy() self.undo = [] for i in self.redo: i.destroy() self.redo = [] def CanUndo(self): return not not self.undo def CanRedo(self): return not not self.redo class UndoCutDelete: def __init__(self, itemIndex, parent, elem): self.itemIndex = itemIndex self.parent = parent self.elem = elem def destroy(self): if self.elem: self.elem.unlink() def undo(self): item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemIndex[:-1]), self.parent, self.elem, g.tree.ItemAtFullIndex(self.itemIndex)) # Scroll to show new item (!!! redundant?) g.tree.EnsureVisible(item) g.tree.SelectItem(item) self.elem = None # Update testWin if needed if g.testWin and g.tree.IsHighlatable(item): if g.conf.autoRefresh: g.tree.needUpdate = True g.tree.pendingHighLight = item else: g.tree.pendingHighLight = None def redo(self): item = g.tree.ItemAtFullIndex(self.itemIndex) # Delete testWin? if g.testWin: # If deleting top-level item, delete testWin if item == g.testWin.item: g.testWin.Destroy() g.testWin = None else: # Remove highlight, update testWin if g.testWin.highLight: g.testWin.highLight.Remove() g.tree.needUpdate = True self.elem = g.tree.RemoveLeaf(item) g.tree.UnselectAll() g.panel.Clear() class UndoPasteCreate: def __init__(self, itemParent, parent, item, selected): self.itemParentIndex = g.tree.ItemFullIndex(itemParent) self.parent = parent self.itemIndex = g.tree.ItemFullIndex(item) # pasted item self.selectedIndex = g.tree.ItemFullIndex(selected) # maybe different from item self.elem = None def destroy(self): if self.elem: self.elem.unlink() def undo(self): self.elem = g.tree.RemoveLeaf(g.tree.ItemAtFullIndex(self.itemIndex)) # Restore old selection selected = g.tree.ItemAtFullIndex(self.selectedIndex) g.tree.EnsureVisible(selected) g.tree.SelectItem(selected) # Delete testWin? if g.testWin: # If deleting top-level item, delete testWin if selected == g.testWin.item: g.testWin.Destroy() g.testWin = None else: # Remove highlight, update testWin if g.testWin.highLight: g.testWin.highLight.Remove() g.tree.needUpdate = True def redo(self): item = g.tree.InsertNode(g.tree.ItemAtFullIndex(self.itemParentIndex), self.parent, self.elem, g.tree.ItemAtFullIndex(self.itemIndex)) # Scroll to show new item g.tree.EnsureVisible(item) g.tree.SelectItem(item) self.elem = None # Update testWin if needed if g.testWin and g.tree.IsHighlatable(item): if g.conf.autoRefresh: g.tree.needUpdate = True g.tree.pendingHighLight = item else: g.tree.pendingHighLight = None class UndoReplace: def __init__(self, item): self.itemIndex = g.tree.ItemFullIndex(item) #self.xxx = g.tree.GetPyData(item) self.elem = None def destroy(self): if self.elem: self.elem.unlink() def undo(self): print 'Sorry, UndoReplace is not yet implemented.' return item = g.tree.ItemAtFullIndex(self.itemIndex) xxx = g.tree.GetPyData(item) # Replace with old element parent = xxx.parent.node if xxx is self.xxx: # sizeritem or notebookpage - replace child parent.replaceChild(self.xxx.child.node, xxx.child.node) else: parent.replaceChild(self.xxx.node, xxx.node) self.xxx.parent = xxx.parent xxx = self.xxx g.tree.SetPyData(item, xxx) g.tree.SetItemText(item, xxx.treeName()) g.tree.SetItemImage(item, xxx.treeImage()) # Update panel g.panel.SetData(xxx) # Update tools g.tools.UpdateUI() g.tree.EnsureVisible(item) g.tree.SelectItem(item) # Delete testWin? if g.testWin: # If deleting top-level item, delete testWin if selected == g.testWin.item: g.testWin.Destroy() g.testWin = None else: # Remove highlight, update testWin if g.testWin.highLight: g.testWin.highLight.Remove() g.tree.needUpdate = True def redo(self): return class UndoMove: def __init__(self, oldParent, oldIndex, newParent, newIndex): # Store indexes because items can be invalid already self.oldParentIndex = g.tree.ItemFullIndex(oldParent) self.oldIndex = oldIndex self.newParentIndex = g.tree.ItemFullIndex(newParent) self.newIndex = newIndex def destroy(self): pass def undo(self): oldParent = g.tree.ItemAtFullIndex(self.oldParentIndex) newParent = g.tree.ItemAtFullIndex(self.newParentIndex) item = g.tree.GetFirstChild(newParent)[0] for i in range(self.newIndex): item = g.tree.GetNextSibling(item) elem = g.tree.RemoveLeaf(item) nextItem = g.tree.GetFirstChild(oldParent)[0] for i in range(self.oldIndex): nextItem = g.tree.GetNextSibling(nextItem) parent = g.tree.GetPyData(oldParent).treeObject() # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. xxx = MakeXXXFromDOM(parent, elem) isChildContainer = isinstance(xxx, xxxChildContainer) if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False # Parent is sizer or notebook, child is not child container if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): # Create sizer item element sizerItemElem = MakeEmptyDOM('sizeritem') sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook) and not isChildContainer: pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem selected = g.tree.InsertNode(oldParent, parent, elem, nextItem) g.tree.EnsureVisible(selected) # Highlight is outdated if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() g.tree.needUpdate = True g.tree.SelectItem(selected) def redo(self): oldParent = g.tree.ItemAtFullIndex(self.oldParentIndex) newParent = g.tree.ItemAtFullIndex(self.newParentIndex) item = g.tree.GetFirstChild(oldParent)[0] for i in range(self.oldIndex): item = g.tree.GetNextSibling(item) elem = g.tree.RemoveLeaf(item) parent = g.tree.GetPyData(newParent).treeObject() # Check parent and child relationships. # If parent is sizer or notebook, child is of wrong class or # parent is normal window, child is child container then detach child. xxx = MakeXXXFromDOM(parent, elem) isChildContainer = isinstance(xxx, xxxChildContainer) if isChildContainer and \ ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False # Parent is sizer or notebook, child is not child container if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer): # Create sizer item element sizerItemElem = MakeEmptyDOM('sizeritem') sizerItemElem.appendChild(elem) elem = sizerItemElem elif isinstance(parent, xxxNotebook) and not isChildContainer: pageElem = MakeEmptyDOM('notebookpage') pageElem.appendChild(elem) elem = pageElem nextItem = g.tree.GetFirstChild(newParent)[0] for i in range(self.newIndex): nextItem = g.tree.GetNextSibling(nextItem) selected = g.tree.InsertNode(newParent, parent, elem, nextItem) g.tree.EnsureVisible(selected) # Highlight is outdated if g.testWin and g.testWin.highLight: g.testWin.highLight.Remove() g.tree.needUpdate = True g.tree.SelectItem(selected) class UndoEdit: def __init__(self): self.pages = map(ParamPage.GetState, g.panel.pages) self.selectedIndex = g.tree.ItemFullIndex(g.tree.GetSelection()) def destroy(self): pass # Update test view def update(self, selected): g.tree.Apply(g.tree.GetPyData(selected), selected) # Update view if g.testWin: if g.testWin.highLight: g.testWin.highLight.Remove() g.tree.pendingHighLight = selected if g.testWin: g.tree.needUpdate = True def undo(self): # Restore selection selected = g.tree.ItemAtFullIndex(self.selectedIndex) if selected != g.tree.GetSelection(): g.tree.SelectItem(selected) # Save current state for redo map(ParamPage.SaveState, g.panel.pages) pages = map(ParamPage.GetState, g.panel.pages) if self.pages: map(ParamPage.SetState, g.panel.pages, self.pages) self.pages = pages self.update(selected) def redo(self): self.undo() self.update(g.tree.GetSelection()) spe-0.8.4.h/_spe/plugins/XRCed/sawfishrc0000644000175000017500000000143310763311540017047 0ustar stanistani(require 'sawmill-defaults) ;;; Define two hooks to reset focus behavior while mapping test window (define (xrced-match-window-before w) (setq prop (aref (get-x-text-property w 'WM_CLASS) 0)) (cond ((equal prop "_XRCED_T_W") (setq transients-get-focus-b transients-get-focus) (setq transients-get-focus nil) (setq focus-windows-when-mapped-b focus-windows-when-mapped) (setq focus-windows-when-mapped nil) ) ) ) (define (xrced-match-window-after w) (setq prop (aref (get-x-text-property w 'WM_CLASS) 0)) (cond ((equal prop "_XRCED_T_W") (setq transients-get-focus-b transients-get-focus-b) (setq focus-windows-when-mapped focus-windows-when-mapped-b) ) ) ) (add-hook 'map-notify-hook xrced-match-window-before) (add-hook 'map-notify-hook xrced-match-window-after 't) spe-0.8.4.h/_spe/plugins/XRCed/XRCed_32.png0000644000175000017500000000124510763311540017113 0ustar stanistaniPNG  IHDR szzsBIT|d\IDATxV10 G8ppp>Pp>g(`@0`*_3{uErBm%fq:  B ǟɂ0 0l(6m RڷM λyȻ<+ntsB]V0F )xc6n0sYk7@x1 YrW5$f 4n M4 @D=3g:7;@k!OH¦BDU=?˵DD`f0sYuH'!8R5u}׸31`XmY|kƘxyjmv7JlDTegIj^v13]:R;)v'a?' T@7'0M%8\/K:<+ Mi5ޜKHW R` :݄iꈖзB.X50T$8pv/چPB$0njYR3&x?<〵9^Ȝ].Wڜp)= # Created: 02.12.2002 # RCS-ID: $Id: panel.py,v 1.30 2007/05/07 22:25:57 ROL Exp $ from xxx import * # xxx imports globals and params from undo import * from wx.html import HtmlWindow # Properties panel containing notebook class Panel(wx.Notebook): def __init__(self, parent, id = -1): if wx.Platform != '__WXMAC__': # some problems with this style on macs wx.Notebook.__init__(self, parent, id, style=wx.NB_BOTTOM) else: wx.Notebook.__init__(self, parent, id) global panel g.panel = panel = self self.modified = False # Set common sizes import params cTmp = wx.Button(self, -1, '') params.buttonSize = (self.DLG_SZE(buttonSizeD)[0], cTmp.GetSize()[1]) cTmp.Destroy() cTmp = wx.TextCtrl(self, -1, '') params.textSize = cTmp.GetSize() cTmp.Destroy() cTmp = wx.CheckBox(self, -1, 'growablerows ') # this is the longest ParamPage.labelSize = cTmp.GetSize() cTmp.Destroy() del cTmp # List of child windows self.pages = [] # Create scrolled windows for pages self.page1 = wx.ScrolledWindow(self, -1) sizer = wx.BoxSizer() sizer.Add(wx.BoxSizer()) # dummy sizer self.page1.SetAutoLayout(True) self.page1.SetSizer(sizer) self.AddPage(self.page1, 'Properties') # Second page self.page2 = wx.ScrolledWindow(self, -1) self.page2.Hide() sizer = wx.BoxSizer() sizer.Add(wx.BoxSizer()) # dummy sizer self.page2.SetAutoLayout(True) self.page2.SetSizer(sizer) # Cache for already used panels self.pageCache = {} # cached property panels self.stylePageCache = {} # cached style panels # Delete child windows and recreate page sizer def ResetPage(self, page): topSizer = page.GetSizer() sizer = topSizer.GetChildren()[0].GetSizer() for w in page.GetChildren(): sizer.Detach(w) if isinstance(w, ParamPage): if w.IsShown(): w.Hide() else: w.Destroy() topSizer.Remove(sizer) # Create new windows sizer = wx.BoxSizer(wx.VERTICAL) # Special case - resize html window if g.conf.panic: topSizer.Add(sizer, 1, wx.EXPAND) else: topSizer.Add(sizer, 1, wx.ALL, 5) return sizer def SetData(self, xxx): self.pages = [] # First page # Remove current objects and sizer sizer = self.ResetPage(self.page1) if not xxx or (not xxx.allParams and not xxx.hasName and not xxx.hasChild): if g.tree.selection: sizer.Add(wx.StaticText(self.page1, -1, 'This item has no properties.')) else: # nothing selected # If first time, show some help if g.conf.panic: html = HtmlWindow(self.page1, -1, wx.DefaultPosition, wx.DefaultSize, wx.SUNKEN_BORDER) html.SetPage(g.helpText) sizer.Add(html, 1, wx.EXPAND) g.conf.panic = False else: sizer.Add(wx.StaticText(self.page1, -1, 'Select a tree item.')) else: g.currentXXX = xxx.treeObject() # Normal or SizerItem page isGBSizerItem = isinstance(xxx.parent, xxxGridBagSizer) cacheID = (xxx.panelName(), isGBSizerItem) try: page = self.pageCache[cacheID] page.box.SetLabel(xxx.panelName()) page.Show() except KeyError: page = PropPage(self.page1, xxx.panelName(), xxx) self.pageCache[cacheID] = page page.SetValues(xxx) self.pages.append(page) sizer.Add(page, 1, wx.EXPAND) if xxx.hasChild: # Special label for child objects - they may have different GUI cacheID = (xxx.child.panelName(), xxx.__class__) try: page = self.pageCache[cacheID] page.box.SetLabel(xxx.child.panelName()) page.Show() except KeyError: page = PropPage(self.page1, xxx.child.panelName(), xxx.child) self.pageCache[cacheID] = page page.SetValues(xxx.child) self.pages.append(page) sizer.Add(page, 0, wx.EXPAND | wx.TOP, 5) self.page1.Layout() size = self.page1.GetSizer().GetMinSize() self.page1.SetScrollbars(1, 1, size.width, size.height, 0, 0, True) # Second page # Create if does not exist if xxx and xxx.treeObject().hasStyle: xxx = xxx.treeObject() # Simplest case: set data if class is the same sizer = self.ResetPage(self.page2) try: page = self.stylePageCache[xxx.__class__] page.Show() except KeyError: page = StylePage(self.page2, xxx.className + ' style', xxx) self.stylePageCache[xxx.__class__] = page page.SetValues(xxx) self.pages.append(page) sizer.Add(page, 0, wx.EXPAND) # Add page if not exists if not self.GetPageCount() == 2: self.AddPage(self.page2, 'Style') self.page2.Layout() if 'wxGTK' in wx.PlatformInfo: self.page2.Show(True) size = self.page2.GetSizer().GetMinSize() self.page2.SetScrollbars(1, 1, size.width, size.height, 0, 0, True) else: # Remove page if exists if self.GetPageCount() == 2: self.SetSelection(0) self.page1.Refresh() self.RemovePage(1) self.modified = False def Clear(self): self.SetData(None) self.modified = False # If some parameter has changed def IsModified(self): return self.modified def SetModified(self, value): # Register undo object when modifying first time if not self.modified and value: g.undoMan.RegisterUndo(UndoEdit()) g.frame.SetModified() self.modified = value def Apply(self): for p in self.pages: p.Apply() ################################################################################ # General class for notebook pages class ParamPage(wx.Panel): labelSize = None def __init__(self, parent, xxx): wx.Panel.__init__(self, parent, -1) self.xxx = xxx # Register event handlers for id in paramIDs.values(): wx.EVT_CHECKBOX(self, id, self.OnCheckParams) self.checks = {} self.controls = {} # save python objects self.controlName = None def OnCheckParams(self, evt): xxx = self.xxx param = evt.GetEventObject().GetName() w = self.controls[param] w.Enable(True) objElem = xxx.node if evt.IsChecked(): # Ad new text node in order of allParams w.SetValue('') # set empty (default) value w.SetModified() # mark as changed elem = g.tree.dom.createElement(param) # Some classes are special if param == 'font': xxx.params[param] = xxxParamFont(xxx.node, elem) elif param in xxxObject.bitmapTags: xxx.params[param] = xxxParamBitmap(elem) else: xxx.params[param] = xxxParam(elem) # Find place to put new element: first present element after param found = False if xxx.hasStyle: paramStyles = xxx.allParams + xxx.styles else: paramStyles = xxx.allParams for p in paramStyles[paramStyles.index(param) + 1:]: # Content params don't have same type if xxx.params.has_key(p) and p != 'content': found = True break if found: nextTextElem = xxx.params[p].node objElem.insertBefore(elem, nextTextElem) else: objElem.appendChild(elem) else: # Remove parameter xxx.params[param].remove() del xxx.params[param] w.SetValue('') w.SetModified(False) # mark as not changed w.Enable(False) # Set modified flag (provokes undo storing is necessary) panel.SetModified(True) def Apply(self): xxx = self.xxx if self.controlName: name = self.controlName.GetValue() if xxx.name != name: xxx.name = name xxx.node.setAttribute('name', name) for param, w in self.controls.items(): if w.modified: paramObj = xxx.params[param] value = w.GetValue() if param in xxx.specials: xxx.setSpecial(param, value) else: paramObj.update(value) # Save current state def SaveState(self): self.origChecks = map(lambda i: (i[0], i[1].GetValue()), self.checks.items()) self.origControls = map(lambda i: (i[0], i[1].GetValue(), i[1].enabled), self.controls.items()) if self.controlName: self.origName = self.controlName.GetValue() # Return original values def GetState(self): if self.controlName: return (self.origChecks, self.origControls, self.origName) else: return (self.origChecks, self.origControls) # Set values from undo data def SetState(self, state): for k,v in state[0]: self.checks[k].SetValue(v) for k,v,e in state[1]: self.controls[k].SetValue(v) self.controls[k].Enable(e) # Set all states to modified if e and k in self.xxx.params: self.controls[k].modified = True if self.controlName: self.controlName.SetValue(state[2]) ################################################################################ # Panel for displaying properties class PropPage(ParamPage): renameDict = {'orient':'orientation', 'option':'proportion', 'usenotebooksizer':'usesizer', 'dontattachtoframe':'dontattach', } def __init__(self, parent, label, xxx): ParamPage.__init__(self, parent, xxx) self.box = wx.StaticBox(self, -1, label) #self.box.SetFont(g.labelFont()) topSizer = wx.StaticBoxSizer(self.box, wx.VERTICAL) sizer = wx.FlexGridSizer(len(xxx.allParams), 2, 1, 5) sizer.AddGrowableCol(1) if xxx.hasName: label = wx.StaticText(self, -1, 'XML ID:', size=self.labelSize) control = ParamText(self, 'XML_name', 200) sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL), (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.GROW, 10) ]) self.controlName = control for param in xxx.allParams: present = xxx.params.has_key(param) sParam = self.renameDict.get(param, param) if param in xxx.required: if isinstance(xxx, xxxComment): label = None else: label = wx.StaticText(self, paramIDs[param], sParam, size = self.labelSize, name = param) else: label = wx.CheckBox(self, paramIDs[param], sParam, size = self.labelSize, name = param) self.checks[param] = label try: typeClass = xxx.paramDict[param] except KeyError: try: # Standart type typeClass = paramDict[param] except KeyError: # Default typeClass = ParamText control = typeClass(self, param) control.Enable(present) # Comment has only one parameter if isinstance(xxx, xxxComment): # Bind char event to check Enter key control.text.Bind(wx.EVT_CHAR, self.OnEnter) sizer.Add(control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) else: sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL), (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ]) self.controls[param] = control topSizer.Add(sizer, 1, wx.ALL | wx.EXPAND, 3) self.SetSizer(topSizer) topSizer.Fit(self) def SetValues(self, xxx): self.xxx = xxx self.origChecks = [] self.origControls = [] # Set values, checkboxes to False, disable defaults if xxx.hasName: self.controlName.SetValue(xxx.name) self.origName = xxx.name for param in xxx.allParams: w = self.controls[param] w.modified = False try: value = xxx.params[param].value() w.Enable(True) w.SetValue(value) if not param in xxx.required: self.checks[param].SetValue(True) self.origChecks.append((param, True)) self.origControls.append((param, value, True)) except KeyError: # Optional param not present in xxx - set empty value self.checks[param].SetValue(False) w.SetValue('') w.Enable(False) self.origChecks.append((param, False)) self.origControls.append((param, '', False)) # This is called only for comment now def OnEnter(self, evt): if evt.GetKeyCode() == 13: g.tree.Apply(self.xxx, g.tree.selection) else: evt.Skip() ################################################################################ # Style notebook page class StylePage(ParamPage): renameDict = {'fg':'foreground', 'bg':'background'} def __init__(self, parent, label, xxx): ParamPage.__init__(self, parent, xxx) box = wx.StaticBox(self, -1, label) #box.SetFont(g.labelFont()) topSizer = wx.StaticBoxSizer(box, wx.VERTICAL) sizer = wx.FlexGridSizer(len(xxx.styles), 2, 1, 5) sizer.AddGrowableCol(1) for param in xxx.styles: present = xxx.params.has_key(param) sParam = self.renameDict.get(param, param) check = wx.CheckBox(self, paramIDs[param], sParam, size = self.labelSize, name = param) check.SetValue(present) control = paramDict[param](self, name = param) control.Enable(present) sizer.AddMany([ (check, 0, wx.ALIGN_CENTER_VERTICAL), (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ]) self.checks[param] = check self.controls[param] = control topSizer.Add(sizer, 1, wx.ALL | wx.EXPAND, 3) self.SetAutoLayout(True) self.SetSizer(topSizer) topSizer.Fit(self) # Set data for a cahced page def SetValues(self, xxx): self.xxx = xxx self.origChecks = [] self.origControls = [] for param in xxx.styles: present = xxx.params.has_key(param) check = self.checks[param] check.SetValue(present) w = self.controls[param] w.modified = False if present: value = xxx.params[param].value() else: value = '' w.SetValue(value) w.Enable(present) self.origChecks.append((param, present)) self.origControls.append((param, value, present)) spe-0.8.4.h/_spe/plugins/XRCed/xrced.xrc0000644000175000017500000006021010763311540016754 0ustar stanistani Text Dialog 1 wxVERTICAL wxHORIZONTAL 250,100 wxALL|wxEXPAND 5 wxEXPAND wxALL|wxALIGN_CENTRE_HORIZONTAL 10 Content 1 250,300 wxVERTICAL wxHORIZONTAL wxTOP|wxBOTTOM|wxLEFT|wxEXPAND 5 wxVERTICAL wxBOTTOM|wxEXPAND 5 wxEXPAND 10,20 wxBOTTOM|wxEXPAND 5 wxEXPAND wxALL|wxEXPAND 5 wxEXPAND wxEXPAND wxHORIZONTAL 1 wxRIGHT 10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 Content 1 250,300 wxVERTICAL wxHORIZONTAL wxTOP|wxBOTTOM|wxLEFT|wxEXPAND 5 wxVERTICAL wxBOTTOM|wxEXPAND 5 wxEXPAND 10,20 wxBOTTOM|wxEXPAND 5 wxEXPAND wxALL|wxEXPAND 5 wxEXPAND 0,10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 Choices 1 wxVERTICAL 250,250 wxALL|wxEXPAND 5 0,10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 Window Styles 1 wxVERTICAL wxTOP|wxLEFT 5 250,150 wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND 5 wxLEFT 5 250,150 wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND 5 0,10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 Numbers 1 100,300 wxVERTICAL wxHORIZONTAL 80,150 wxALL|wxALIGN_CENTRE_HORIZONTAL 5 wxVERTICAL 60,-1 wxBOTTOM 5 wxBOTTOM 5 wxTOP 5 wxALL|wxALIGN_CENTRE_HORIZONTAL 5 wxEXPAND 0 0,10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 wxVERTICAL 2 2 wxALIGN_CENTRE_VERTICAL wxART_ADD_BOOKMARK wxART_DEL_BOOKMARK wxART_HELP_SIDE_PANEL wxART_HELP_SETTINGS wxART_HELP_BOOK wxART_HELP_FOLDER wxART_HELP_PAGE wxART_GO_BACK wxART_GO_FORWARD wxART_GO_UP wxART_GO_DOWN wxART_GO_TO_PARENT wxART_GO_HOME wxART_FILE_OPEN wxART_FILE_SAVE wxART_FILE_SAVE_AS wxART_PRINT wxART_HELP wxART_TIP wxART_REPORT_VIEW wxART_LIST_VIEW wxART_NEW_DIR wxART_HARDDISK wxART_FLOPPY wxART_CDROM wxART_REMOVABLE wxART_FOLDER wxART_FOLDER_OPEN wxART_GO_DIR_UP wxART_EXECUTABLE_FILE wxART_NORMAL_FILE wxART_TICK_MARK wxART_CROSS_MARK wxART_ERROR wxART_QUESTION wxART_WARNING wxART_INFORMATION wxART_MISSING_IMAGE wxART_COPY wxART_CUT wxART_PASTE wxART_DELETE wxART_NEW wxART_UNDO wxART_REDO wxART_QUIT wxART_FIND wxART_FIND_AND_REPLACE wxRIGHT|wxEXPAND 5 wxALIGN_CENTRE_VERTICAL wxHORIZONTAL wxRIGHT|wxEXPAND 5 40,-1d wxRIGHT|wxEXPAND 5 2 1 wxEXPAND Python Module Config wxVERTICAL wxVERTICAL wxBOTTOM|wxLEFT|wxRIGHT 5 wxBOTTOM|wxLEFT|wxRIGHT 5 wxBOTTOM|wxLEFT|wxRIGHT 5 0 1 wxBOTTOM|wxLEFT|wxRIGHT 5 wxALL 5 wxHORIZONTAL 500,-1 wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 5 wxBOTTOM|wxRIGHT 5 wxEXPAND wxALL 10 wxEXPAND wxHORIZONTAL 1,10 1 10,1 10,1 wxALL|wxEXPAND|wxALIGN_CENTRE_HORIZONTAL 10 XRCed Preferences wxVERTICAL wxVERTICAL 2 2 30,-1d 150,-1 10 wxALL 5 wxVERTICAL 2 2 30,-1d 150,-1 10 wxALL 5 ask always never wxALL|wxALIGN_CENTRE_HORIZONTAL 5 0,10 wxALL|wxALIGN_CENTRE_HORIZONTAL 10 spe-0.8.4.h/_spe/plugins/XRCed/XRCed_16.png0000644000175000017500000000103610763311540017113 0ustar stanistaniPNG  IHDRh6 pHYs  IDATx1hQrWޔdzSxqn( tMu`p8C`A4CJGC#Cu1*֊!-}/gfKZ`%֋-!z+A2L44<[} 楺zB^TBJiLMDLNݵGk03i˶Off)|!|H8筍߹`p6 ?d6Zre,sRa^E#˶v^ 8̡j<>oFqX,Ɵqs3)JRdXSJq\,B[_!p/[IxMyٗ  !}kX5*Q1(5HSP A)8( "_!+Xq*yBYfL,{:x1@z,_ 14IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/0000755000175000017500000000000011004131464017156 5ustar stanistanispe-0.8.4.h/_spe/plugins/XRCed/src-images/Undo.png0000644000175000017500000000176310763311540020606 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs B(xtIME 8?TIDAT8˭_h[UǿM{]t\u>̗"[բȊ21ʄ>QEA>>8(/ -[ctaݬڤuB{[.Yxǽ=øtnd2] iK CG43vHoCg{m`e'G*~E2ްpôS7N`U83#<F0lr/}AC"JG^G=P(=lxtÏ?=P%l-ٽuW3Y#Y\)6fzUpx{i{z%dV+ CG64 [_|i\ǟBy̷zDhCӬZ¬@O~\[I-""fx嘇tuqi*-lp/OYz? +YPu̵}GxMZ]܅սu1AE,IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolTreeCtrl.png0000644000175000017500000000023210763311540022251 0ustar stanistaniPNG  IHDR&/aIDATx 0Ca 6Ho"qo|l"Dw4kkYUJ Ddn1"Dk< vWdx*2= IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/MoveLeft.png0000644000175000017500000000177410763311540021424 0ustar stanistaniPNG  IHDRĴl; pHYs  tIME 4 xIDAT8kEǿ?ݭn.x&vQB |SHڼJ,7}SEAA9@!Eһ/65 >0wv?wb۶STLa8N<==eY/zy+ nUGt8N\.^9$ zayyJ} q ۶_A8󛛛$abbbdddfJ-u2o("awwr=pRY\..kEQth4:Ex_J%Ryˌ9wX_p]7hmuubz7;oRJ?puq8QT"bqAcH%0MSeiUUOID [󭍍 >:O&''y:54eMӞ7MC4O+BjZ}²!|>ܙ)1 Cj5}ii <hY!s3( "ؘ(OQ]O`Cuh4 T*]NeYt]+BAE^fqj9SJ?Vz|B^ws~(- po[KwV["|uo,(Z%"Q Ȅ|w*<ܻ\H Q.]>2! @Y0%ct>,<+i}?Y P0.K( `@Q LA5M12wIrv܎mK $I&7^mR= 8hEp XM|ea(IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeComment.png0000644000175000017500000000023610763311540022115 0ustar stanistaniPNG  IHDR&/bKGDD(M pHYs  tIME  ) +IDAT(c`?16Ql#"FzP ->F?IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolScrollBar.png0000644000175000017500000000037610763311540022421 0ustar stanistaniPNG  IHDR IDATx g ͬ%`܄zF6^ M H|'~>ypDO#G\ЮQ=eb+c*TCz~SJw7@-sҜ_1!ΏjqB!zPH\vs{>S\_}Rr/\.Y(׋{CHAŬ]HIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeToolBar.png0000644000175000017500000000027110763311540022054 0ustar stanistaniPNG  IHDRaIDATx퓻 0DB-%\ Bs!pri4#۫u!Z58? Rns "*xU`2jNUR+ cp._"IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolListCtrl.png0000644000175000017500000000024710763311540022273 0ustar stanistaniPNG  IHDRqܚnIDATxc2u B#gk L8X*: 5c18<F,# 4:1ai-A$iG҂zR oye/l3IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Refresh.png0000644000175000017500000000252410763311540021273 0ustar stanistaniPNG  IHDRĴl;sBIT|dtEXtSoftwarewww.inkscape.org<IDAT8iLg;3;K9[kEh&1iOM&415iZ$54iGb53LNUxO&3E,kÓ]zCM/ >5+5nmJ_;$ nB8,!Xd1 CH `"wĴUtyh*K1C!vò)B0cK`e)N,MZ.j\귊Ԥx iNl.HH01HK97rŢ.jHc,ҎGH^V@s>⪦1ǸqFO;Jkdl9ƀnL)@VZPv>,}\Gyd\5Bi^߉ հNITɰHll͜3nӖ)?FU4/],a}@8qܝ01kr08Đȁ-=])nJXb\d"CUzm)c5;_ft/EĴyϋW 3tǾg'NƐ֐8'k+z"0g4C5&8߱im˺,7`"0/M.R]MG e/$"0Ƥ FﺸqQʝ%իOMQ2ScaC0L ]qC=81raa"gu~s=}5)++ZZp:UFLߟ}6uE$ }͛ /PDFn%! !F\GPѢ1&́D a7oEcD0Ț)i\r`IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeSeparator.png0000644000175000017500000000014710763311540022454 0ustar stanistaniPNG  IHDR&/.IDATx DC4',}>:өIlF)IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeDefault.png0000644000175000017500000000023210763311540022073 0ustar stanistaniPNG  IHDR&/sBIT|dQIDATxc`0Q x?., x ````q؁:a@@d`_ ` C?%Rl ZUIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolComboBox.png0000644000175000017500000000035110763311540022237 0ustar stanistaniPNG  IHDRF(IDATx E+ $": U"dJq0؆cg6" sbf4΁gSb\| "<8:\SQf@H6Ձ2)[ST,ydR>_{ojHL yHXZ IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeRoot.png0000644000175000017500000000025210763311540021434 0ustar stanistaniPNG  IHDR&/sBIT|daIDATx 0Ca 6Ho"qo|l"Dw4kkYUJ Ddn1"Dk< vWdx*2= IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolSpacer.png0000644000175000017500000000037110763311540021746 0ustar stanistaniPNG  IHDRabKGD pHYs  ~tIME 2} HIDATxݓ E Gs)2 Hs>*1 |,/ Zt؋hQ,ӭ?U8^Gmr303$%3uo:\ŌdD}۾IȯQHN Na=(IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolStaticLine.png0000644000175000017500000000012210763311540022562 0ustar stanistaniPNG  IHDRXIDATxc2u*lZ|B@2}IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Test.png0000644000175000017500000000233410763311540020613 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs  tIME {RiIDAT8}MlTULt^ HiX"PlERQD㚅 7cBb,0ƅ,1|-+EH[>4v:3ś {9'x֊/NO)"1|yAߊ{?{zT^ݫhm6btgj*={kRt'7h*,5:;(,+sۥ?by @_B|mXoBT)NbLc^8M\.[1Sork׶9rz:}JD*R' س )eOZm/-:>b~ ٖ>JDbCb?? Yƀ_ë'"¦ |fg}^x~kc4˼#xA07~vl6z=ڰ)h~KYB ACiV}H26l5}zY 09ɮZ-C꣆E[ZWqvL{{ZwˮKAFJƓ XO[G|;8{bHoxQn;ZC,/88c7[cV)C^pVlN0%tiɢ "ڵ2p Tcn'"bCUo@.' Wf}\$e*lʒ|8,#؂J} I\P_kL z~% M@9 lIRA/I lh*<*ȅNɈNrFbIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolChoice.png0000644000175000017500000000030110763311540021714 0ustar stanistaniPNG  IHDR $IDATxK Dg)DZ+Xo#W Z8{κO*ȘYӊHvC7vkQub<E_Q z.٥+FٷvGB;աBj5ܜ0eIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolDefault.png0000644000175000017500000000023210763311540022111 0ustar stanistaniPNG  IHDR&/sBIT|dQIDATxc`0Q x?., x ````q؁:a@@d`_ ` C?%Rl ZUIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeMenu.png0000644000175000017500000000024610763311540021420 0ustar stanistaniPNG  IHDRasBIT|d]IDATxc`o^g pp002000K޸q1 0ĘZG^T  0 ` I3lals=IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolMenuItem.png0000644000175000017500000000020710763311540022252 0ustar stanistaniPNG  IHDR TNIDATxc"  Í7*>p 6SЁM 9 jp`d`` :h[߻IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolBitmapButton.png0000644000175000017500000000115010763311540023135 0ustar stanistaniPNG  IHDRw=/IDATx?hQ?^dȍ:٭EfET:h-E:X:FH!$9Bnr`pp`0`JJ$h];-צe\ק M2s')ml˴̃?mXDhpds!.f^a܃ &FZPxj"S$dJesрw;5ʂM%@%5{O_[!AÆPABARRĦ(54J"FDۯP\{gIsph_ B4A\Py=ܓ>&b$8u!QOP]& :]vv8ndn(o->I+ØU12׸p^XPz -qt77@oᄸIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/MoveUp.png0000644000175000017500000000220710763311540021106 0ustar stanistaniPNG  IHDRĴl; pHYs  tIME 2&IDAT8OhUǿyfwvSԃkƢ)iCMz, *փҊxA! H(] D{IMI1ݝ}ٰ&1yw BS&ɚEˢe+Y%"z5>uI7x<Ş\P$}`T2Tҩ_ !ąK|  %ݼ "a\7 zxNޫqB Q"d4ih:AYɲG".@W}K=xx 8a+&d2yA`ccoff̓ ;?HP(\"J)nL$I)%Z4MCiàt( sr!^CJfyܕ2vX|5M‚ev&qj> tK)eV;ڶy }॥v6W?V妶Rž*8Ӻ%$av9CIX_r04 Pӊ[7Z{.:Eo味f~mMz4S)B؍Q;0uIo[;mcvցck'O`J>.ՔMz7~z1C+X3y#VcWAB(亗1O(loȻڮvQ#,`=ƸearIw*IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/MoveDown.png0000644000175000017500000000216610763311540021435 0ustar stanistaniPNG  IHDRĴl; pHYs  tIME 1AlIDAT8Mh\Usɝɟzf&tEi$]lBq+t`q!(Eu+H JwNLMsd/yxw{YR1j ԩSLNNI5 WJ }G$̼h>9޽aT*{rMEQ011'vvvR5!01 &`w^LMiF!NqH)tWg B{^WV=UU/ض4 mlڭV 첔w/ Y>sEn*,t&IZUu4Ms! }<؛kۇiRV_(aA{Ee)kB\m97R8DpUU 88_ҭ n?tWPKN>~+SSS塡!ekk5 㛽w'''onll &DȀC`0“'O>̙8=vƍ:xPV+ŞtƉh. Fs\.{pww7_,iҽ+=!NGa``vRJߋ]hazzzsmCpfӲ,vQi{) s8r̲8m_{w5nb6M3,l~u+TEQԉN[i 2@^KUݕX5!Re)~XrEy)$ӈhOur]w_㜗ADQM̥eԿu$OD>zW_4}_fMڣ_eEciP =|o;vreUr cN=?_ukضp_Q Bu`/6х>(RGci]׉s~?Ԅث aԄx4pR9}DK@D.j 5 `(lIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolMenu.png0000644000175000017500000000024610763311540021436 0ustar stanistaniPNG  IHDRasBIT|d]IDATxc`o^g pp002000K޸q1 0ĘZG^T  0 ` I3lals=IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolFrame.png0000644000175000017500000000020310763311540021555 0ustar stanistaniPNG  IHDRasBIT|d:IDATxcd``@`P?D @0pY t A0, 8)cyvFIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolSeparator.png0000644000175000017500000000012010763311540022461 0ustar stanistaniPNG  IHDRzIDATxc2u  ;+BCIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Paste.png0000644000175000017500000000144010763311540020745 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs  tIME ,(yQIDAT8MHTQ'-mqI@PrMX䈴ȬM`;wۦE0 mE nkEI.$ 1Cgt9ӌ-9X{w}#bttoYtX(h+s8RO~'t!DfRoh;#~B>?}Zsghoo.keښ s۟ӑ^_n>nμCF:N&acKT^E5;c(Wpکs84=xә|rY|73#-H%Af n6@t:]lBrO˲!pT+&GP( z+5*TG",SU \l5.@?a权NSS`K ^7?6vBZJ࠷PL_skHi+P܊_.xsye2kX]>]_ͷ"k1 4wŸpII$Ae]07z5ՖܵrJQZ[,E+G˯L<Oim9iK^ϑ–H{.UK6Y! f)Zĝ\<֜e\ -{-/ā[U 7И l|0 \{IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeMenuBar.png0000644000175000017500000000025310763311540022043 0ustar stanistaniPNG  IHDRasBIT|dbIDATxc`0Q{PϏj```a```qɚ81Y888D p 1cE.`d`` ;GDOQkIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/New.png0000644000175000017500000000126410763311540020426 0ustar stanistaniPNG  IHDRĴl;bKGDO4ױ pHYs B(xtIME%0C& AIDAT8˭kaTM5IDL-O]abIv^NA)N6j } q޽;H(E j, {SVD42Nlh1D1le4NOьyxI/ NԸ[NI f6ƅUP,c+Ap{պ:˫c #MIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolButton.png0000644000175000017500000000026610763311540022007 0ustar stanistaniPNG  IHDR $}IDATxŔA '}EؓJwH Zk%H"BâlQƥX@ {>ݛgӘ-?FmYPS;EoU1Gg4 \ؘtUvj N1$iqIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolRoot.png0000644000175000017500000000025210763311540021452 0ustar stanistaniPNG  IHDR&/sBIT|daIDATx 0Ca 6Ho"qo|l"Dw4kkYUJ Ddn1"Dk< vWdx*2= IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolStaticBoxSizer.png0000644000175000017500000000025510763311540023447 0ustar stanistaniPNG  IHDRasBIT|ddIDATxA 054>3U,ISsxE҉D%lr+5 lgyETgAMA aEIDATxc2u UU ? mz*@Y LרA WX Եppttįa0Q"K AIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/AutoRefresh.png0000644000175000017500000000251110763311540022120 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs  tIME#~IDAT8ŕ[lTEƿ9gvO-ZʵP! /|T 1Ġ! /`@7Evt۽یnm7'~gorm=SK֟]Ă*J"ǀ i pra]期%Qteg1*7s5oG40^R{ͭ=[TT044čO[C ~I~XV)፶4Sk-ΞuNCUp*(((!(!h5$[EotĢFo4ueTY}}h@ar.([-LϩP^ ph"sso";M$I]N[z0D3eiRK$টxno'!`*Ac(TJ- jRKq9sCISc4yC-n޸\wNu޽?M<GZF S ,3m:"Bq#=(r LLߩfىDB0E <;ڳ.NLpl tͲk 0˶`1ln~_ ޹FWN#ecd>kVC-/o@Ɏ@u8}ǧ D_6x'fgJneE|"? dJKY*)_tn£΅K%O;̀,.5xx{oh"Rkr^JP,Y$*ao3=MPJrFNON] kBz aijCeQ+T8چG yx* ÍEIgSJI4tWl/1p,+\.g2PP€MLh!E zydJ^|xcZ)@`v`zyDrB:mN┝0AM~컺ݗ dUPO{oH^]f+$ !FŒ3.(oi=t> R@|LV^](iSbr.s\x( SRH/kbiIILHI`Ʀ?D|>eIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolToolBar.png0000644000175000017500000000024510763311540022073 0ustar stanistaniPNG  IHDRvlIDATx 0 Q\PxdBUp/[<ۺ&@Jp17dVd("(zO\.l U`V{c Z^Y7:IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolDialog.png0000644000175000017500000000022210763311540021723 0ustar stanistaniPNG  IHDRasBIT|dIIDATxcd``@`P?D @0pY t A$8@b888mI) c̡IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolStaticBitmap.png0000644000175000017500000000110010763311540023104 0ustar stanistaniPNG  IHDRȝIDATx}1hQnx;pCn-84LPRKh,*qtz (;qhPȁ{9;SO}4JQ*f\mz&wېxOtSy:ߣh pt+dMR{}lK``Zˀj@+1Oݬ\~ByMV! äQټZ$+XfA`"k93G)% Rs"H!zuq(CP#XPaH:~3!HbEƴ^fdwB D#C"9\6\mm;98_t0 4_:q?t%ҕlܩ$ҕ_JR{t79uHs+cc#'CO,XiWifjy5yScVAϡX,|m)#A@YK7x?< ØAKBi!-2[խ.B)%/IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeMenuItem.png0000644000175000017500000000021310763311540022231 0ustar stanistaniPNG  IHDR&/RIDATxc`hc?8X8zY%nܸAPPLڊ `D0(vmͩD#tEPMᘬwIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolCheckList.png0000644000175000017500000000035110763311540022400 0ustar stanistaniPNG  IHDRoIDATx͔A E+;ZvZ0_E/Th >SYSJ}>X6hւLBh}d_;3b)2ȂGȤDz zPɽYSPK=z.MC Mz ? zj_#s饸3oP{wzOcTd!IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolSlider.png0000644000175000017500000000027110763311540021752 0ustar stanistaniPNG  IHDR5~IDATxݔ 0 E_ĩgqqtx hJLBLdT }s3q4mj]wsaY.UO^jB 9 &p$%516|x3`V8?!iIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolFlexGridSizer.png0000644000175000017500000000021310763311540023245 0ustar stanistaniPNG  IHDRasBIT|dBIDATxc` @&`16,] g"fxGqj@qBb+FIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeFrame.png0000644000175000017500000000020310763311540021537 0ustar stanistaniPNG  IHDRasBIT|d:IDATxcd``@`P?D @0pY t A0, 8)cyvFIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolGridSizer.png0000644000175000017500000000020510763311540022427 0ustar stanistaniPNG  IHDRasBIT|d%33g<4t:m֡zX.Cac"ǑPJAkU=:̌`*l6|>( !k BHH)Ag&`bb"l uݡ"ES.s[ZqSֻob/z" 7BH@k=t^<P>36q=?wOp]ׁcM\ׇL6:=z%X)L&cRFwA陷xVz;=~b0[sσ?*mAIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolTool.png0000644000175000017500000000016710763311540021451 0ustar stanistaniPNG  IHDR oG>IDATxc6p 40000a,hj |3n&b ๽"IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Icon.png0000644000175000017500000000212710763311540020564 0ustar stanistaniPNG  IHDR DPLTEUUUrrr999rrUU99}IDATxۚ0IPH@ꦭ-J0]!D] )j]|(\"r.E@ylꀧh"zҢz(Tke;(L9BS̽pxf$ʨ_YJ{e4 @bSE^[@Ay27L+[.ɏX,}kkU##ƆjjkM++tX67n<(BX_MN"Z`.L]߃ %r9H-5IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolBoxSizer.png0000644000175000017500000000021510763311540022273 0ustar stanistaniPNG  IHDRasBIT|dDIDATxc`0Q0000 k60bST0Q@@83 9fIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreePanel.png0000644000175000017500000000021410763311540021546 0ustar stanistaniPNG  IHDR&/sBIT|dCIDATx10 CW?Qt@ 11^ui2c Ga Aβ@Lpr %l 6IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/LocateArmed.png0000644000175000017500000000072710763311540022060 0ustar stanistaniPNG  IHDRw=bKGD pHYs  tIME##dIDATHǵ1n0 E){{ g"3=C_h,p[ C1] ;'-BM ?%-OtK658rٱPIق\aeA5%,ir"r<{; lxZc"أ#Ƙ&2n8`\C@y~I2tmƜC-EΟ XU˂1e 1UΘD-lXXo 7W7sLY}.D֢a*W{*X$Ƙ1a칆|-֢1D,ec7{)t?^'XZM.wеyڼxK| HP IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolTextCtrl.png0000644000175000017500000000020110763311540022272 0ustar stanistaniPNG  IHDR $HIDATxc2u05j*0j  e젉."2$ڍ IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolStaticBox.png0000644000175000017500000000027510763311540022434 0ustar stanistaniPNG  IHDR}\IDATxK D;7b|7 iXT ;ޘlogbaϒի@Ud8BzHR"cg (&+ bNܷ; Kr9&0%PWO9m$JHfIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolGauge.png0000644000175000017500000000021510763311540021556 0ustar stanistaniPNG  IHDRK)TIDATxc2u UU ? )xU"b޿~OpIl۽: F " X9)r S0>RU9IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolSpinButton.png0000644000175000017500000000024110763311540022632 0ustar stanistaniPNG  IHDR HUChIDATx 0 /i`4:N[8CNQl$ ۾R z%Z+rΤ%;L̬['.@YyᜨZ<^y.9`EOIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolNotebook.png0000644000175000017500000000037510763311540022315 0ustar stanistaniPNG  IHDRw=IDATxM! _ 0W'xaסcpa6fft@D3ȩf46kW!?$r[\*  Vnk2%:{{). }Lrq֡OMV[C-&КS$ ->D $(<ӿ (5R# ?tOxp_IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolSpinCtrl.png0000644000175000017500000000046410763311540022272 0ustar stanistaniPNG  IHDR $IDATx͍0YmĦ#"\l;Hpȁfa'qy+ZOW]Ϊ7QzNciׅnj /=^Q4*AV"Z 0dpߊcl.wXora?>V*ڡ.|eZK:Draf{pj&ǖ#s1I[ •G("OjEu3?:!nAnC:cIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolMenuBar.png0000644000175000017500000000025310763311540022061 0ustar stanistaniPNG  IHDRasBIT|dbIDATxc`0Q{PϏj```a```qɚ81Y888D p 1cE.`d`` ;GDOQkIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeSizerFlexGrid.png0000644000175000017500000000021310763311540023227 0ustar stanistaniPNG  IHDRasBIT|dBIDATxc` @&`16,] g"fxGqj@qBb+FIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolUnknown.png0000644000175000017500000000022110763311540022162 0ustar stanistaniPNG  IHDRh6XIDATxc` 0200\vHZ,XElLb7;k@0pq=aO#&Ѐ`8\fA[K7h$OgIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolGridBagSizer.png0000644000175000017500000000027510763311540023050 0ustar stanistaniPNG  IHDRabKGD pHYs  ~tIME % MJIDATxc` @&`16,aB3k3  b`THHJIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Open.png0000644000175000017500000000175110763311540020577 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs B(xtIME /4|vIDAT8˵_h[U?6In֦ٲsE:dd ΉA|VaԲu > Ylk?v%I,i6ɹMȶ ~~~~{~>8(F=!P[<|w ( rFqwY)w"YyW zP;o>i,|~ٹX'CC 'AtXdb|p$L_/'y|>G> 5H=~X]Pv8NZ=PTJ;VB,PJam;LgROC" ϿH6_ (n1H=¶D?fNid^ypd6e9:j]Gݕ6p;z<9c?\f(U+1Pǎ@\T=#ruh0*e0ͮV=IeR?[ ;օѱ$Q]v(mM_3@a}lDғ#1`iЇ,U`[7O*_a[ڳeRa%UrОX?fX,~ &+7DǢɾfE&&o@r*5'z̪މ浾[gM4:uxtۺhU#RߦFcs"`6kSSEv[fS8@w)ݚ`[K)_9d^IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolListBox.png0000644000175000017500000000027010763311540022113 0ustar stanistaniPNG  IHDRqܚIDATxՔA w?ٯ! 6'd݌!gb,JHS\aޑ SaH\T FRbJA,=#ײxpS+= S7Y׾FKv )>BIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolCheckBox.png0000644000175000017500000000016510763311540022220 0ustar stanistaniPNG  IHDR 2Ͻ>Os}8]mCbn g^/p΅$I SE_ !ZD'sh=4>ޮR/:b1G3 FZvjV_MUp@hE`N_p&a###l6{kbb"%UU댱OOVin CtV_abvvB\>{~ZN/xM@`r 1MӮ>Su]`!ŮxblRbpUOYW )o`UUQ.E"(, JN'y ܖ=VW4<==(%ɠm_W; 5Lv6?*yOK'''Ah4!%/L5(ӿadIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolStaticText.png0000644000175000017500000000024610763311540022626 0ustar stanistaniPNG  IHDR cmIDATxSA 0ӱט?~; B7XnFDe-gcᷠ0to,% m3rK02 Ǡ8|?d+0܄sZfT{B> ;W6} mLtӐIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Cut.png0000644000175000017500000000223110763311540020423 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs  tIME 21A|&IDAT8˅]H\G3;wݬ&cc̮641%Ո$Җ>I_6AK@!!!?Si5%&icm4{g!+Ȳ s99 I_,4ͪ;@ϞjЩi?$ir22#4M}kiN7^x ڴo/HǽͲgPa۹/-sqw* iD#ix|j5nCa mW<>'33s`y8Bi-=]"%#YWm.O 7VZڻ҂Z484 N'xyy?=R9c=X,Z+F[K{끇ݗ w_tkꀔwb6'ٲ`y%233?)(,'hSZ{-mfAQ9!iGBtsN>go "!D1=3 f=H`(psx$P]sTeqI)Lӄa?|M;U: &@qq1BXzAc30IqnӴJHmsmޗ㿣5b/UtKQ̤퍊yQVV(P賆gge"W0- iʊcq>wu˕'}4pgX gaQL|+˕/lkR{Wx^$pۡ(Xaw7XPBt/}H^h}ji>1a%!Tv;(!':{JȼnXÒCczk䞠clL,,,r @,^xv-/PA] @`4q 3vy.@0χe)~ىէRPUd( `1@M!]մ*e%%Iyi$bVR]V3BD[9|b4z$;M@\J@ĺ ,՟IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/ToolRadioButton.png0000644000175000017500000000031010763311540022754 0ustar stanistaniPNG  IHDR w&IDATxu 0?Ml `–#[XMxH)gg%a^8ɂ^99=lϿ5c%ŶKKm0,G8Fw,G!g r> ^k+ix{Y cn1IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeSizerV.png0000644000175000017500000000021010763311540021725 0ustar stanistaniPNG  IHDRasBIT|d?IDATxc`@! k60,t F#JF# 8ѳ3& mXtZIENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeDialog.png0000644000175000017500000000022210763311540021705 0ustar stanistaniPNG  IHDRasBIT|dIIDATxcd``@`P?D @0pY t A$8@b888mI) c̡IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/TreeStaticBoxSizerH.png0000644000175000017500000000025510763311540023541 0ustar stanistaniPNG  IHDRasBIT|ddIDATxA 054>3U,ISsxE҉D%lr+5 lgyET|_@@&B?|$B5a\ k60nX;8 i&; lQEآ oű$S0&0IENDB`spe-0.8.4.h/_spe/plugins/XRCed/src-images/Save.png0000644000175000017500000000217610763311540020576 0ustar stanistaniPNG  IHDRĴl;bKGD pHYs B(xtIME 4Her IDAT8˭]lU39meeY>"ڒVX0B4F|5HUR FilD4ȋh 16ƈ4AT%6ݶvggw|hwlPL'7s=3W`{?ƦH\om~8ያ#>1UeNϸT:CdVۻ_;rĖ"U[pm##J+PvutPv=ܹϥ:p+bkw'tO>P+Ft6N<@}A/.yYb5%3}}pG_6G$TUHNeRELhekԡ>;r?Ϫ I۩7/Jrk|ow_&ǎdۺe) This will cause the script to freeze until a debugger console attaches. _rpdb2_pwd - The password that governs security of client/server communication fAllowUnencrypted - Allow unencrypted communications. Communication will be authenticated but encrypted only if possible. fAllowRemote - Allow debugger consoles from remote machines to connect. timeout - Seconds to wait for attachment before giving up. If None, never give up. Once the timeout period expires, the debuggee will resume execution. source_provider - When script source is not available on file system it is possible to specify a function that receives a "filename" and returns its source. If filename specifies a file that does not fall under the jurisdiction of this function it should raise IOError. If this function is responsible for the specified file but the source is not available it should raise IOError(SOURCE_NOT_AVAILABLE). You can study the way source_provider_blender() works. Note that a misbehaving function can break the debugger. fDebug - debug output. IMPORTNAT SECURITY NOTE: USING A HARDCODED PASSWORD MAY BE UNSECURE SINCE ANYONE WITH READ PERMISSION TO THE SCRIPT WILL BE ABLE TO READ THE PASSWORD AND CONNECT TO THE DEBUGGER AND DO WHATEVER THEY WISH VIA THE 'EXEC' DEBUGGER COMMAND. It is safer to use: start_embedded_debugger_interactive_password() """ return __start_embedded_debugger( _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, timeout, source_provider, fDebug ) def start_embedded_debugger_interactive_password( fAllowUnencrypted = True, fAllowRemote = False, timeout = TIMEOUT_FIVE_MINUTES, source_provider = None, fDebug = False, stdin = sys.stdin, stdout = sys.stdout ): if g_server is not None: return while True: if stdout is not None: stdout.write('Please type password:') _rpdb2_pwd = stdin.readline().rstrip('\n') _rpdb2_pwd = as_unicode(_rpdb2_pwd, detect_encoding(stdin), fstrict = True) try: return __start_embedded_debugger( _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, timeout, source_provider, fDebug ) except BadArgument: stdout.write(STR_PASSWORD_BAD) def settrace(): """ Trace threads that were created with thread.start_new_thread() To trace, call this function from the thread target function. NOTE: The main thread and any threads created with the threading module are automatically traced, and there is no need to invoke this function for them. Note: This call does not pause the script. """ return __settrace() def setbreak(): """ Pause the script for inspection at next script statement. """ return __setbreak() # #----------------------------------- Interfaces ------------------------------ # VERSION = (2, 3, 4, 0, '') RPDB_VERSION = "RPDB_2_3_4" RPDB_COMPATIBILITY_VERSION = "RPDB_2_3_4" def get_version(): return RPDB_VERSION def get_interface_compatibility_version(): return RPDB_COMPATIBILITY_VERSION class CSimpleSessionManager: """ This is a wrapper class that simplifies launching and controlling of a debuggee from within another program. For example, an IDE that launches a script for debugging puposes can use this class to launch, debug and stop a script. """ def __init__(self, fAllowUnencrypted = True): self.__sm = CSessionManagerInternal( _rpdb2_pwd = None, fAllowUnencrypted = fAllowUnencrypted, fAllowRemote = False, host = LOCALHOST ) self.m_fRunning = False event_type_dict = {CEventUnhandledException: {}} self.__sm.register_callback(self.__unhandled_exception, event_type_dict, fSingleUse = False) event_type_dict = {CEventState: {}} self.__sm.register_callback(self.__state_calback, event_type_dict, fSingleUse = False) event_type_dict = {CEventExit: {}} self.__sm.register_callback(self.__termination_callback, event_type_dict, fSingleUse = False) def shutdown(self): self.__sm.shutdown() def launch(self, fchdir, command_line, encoding = 'utf-8', fload_breakpoints = False): command_line = as_unicode(command_line, encoding, fstrict = True) self.m_fRunning = False self.__sm.launch(fchdir, command_line, fload_breakpoints) def request_go(self): self.__sm.request_go() def detach(self): self.__sm.detach() def stop_debuggee(self): self.__sm.stop_debuggee() def get_session_manager(self): return self.__sm def prepare_attach(self): """ Use this method to attach a debugger to the debuggee after an exception is caught. """ _rpdb2_pwd = self.__sm.get_password() si = self.__sm.get_server_info() rid = si.m_rid if os.name == 'posix': # # On posix systems the password is set at the debuggee via # a special temporary file. # create_pwd_file(rid, _rpdb2_pwd) _rpdb2_pwd = None return (rid, _rpdb2_pwd) # # Override these callbacks to react to the related events. # def unhandled_exception_callback(self): _print('unhandled_exception_callback') self.request_go() def script_paused(self): _print('script_paused') self.request_go() def script_terminated_callback(self): _print('script_terminated_callback') # # Private Methods # def __unhandled_exception(self, event): self.unhandled_exception_callback() def __termination_callback(self, event): self.script_terminated_callback() def __state_calback(self, event): """ Handle state change notifications from the debugge. """ if event.m_state != STATE_BROKEN: return if not self.m_fRunning: # # First break comes immediately after launch. # print_debug('Simple session manager continues on first break.') self.m_fRunning = True self.request_go() return if self.__sm.is_unhandled_exception(): return sl = self.__sm.get_stack(tid_list = [], fAll = False) if len(sl) == 0: self.request_go() return st = sl[0] s = st.get(DICT_KEY_STACK, []) if len(s) == 0: self.request_go() return e = s[-1] function_name = e[2] filename = os.path.basename(e[0]) if filename != DEBUGGER_FILENAME: # # This is a user breakpoint (e.g. rpdb2.setbreak()) # self.script_paused() return # # This is the setbreak() before a fork, exec or program # termination. # self.request_go() return class CSessionManager: """ Interface to the session manager. This is the interface through which the debugger controls and communicates with the debuggee. Accepted strings are either utf-8 or Unicode unless specified otherwise. Returned strings are Unicode (also when embedded in data structures). You can study the way it is used in StartClient() """ def __init__(self, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host): if _rpdb2_pwd != None: assert(is_valid_pwd(_rpdb2_pwd)) _rpdb2_pwd = as_unicode(_rpdb2_pwd, fstrict = True) self.__smi = CSessionManagerInternal( _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host ) def shutdown(self): return self.__smi.shutdown() def set_printer(self, printer): """ 'printer' is a function that takes one argument and prints it. You can study CConsoleInternal.printer() as example for use and rational. """ return self.__smi.set_printer(printer) def report_exception(self, type, value, tb): """ Sends exception information to the printer. """ return self.__smi.report_exception(type, value, tb) def register_callback(self, callback, event_type_dict, fSingleUse): """ Receive events from the session manager. The session manager communicates it state mainly by firing events. You can study CConsoleInternal.__init__() as example for use. For details see CEventDispatcher.register_callback() """ return self.__smi.register_callback( callback, event_type_dict, fSingleUse ) def remove_callback(self, callback): return self.__smi.remove_callback(callback) def refresh(self): """ Fire again all relevant events needed to establish the current state. """ return self.__smi.refresh() def launch(self, fchdir, command_line, encoding = 'utf-8', fload_breakpoints = True): """ Launch debuggee in a new process and attach. fchdir - Change current directory to that of the debuggee. command_line - command line arguments pass to the script as a string. fload_breakpoints - Load breakpoints of last session. if command line is not a unicode string it will be decoded into unicode with the given encoding """ command_line = as_unicode(command_line, encoding, fstrict = True) return self.__smi.launch(fchdir, command_line, fload_breakpoints) def restart(self): """ Restart debug session with same command_line and fchdir arguments which were used in last launch. """ return self.__smi.restart() def get_launch_args(self): """ Return command_line and fchdir arguments which were used in last launch as (last_fchdir, last_command_line). Returns (None, None) if there is no info. """ return self.__smi.get_launch_args() def attach(self, key, name = None, encoding = 'utf-8'): """ Attach to a debuggee (establish communication with the debuggee-server) key - a string specifying part of the filename or PID of the debuggee. if key is not a unicode string it will be decoded into unicode with the given encoding """ key = as_unicode(key, encoding, fstrict = True) return self.__smi.attach(key, name) def detach(self): """ Let the debuggee go... """ return self.__smi.detach() def request_break(self): return self.__smi.request_break() def request_go(self): return self.__smi.request_go() def request_go_breakpoint(self, filename, scope, lineno): """ Go (run) until the specified location is reached. """ filename = as_unicode(filename, fstrict = True) scope = as_unicode(scope, fstrict = True) return self.__smi.request_go_breakpoint(filename, scope, lineno) def request_step(self): """ Go until the next line of code is reached. """ return self.__smi.request_step() def request_next(self): """ Go until the next line of code in the same scope is reached. """ return self.__smi.request_next() def request_return(self): """ Go until end of scope is reached. """ return self.__smi.request_return() def request_jump(self, lineno): """ Jump to the specified line number in the same scope. """ return self.__smi.request_jump(lineno) # # REVIEW: should return breakpoint ID # def set_breakpoint(self, filename, scope, lineno, fEnabled, expr): """ Set a breakpoint. filename - (Optional) can be either a file name or a module name, full path, relative path or no path at all. If filname is None or '', then the current module is used. scope - (Optional) Specifies a dot delimited scope for the breakpoint, such as: foo or myClass.foo lineno - (Optional) Specify a line within the selected file or if a scope is specified, an zero-based offset from the start of the scope. expr - (Optional) A Python expression that will be evaluated locally when the breakpoint is hit. The break will occur only if the expression evaluates to true. """ filename = as_unicode(filename, fstrict = True) scope = as_unicode(scope, fstrict = True) expr = as_unicode(expr, fstrict = True) return self.__smi.set_breakpoint( filename, scope, lineno, fEnabled, expr ) def disable_breakpoint(self, id_list, fAll): """ Disable breakpoints id_list - (Optional) A list of breakpoint ids. fAll - disable all breakpoints regardless of id_list. """ return self.__smi.disable_breakpoint(id_list, fAll) def enable_breakpoint(self, id_list, fAll): """ Enable breakpoints id_list - (Optional) A list of breakpoint ids. fAll - disable all breakpoints regardless of id_list. """ return self.__smi.enable_breakpoint(id_list, fAll) def delete_breakpoint(self, id_list, fAll): """ Delete breakpoints id_list - (Optional) A list of breakpoint ids. fAll - disable all breakpoints regardless of id_list. """ return self.__smi.delete_breakpoint(id_list, fAll) def get_breakpoints(self): """ Return breakpoints in a dictionary of id keys to CBreakPoint values """ return self.__smi.get_breakpoints() def save_breakpoints(self, _filename = ''): """ Save breakpoints to file, locally (on the client side) """ return self.__smi.save_breakpoints(_filename) def load_breakpoints(self, _filename = ''): """ Load breakpoints from file, locally (on the client side) """ return self.__smi.load_breakpoints(_filename) def set_trap_unhandled_exceptions(self, ftrap): """ Set trap-unhandled-exceptions mode. ftrap with a value of False means unhandled exceptions will be ignored. The session manager default is True. """ return self.__smi.set_trap_unhandled_exceptions(ftrap) def get_trap_unhandled_exceptions(self): """ Get trap-unhandled-exceptions mode. """ return self.__smi.get_trap_unhandled_exceptions() def set_fork_mode(self, ffork_into_child, ffork_auto): """ Determine how to handle os.fork(). ffork_into_child - True|False - If True, the debugger will debug the child process after a fork, otherwise the debugger will continue to debug the parent process. ffork_auto - True|False - If True, the debugger will not pause before a fork and will automatically make a decision based on the value of the ffork_into_child flag. """ return self.__smi.set_fork_mode(ffork_into_child, ffork_auto) def get_fork_mode(self): """ Return the fork mode in the form of a (ffork_into_child, ffork_auto) flags tuple. """ return self.__smi.get_fork_mode() def get_stack(self, tid_list, fAll): return self.__smi.get_stack(tid_list, fAll) def get_source_file(self, filename, lineno, nlines): filename = as_unicode(filename, fstrict = True) return self.__smi.get_source_file(filename, lineno, nlines) def get_source_lines(self, nlines, fAll): return self.__smi.get_source_lines(nlines, fAll) def set_frame_index(self, frame_index): """ Set frame index. 0 is the current executing frame, and 1, 2, 3, are deeper into the stack. """ return self.__smi.set_frame_index(frame_index) def get_frame_index(self): """ Get frame index. 0 is the current executing frame, and 1, 2, 3, are deeper into the stack. """ return self.__smi.get_frame_index() def set_analyze(self, fAnalyze): """ Toggle analyze mode. In analyze mode the stack switches to the exception stack for examination. """ return self.__smi.set_analyze(fAnalyze) def set_host(self, host): """ Set host to specified host (string) for attaching to debuggies on specified host. host can be a host name or ip address in string form. """ return self.__smi.set_host(host) def get_host(self): return self.__smi.get_host() def calc_server_list(self): """ Calc servers (debuggable scripts) list on specified host. Returns a tuple of a list and a dictionary. The list is a list of CServerInfo objects sorted by their age ordered oldest last. The dictionary is a dictionary of errors that were encountered during the building of the list. The dictionary has error (exception) type as keys and number of occurances as values. """ return self.__smi.calc_server_list() def get_server_info(self): """ Return CServerInfo server info object that corresponds to the server (debugged script) to which the session manager is attached. """ return self.__smi.get_server_info() def get_namespace(self, nl, filter_level, repr_limit = 128, fFilter = "DEPRECATED"): """ get_namespace is designed for locals/globals panes that let the user inspect a namespace tree in GUI debuggers such as Winpdb. You can study the way it is used in Winpdb. nl - List of tuples, where each tuple is made of a python expression as string and a flag that controls whether to "expand" the value, that is, to return its children as well in case it has children e.g. lists, dictionaries, etc... filter_level - 0, 1, or 2. Filter out methods and functions from classes and objects. (0 - None, 1 - Medium, 2 - Maximum). repr_limit - Length limit (approximated) to be imposed repr() of returned items. examples of expression lists: [('x', false), ('y', false)] [('locals()', true)] [('a.b.c', false), ('my_object.foo', false), ('another_object', true)] Return value is a list of dictionaries, where every element in the list corresponds to an element in the input list 'nl'. Each dictionary has the following keys and values: DICT_KEY_EXPR - the original expression string. DICT_KEY_REPR - A repr of the evaluated value of the expression. DICT_KEY_IS_VALID - A boolean that indicates if the repr value is valid for the purpose of re-evaluation. DICT_KEY_TYPE - A string representing the type of the experession's evaluated value. DICT_KEY_N_SUBNODES - If the evaluated value has children like items in a list or in a dictionary or members of a class, etc, this key will have their number as value. DICT_KEY_SUBNODES - If the evaluated value has children and the "expand" flag was set for this expression, then the value of this key will be a list of dictionaries as described below. DICT_KEY_ERROR - If an error prevented evaluation of this expression the value of this key will be a repr of the exception info: repr(sys.exc_info()) Each dictionary for child items has the following keys and values: DICT_KEY_EXPR - The Python expression that designates this child. e.g. 'my_list[0]' designates the first child of the list 'my_list' DICT_KEY_NAME - a repr of the child name, e.g '0' for the first item in a list. DICT_KEY_REPR - A repr of the evaluated value of the expression. DICT_KEY_IS_VALID - A boolean that indicates if the repr value is valid for the purpose of re-evaluation. DICT_KEY_TYPE - A string representing the type of the experession's evaluated value. DICT_KEY_N_SUBNODES - If the evaluated value has children like items in a list or in a dictionary or members of a class, etc, this key will have their number as value. """ if fFilter != "DEPRECATED": filter_level = fFilter filter_level = int(filter_level) return self.__smi.get_namespace(nl, filter_level, repr_limit) # # REVIEW: remove warning item. # def evaluate(self, expr): """ Evaluate a python expression in the context of the current thread and frame. Return value is a tuple (v, w, e) where v is a repr of the evaluated expression value, w is always '', and e is an error string if an error occurred. NOTE: This call might not return since debugged script logic can lead to tmporary locking or even deadlocking. """ expr = as_unicode(expr, fstrict = True) return self.__smi.evaluate(expr) def execute(self, suite): """ Execute a python statement in the context of the current thread and frame. Return value is a tuple (w, e) where w and e are warning and error strings (respectively) if an error occurred. NOTE: This call might not return since debugged script logic can lead to tmporary locking or even deadlocking. """ suite = as_unicode(suite, fstrict = True) return self.__smi.execute(suite) def complete_expression(self, expr): """ Return matching completions for expression. Accepted expressions are of the form a.b.c Dictionary lookups or functions call are not evaluated. For example: 'getobject().complete' or 'dict[item].complete' are not processed. On the other hand partial expressions and statements are accepted. For example: 'foo(arg1, arg2.member.complete' will be accepted and the completion for 'arg2.member.complete' will be calculated. Completions are returned as a tuple of two items. The first item is a prefix to expr and the second item is a list of completions. For example if expr is 'foo(self.comp' the returned tuple can be ('foo(self.', ['complete', 'completion', etc...]) """ expr = as_unicode(expr, fstrict = True) return self.__smi.complete_expression(expr) def set_encoding(self, encoding, fraw = False): """ Set the encoding that will be used as source encoding for execute() evaluate() commands and in strings returned by get_namespace(). The encoding value can be either 'auto' or any encoding accepted by the codecs module. If 'auto' is specified, the encoding used will be the source encoding of the active scope, which is utf-8 by default. The default encoding value is 'auto'. If fraw is True, strings returned by evaluate() and get_namespace() will represent non ASCII characters as an escape sequence. """ return self.__smi.set_encoding(encoding, fraw) def get_encoding(self): """ return the (encoding, fraw) tuple. """ return self.__smi.get_encoding() def set_synchronicity(self, fsynchronicity): """ Set the synchronicity mode. Traditional Python debuggers that use the inspected thread (usually the main thread) to query or modify the script name-space have to wait until the script hits a break-point. Synchronicity allows the debugger to query and modify the script name-space even if its threads are still running or blocked in C library code by using special worker threads. In some rare cases querying or modifying data in synchronicity can crash the script. For example in some Linux builds of wxPython querying the state of wx objects from a thread other than the GUI thread can crash the script. If this happens or if you want to restrict these operations to the inspected thread, turn synchronicity off. On the other hand when synchronicity is off it is possible to accidentally deadlock or block indefinitely the script threads by querying or modifying particular data structures. The default is on (True). """ return self.__smi.set_synchronicity(fsynchronicity) def get_synchronicity(self): return self.__smi.get_synchronicity() def get_state(self): """ Get the session manager state. Return one of the STATE_* constants defined below, for example STATE_DETACHED, STATE_BROKEN, etc... """ return self.__smi.get_state() # # REVIEW: Improve data strucutre. # def get_thread_list(self): return self.__smi.get_thread_list() def set_thread(self, tid): """ Set the focused thread to the soecified thread. tid - either the OS thread id or the zero based index of the thread in the thread list returned by get_thread_list(). """ return self.__smi.set_thread(tid) def set_password(self, _rpdb2_pwd): """ Set the password that will govern the authentication and encryption of client-server communication. """ _rpdb2_pwd = as_unicode(_rpdb2_pwd, fstrict = True) return self.__smi.set_password(_rpdb2_pwd) def get_password(self): """ Get the password that governs the authentication and encryption of client-server communication. """ return self.__smi.get_password() def get_encryption(self): """ Get the encryption mode. Return True if unencrypted connections are not allowed. When launching a new debuggee the debuggee will inherit the encryption mode. The encryption mode can be set via command-line only. """ return self.__smi.get_encryption() def set_remote(self, fAllowRemote): """ Set the remote-connections mode. if True, connections from remote machine are allowed. When launching a new debuggee the debuggee will inherit this mode. This mode is only relevant to the debuggee. """ return self.__smi.set_remote(fAllowRemote) def get_remote(self): """ Get the remote-connections mode. Return True if connections from remote machine are allowed. When launching a new debuggee the debuggee will inherit this mode. This mode is only relevant to the debuggee. """ return self.__smi.get_remote() def set_environ(self, envmap): """ Set the environment variables mapping. This mapping is used when a new script is launched to modify its environment. Example for a mapping on Windows: [('Path', '%Path%;c:\\mydir')] Example for a mapping on Linux: [('PATH', '$PATH:~/mydir')] The mapping should be a list of tupples where each tupple is composed of a key and a value. Keys and Values must be either strings or Unicode strings. Other types will raise the BadArgument exception. Invalid arguments will be silently ignored. """ return self.__smi.set_environ(envmap) def get_environ(self): """ Return the current environment mapping. """ return self.__smi.get_environ() def stop_debuggee(self): """ Stop the debuggee immediately. """ return self.__smi.stop_debuggee() class CConsole: """ Interface to a debugger console. """ def __init__( self, session_manager, stdin = None, stdout = None, fSplit = False ): """ Constructor of CConsole session_manager - session manager object. stdin, stdout - redirection for IO. fsplit - Set flag to True when Input and Ouput belong to different panes. For example take a look at Winpdb. """ self.m_ci = CConsoleInternal( session_manager, stdin, stdout, fSplit ) def start(self): return self.m_ci.start() def join(self): """ Wait until the console ends. """ return self.m_ci.join() def set_filename(self, filename): """ Set current filename for the console. The current filename can change from outside the console when the console is embeded in other components, for example take a look at Winpdb. """ filename = as_unicode(filename) return self.m_ci.set_filename(filename) def complete(self, text, state): """ Return the next possible completion for 'text'. If a command has not been entered, then complete against command list. Otherwise try to call complete_ to get list of completions. """ text = as_unicode(text) return self.m_ci.complete(text, state) def printer(self, text): text = as_unicode(text) return self.m_ci.printer(text) # # ---------------------------- Exceptions ---------------------------------- # class CException(Exception): """ Base exception class for the debugger. """ def __init__(self, *args): Exception.__init__(self, *args) class BadMBCSPath(CException): """ Raised on Windows systems when the python executable or debugger script path can not be encoded with the file system code page. This means that the Windows code page is misconfigured. """ class NotPythonSource(CException): """ Raised when an attempt to load non Python source is made. """ class InvalidScopeName(CException): """ Invalid scope name. This exception might be thrown when a request was made to set a breakpoint to an unknown scope. """ class BadArgument(CException): """ Bad Argument. """ class ThreadNotFound(CException): """ Thread not found. """ class NoThreads(CException): """ No Threads. """ class ThreadDone(CException): """ Thread Done. """ class DebuggerNotBroken(CException): """ Debugger is not broken. This exception is thrown when an operation that can only be performed while the debuggee is broken, is requested while the debuggee is running. """ class InvalidFrame(CException): """ Invalid Frame. This exception is raised if an operation is requested on a stack frame that does not exist. """ class NoExceptionFound(CException): """ No Exception Found. This exception is raised when exception information is requested, but no exception is found, or has been thrown. """ class CConnectionException(CException): def __init__(self, *args): CException.__init__(self, *args) class FirewallBlock(CConnectionException): """Firewall is blocking socket communication.""" class BadVersion(CConnectionException): """Bad Version.""" def __init__(self, version): CConnectionException.__init__(self) self.m_version = version def __str__(self): return repr(self.m_version) class UnexpectedData(CConnectionException): """Unexpected data.""" class AlreadyAttached(CConnectionException): """Already Attached.""" class NotAttached(CConnectionException): """Not Attached.""" class SpawnUnsupported(CConnectionException): """Spawn Unsupported.""" class UnknownServer(CConnectionException): """Unknown Server.""" class CSecurityException(CConnectionException): def __init__(self, *args): CConnectionException.__init__(self, *args) class UnsetPassword(CSecurityException): """Unset Password.""" class EncryptionNotSupported(CSecurityException): """Encryption Not Supported.""" class EncryptionExpected(CSecurityException): """Encryption Expected.""" class DecryptionFailure(CSecurityException): """Decryption Failure.""" class AuthenticationBadData(CSecurityException): """Authentication Bad Data.""" class AuthenticationFailure(CSecurityException): """Authentication Failure.""" class AuthenticationBadIndex(CSecurityException): """Authentication Bad Index.""" def __init__(self, max_index = 0, anchor = 0): CSecurityException.__init__(self) self.m_max_index = max_index self.m_anchor = anchor def __str__(self): return repr((self.m_max_index, self.m_anchor)) # #----------------- unicode handling for compatibility with py3k ---------------- # def is_py3k(): return sys.version_info[0] >= 3 def is_unicode(s): if is_py3k() and type(s) == str: return True if type(s) == unicode: return True return False def as_unicode(s, encoding = 'utf-8', fstrict = False): if is_unicode(s): return s if fstrict: u = s.decode(encoding) else: u = s.decode(encoding, 'replace') return u def as_string(s, encoding = 'utf-8', fstrict = False): if is_py3k(): if is_unicode(s): return s if fstrict: e = s.decode(encoding) else: e = s.decode(encoding, 'replace') return e if not is_unicode(s): return s if fstrict: e = s.encode(encoding) else: e = s.encode(encoding, 'replace') return e def as_bytes(s, encoding = 'utf-8', fstrict = True): if not is_unicode(s): return s if fstrict: b = s.encode(encoding) else: b = s.encode(encoding, 'replace') return b # #----------------------- Infinite List of Globals --------------------------- # # # According to PEP-8: "Use 4 spaces per indentation level." # PYTHON_TAB_WIDTH = 4 GNOME_DEFAULT_TERM = 'gnome-terminal' NT_DEBUG = 'nt_debug' SCREEN = 'screen' MAC = 'mac' DARWIN = 'darwin' POSIX = 'posix' # # Map between OS type and relevant command to initiate a new OS console. # entries for other OSs can be added here. # '%s' serves as a place holder. # # Currently there is no difference between 'nt' and NT_DEBUG, since now # both of them leave the terminal open after termination of debuggee to # accommodate scenarios of scripts with child processes. # osSpawn = { 'nt': 'start "rpdb2 - Version ' + get_version() + ' - Debuggee Console" cmd.exe /K ""%(exec)s" %(options)s"', NT_DEBUG: 'start "rpdb2 - Version ' + get_version() + ' - Debuggee Console" cmd.exe /K ""%(exec)s" %(options)s"', POSIX: "%(term)s -e %(shell)s -c '%(exec)s %(options)s; %(shell)s' &", 'Terminal': "Terminal --disable-server -x %(shell)s -c '%(exec)s %(options)s; %(shell)s' &", GNOME_DEFAULT_TERM: "gnome-terminal --disable-factory -x %(shell)s -c '%(exec)s %(options)s; %(shell)s' &", MAC: '%(exec)s %(options)s', DARWIN: '%(exec)s %(options)s', SCREEN: 'screen -t debuggee_console %(exec)s %(options)s' } RPDBTERM = 'RPDBTERM' COLORTERM = 'COLORTERM' TERM = 'TERM' KDE_PREFIX = 'KDE' GNOME_PREFIX = 'GNOME' KDE_DEFAULT_TERM_QUERY = "kreadconfig --file kdeglobals --group General --key TerminalApplication --default konsole" XTERM = 'xterm' RXVT = 'rxvt' RPDB_SETTINGS_FOLDER = '.rpdb2_settings' RPDB_PWD_FOLDER = os.path.join(RPDB_SETTINGS_FOLDER, 'passwords') RPDB_BPL_FOLDER = os.path.join(RPDB_SETTINGS_FOLDER, 'breakpoints') RPDB_BPL_FOLDER_NT = 'rpdb2_breakpoints' MAX_BPL_FILES = 100 EMBEDDED_SYNC_THRESHOLD = 1.0 EMBEDDED_SYNC_TIMEOUT = 5.0 HEARTBEAT_TIMEOUT = 16 IDLE_MAX_RATE = 2.0 PING_TIMEOUT = 4.0 LOCAL_TIMEOUT = 1.0 COMMUNICATION_RETRIES = 5 WAIT_FOR_BREAK_TIMEOUT = 3.0 SHUTDOWN_TIMEOUT = 4.0 STARTUP_TIMEOUT = 3.0 STARTUP_RETRIES = 3 LOOPBACK = '127.0.0.1' LOCALHOST = 'localhost' SERVER_PORT_RANGE_START = 51000 SERVER_PORT_RANGE_LENGTH = 24 SOURCE_EVENT_CALL = 'C' SOURCE_EVENT_LINE = 'L' SOURCE_EVENT_RETURN = 'R' SOURCE_EVENT_EXCEPTION = 'E' SOURCE_STATE_UNBROKEN = '*' SOURCE_BP_ENABLED = 'B' SOURCE_BP_DISABLED = 'D' SYMBOL_MARKER = '>' SYMBOL_ALL = '*' SOURCE_MORE = '+' SOURCE_LESS = '-' SOURCE_ENTIRE_FILE = '^' CONSOLE_PRINTER = '*** ' CONSOLE_WRAP_INDEX = 78 CONSOLE_PROMPT = '\n> ' CONSOLE_PROMPT_ANALYZE = '\nAnalayze> ' CONSOLE_INTRO = ("""RPDB - The Remote Python Debugger, version %s, Copyright (C) 2005-2008 Nir Aides. Type "help", "copyright", "license", "credits" for more information.""" % (RPDB_VERSION)) PRINT_NOTICE_PROMPT = "Hit Return for more, or q (and Return) to quit:" PRINT_NOTICE_LINES_PER_SECTION = 20 STR_NO_THREADS = "Operation failed since no traced threads were found." STR_STARTUP_NOTICE = "Attaching to debuggee..." STR_SPAWN_UNSUPPORTED = "The debugger does not know how to open a new console on this system. You can start the debuggee manually with the -d flag on a separate console and then use the 'attach' command to attach to it." STR_SPAWN_UNSUPPORTED_SCREEN_SUFFIX = """Alternatively, you can use the screen utility and invoke rpdb2 in screen mode with the -s command-line flag as follows: screen rpdb2 -s some-script.py script-arg1 script-arg2...""" STR_AUTOMATIC_LAUNCH_UNKNOWN = STR_SPAWN_UNSUPPORTED STR_STARTUP_SPAWN_NOTICE = "Starting debuggee..." STR_KILL_NOTICE = "Stopping debuggee..." STR_STARTUP_FAILURE = "Debuggee failed to start in a timely manner." STR_OUTPUT_WARNING = "Textual output will be done at the debuggee." STR_OUTPUT_WARNING_ASYNC = "The operation will continue to run in the background." STR_ANALYZE_GLOBALS_WARNING = "In analyze mode the globals and locals dictionaries are read only." STR_BREAKPOINTS_LOADED = "Breakpoints were loaded." STR_BREAKPOINTS_SAVED = "Breakpoints were saved." STR_BREAKPOINTS_SAVE_PROBLEM = "A problem occurred while saving the breakpoints." STR_BREAKPOINTS_LOAD_PROBLEM = "A problem occurred while loading the breakpoints." STR_BREAKPOINTS_NOT_SAVED = "Breakpoints were not saved." STR_BREAKPOINTS_NOT_LOADED = "Breakpoints were not loaded." STR_BREAKPOINTS_FILE_NOT_FOUND = "Breakpoints file was not found." STR_BREAKPOINTS_NOT_FOUND = "No Breakpoints were found." STR_BAD_FILENAME = "Bad File Name." STR_SOME_BREAKPOINTS_NOT_LOADED = "Some breakpoints were not loaded, because of an error." STR_BAD_EXPRESSION = "Bad expression '%s'." STR_FILE_NOT_FOUND = "File '%s' not found." STR_DISPLAY_ERROR = """If the X server (Windowing system) is not started you need to use rpdb2 with the screen utility and invoke rpdb2 in screen mode with the -s command-line flag as follows: screen rpdb2 -s some-script.py script-arg1 script-arg2...""" STR_EXCEPTION_NOT_FOUND = "No exception was found." STR_SCOPE_NOT_FOUND = "Scope '%s' not found." STR_NO_SUCH_BREAKPOINT = "Breakpoint not found." STR_THREAD_NOT_FOUND = "Thread was not found." STR_NO_THREADS_FOUND = "No threads were found." STR_THREAD_NOT_BROKEN = "Thread is running." STR_THREAD_FOCUS_SET = "Focus was set to chosen thread." STR_ILEGAL_ANALYZE_MODE_ARG = "Argument is not allowed in analyze mode. Type 'help analyze' for more info." STR_ILEGAL_ANALYZE_MODE_CMD = "Command is not allowed in analyze mode. Type 'help analyze' for more info." STR_ANALYZE_MODE_TOGGLE = "Analyze mode was set to: %s." STR_BAD_ARGUMENT = "Bad Argument." STR_PSYCO_WARNING = "The psyco module was detected. The debugger is incompatible with the psyco module and will not function correctly as long as the psyco module is imported and used." STR_CONFLICTING_MODULES = "The modules: %s, which are incompatible with the debugger were detected and can possibly cause the debugger to fail." STR_SIGNAL_INTERCEPT = "The signal %s(%d) was intercepted inside debugger tracing logic. It will be held pending until the debugger continues. Any exceptions raised by the handler will be ignored!" STR_SIGNAL_EXCEPTION = "Exception %s raised by handler of signal %s(%d) inside debugger tracing logic was ignored!" STR_DEBUGGEE_TERMINATED = "Debuggee has terminated." STR_DEBUGGEE_NOT_BROKEN = "Debuggee has to be waiting at break point to complete this command." STR_DEBUGGER_HAS_BROKEN = "Debuggee is waiting at break point for further commands." STR_ALREADY_ATTACHED = "Already attached. Detach from debuggee and try again." STR_NOT_ATTACHED = "Not attached to any script. Attach to a script and try again." STR_COMMUNICATION_FAILURE = "Failed to communicate with debugged script." STR_ERROR_OTHER = "Command returned the following error:\n%(type)s, %(value)s.\nPlease check stderr for stack trace and report to support." STR_BAD_MBCS_PATH = "The debugger can not launch the script since the path to the Python executable or the debugger scripts can not be encoded into the default system code page. Please check the settings of 'Language for non-Unicode programs' in the Advanced tab of the Windows Regional and Language Options dialog." STR_LOST_CONNECTION = "Lost connection to debuggee." STR_FIREWALL_BLOCK = "A firewall is blocking the local communication chanel (socket) that is required between the debugger and the debugged script. Please make sure that the firewall allows that communication." STR_BAD_VERSION = "A debuggee was found with incompatible debugger version %(value)s." STR_BAD_VERSION2 = "While attempting to find the specified debuggee at least one debuggee was found that uses incompatible version of RPDB2." STR_UNEXPECTED_DATA = "Unexpected data received." STR_ACCESS_DENIED = "While attempting to find debuggee, at least one debuggee denied connection because of mismatched passwords. Please verify your password." STR_ACCESS_DENIED2 = "Communication is denied because of un-matching passwords." STR_ENCRYPTION_EXPECTED = "While attempting to find debuggee, at least one debuggee denied connection since it accepts encrypted connections only." STR_ENCRYPTION_EXPECTED2 = "Debuggee will only talk over an encrypted channel." STR_DECRYPTION_FAILURE = "Bad packet was received by the debuggee." STR_DEBUGGEE_NO_ENCRYPTION = "Debuggee does not support encrypted mode. Either install the python-crypto package on the debuggee machine or allow unencrypted connections." STR_RANDOM_PASSWORD = "Password has been set to a random password." STR_PASSWORD_INPUT = "Please type a password:" STR_PASSWORD_CONFIRM = "Password has been set." STR_PASSWORD_NOT_SUPPORTED = "The --pwd flag is only supported on NT systems." STR_PASSWORD_MUST_BE_SET = "A password should be set to secure debugger client-server communication." STR_BAD_DATA = "Bad data received from debuggee." STR_BAD_FILE_DATA = "Bad data received from file." STR_ATTACH_FAILED = "Failed to attach" STR_ATTACH_FAILED_NAME = "Failed to attach to '%s'." STR_ATTACH_CRYPTO_MODE = "Debug Channel is%s encrypted." STR_ATTACH_CRYPTO_MODE_NOT = "NOT" STR_ATTACH_SUCCEEDED = "Successfully attached to '%s'." STR_ATTEMPTING_TO_STOP = "Requesting script to stop." STR_ATTEMPTING_TO_DETACH = "Detaching from script..." STR_DETACH_SUCCEEDED = "Detached from script." STR_DEBUGGEE_UNKNOWN = "Failed to find script." STR_MULTIPLE_DEBUGGEES = "WARNING: There is more than one debuggee '%s'." MSG_ERROR_HOST_TEXT = """The debugger was not able to set the host to '%s'. The following error was returned: %s""" STR_SOURCE_NOT_FOUND = "Failed to get source from debuggee." STR_SCRIPTS_CONNECTING = "Connecting to '%s'..." STR_SCRIPTS_NO_SCRIPTS = "No scripts to debug on '%s'" STR_SCRIPTS_TO_DEBUG = """Scripts to debug on '%s': pid name --------------------------""" STR_STACK_TRACE = """Stack trace for thread %d: Frame File Name Line Function ------------------------------------------------------------------------------""" STR_SOURCE_LINES = """Source lines for thread %d from file '%s': """ STR_ACTIVE_THREADS = """List of active threads known to the debugger: No Tid Name State -----------------------------------------------""" STR_BREAKPOINTS_LIST = """List of breakpoints: Id State Line Filename-Scope-Condition-Encoding ------------------------------------------------------------------------------""" STR_BREAKPOINTS_TEMPLATE = """ %2d %-8s %5d %s %s %s %s""" STR_ENCRYPTION_SUPPORT_ERROR = "Encryption is not supported since the python-crypto package was not found. Either install the python-crypto package or allow unencrypted connections." STR_PASSWORD_NOT_SET = 'Password is not set.' STR_PASSWORD_SET = 'Password is set to: "%s"' STR_PASSWORD_BAD = 'The password should begin with a letter and continue with any combination of digits, letters or underscores (\'_\'). Only English characters are accepted for letters.' STR_ENCRYPT_MODE = 'Force encryption mode: %s' STR_REMOTE_MODE = 'Allow remote machines mode: %s' STR_ENCODING_MODE = 'Encoding is set to: %s' STR_ENCODING_MODE_SET = 'Encoding was set to: %s' STR_ENCODING_BAD = 'The specified encoding was not recognized by the debugger.' STR_ENVIRONMENT = 'The current environment mapping is:' STR_ENVIRONMENT_EMPTY = 'The current environment mapping is not set.' STR_SYNCHRONICITY_BAD = "Can not process command when thread is running unless synchronicity mode is turned on. Type 'help synchro' at the command prompt for more information." STR_SYNCHRONICITY_MODE = 'The synchronicity mode is set to: %s' STR_TRAP_MODE = 'Trap unhandled exceptions mode is set to: %s' STR_TRAP_MODE_SET = "Trap unhandled exceptions mode was set to: %s." STR_FORK_MODE = "Fork mode is set to: %s, %s." STR_FORK_MODE_SET = "Fork mode was set to: %s, %s." STR_LOCAL_NAMESPACE_WARNING = 'Debugger modifications to the original bindings of the local namespace of this frame will be committed before the execution of the next statement of the frame. Any code using these variables executed before that point will see the original values.' STR_WARNING = 'Warning: %s' STR_MAX_NAMESPACE_WARNING_TITLE = 'Namespace Warning' STR_MAX_NAMESPACE_WARNING_TYPE = '*** WARNING ***' STR_MAX_NAMESPACE_WARNING_MSG = 'Number of items exceeds capacity of namespace browser.' STR_MAX_EVALUATE_LENGTH_WARNING = 'Output length exeeds maximum capacity.' FORK_CHILD = 'child' FORK_PARENT = 'parent' FORK_MANUAL = 'manual' FORK_AUTO = 'auto' ENCRYPTION_ENABLED = 'encrypted' ENCRYPTION_DISABLED = 'plain-text' STATE_ENABLED = 'enabled' STATE_DISABLED = 'disabled' BREAKPOINTS_FILE_EXT = '.bpl' PYTHON_FILE_EXTENSION = '.py' PYTHONW_FILE_EXTENSION = '.pyw' PYTHONW_SO_EXTENSION = '.so' PYTHON_EXT_LIST = ['.py', '.pyw', '.pyc', '.pyd', '.pyo', '.so'] MODULE_SCOPE = '?' MODULE_SCOPE2 = '' BLENDER_SOURCE_NOT_AVAILABLE = as_unicode('Blender script source code is not available.') SOURCE_NOT_AVAILABLE = as_unicode('Source code is not available.') SCOPE_SEP = '.' BP_FILENAME_SEP = ':' BP_EVAL_SEP = ',' DEBUGGER_FILENAME = 'rpdb2.py' THREADING_FILENAME = 'threading.py' STR_STATE_BROKEN = 'waiting at break point' STATE_BROKEN = 'broken' STATE_RUNNING = 'running' STATE_ANALYZE = 'analyze' STATE_DETACHED = 'detached' STATE_DETACHING = 'detaching' STATE_SPAWNING = 'spawning' STATE_ATTACHING = 'attaching' DEFAULT_NUMBER_OF_LINES = 20 DICT_KEY_TID = 'tid' DICT_KEY_STACK = 'stack' DICT_KEY_CODE_LIST = 'code_list' DICT_KEY_CURRENT_TID = 'current tid' DICT_KEY_BROKEN = 'broken' DICT_KEY_BREAKPOINTS = 'breakpoints' DICT_KEY_LINES = 'lines' DICT_KEY_FILENAME = 'filename' DICT_KEY_FIRST_LINENO = 'first_lineno' DICT_KEY_FRAME_LINENO = 'frame_lineno' DICT_KEY_EVENT = 'event' DICT_KEY_EXPR = 'expr' DICT_KEY_NAME = 'name' DICT_KEY_REPR = 'repr' DICT_KEY_IS_VALID = 'fvalid' DICT_KEY_TYPE = 'type' DICT_KEY_SUBNODES = 'subnodes' DICT_KEY_N_SUBNODES = 'n_subnodes' DICT_KEY_ERROR = 'error' RPDB_EXEC_INFO = as_unicode('rpdb_exception_info') MODE_ON = 'ON' MODE_OFF = 'OFF' ENCODING_UTF8_PREFIX_1 = '\xef\xbb\xbf' ENCODING_SOURCE = '# -*- coding: %s -*-\n' ENCODING_AUTO = as_unicode('auto') ENCODING_RAW = as_unicode('raw') ENCODING_RAW_I = as_unicode('__raw') MAX_EVALUATE_LENGTH = 256 * 1024 MAX_NAMESPACE_ITEMS = 1024 MAX_SORTABLE_LENGTH = 256 * 1024 REPR_ID_LENGTH = 4096 MAX_NAMESPACE_WARNING = { DICT_KEY_EXPR: STR_MAX_NAMESPACE_WARNING_TITLE, DICT_KEY_NAME: STR_MAX_NAMESPACE_WARNING_TITLE, DICT_KEY_REPR: STR_MAX_NAMESPACE_WARNING_MSG, DICT_KEY_IS_VALID: False, DICT_KEY_TYPE: STR_MAX_NAMESPACE_WARNING_TYPE, DICT_KEY_N_SUBNODES: 0 } MAX_EVENT_LIST_LENGTH = 1000 EVENT_EXCLUDE = 'exclude' EVENT_INCLUDE = 'include' INDEX_TABLE_SIZE = 100 DISPACHER_METHOD = 'dispatcher_method' BASIC_TYPES_LIST = ['bytearray', 'bytes', 'str', 'str8', 'unicode', 'int', 'long', 'float', 'bool', 'NoneType'] CONFLICTING_MODULES = ['psyco', 'pdb', 'bdb', 'doctest'] XML_DATA = """ dispatcher_method %s """ % RPDB_COMPATIBILITY_VERSION N_WORK_QUEUE_THREADS = 8 DEFAULT_PATH_SUFFIX_LENGTH = 55 ELLIPSIS_UNICODE = as_unicode('...') ELLIPSIS_BYTES = as_bytes('...') ERROR_NO_ATTRIBUTE = 'Error: No attribute.' g_server_lock = threading.RLock() g_server = None g_debugger = None g_fScreen = False g_fDefaultStd = True # # In debug mode errors and tracebacks are printed to stdout # g_fDebug = False # # Lock for the traceback module to prevent it from interleaving # output from different threads. # g_traceback_lock = threading.RLock() g_source_provider_aux = None g_lines_cache = {} g_initial_cwd = [] g_error_mapping = { socket.error: STR_COMMUNICATION_FAILURE, CConnectionException: STR_LOST_CONNECTION, FirewallBlock: STR_FIREWALL_BLOCK, BadVersion: STR_BAD_VERSION, UnexpectedData: STR_UNEXPECTED_DATA, SpawnUnsupported: STR_SPAWN_UNSUPPORTED, UnknownServer: STR_DEBUGGEE_UNKNOWN, UnsetPassword: STR_PASSWORD_MUST_BE_SET, EncryptionNotSupported: STR_DEBUGGEE_NO_ENCRYPTION, EncryptionExpected: STR_ENCRYPTION_EXPECTED, DecryptionFailure: STR_DECRYPTION_FAILURE, AuthenticationBadData: STR_ACCESS_DENIED, AuthenticationFailure: STR_ACCESS_DENIED, BadMBCSPath: STR_BAD_MBCS_PATH, AlreadyAttached: STR_ALREADY_ATTACHED, NotAttached: STR_NOT_ATTACHED, DebuggerNotBroken: STR_DEBUGGEE_NOT_BROKEN, NoThreads: STR_NO_THREADS, NoExceptionFound: STR_EXCEPTION_NOT_FOUND, } # # These globals are related to handling the os.fork() os._exit() and exec # pattern. # g_forkpid = None g_forktid = None g_fignorefork = False g_exectid = None g_execpid = None g_fos_exit = False # # To hold a reference to __main__ to prevent its release if an unhandled # exception is raised. # g_module_main = None g_found_conflicting_modules = [] g_fignore_atexit = False g_ignore_broken_pipe = 0 # # Unicode version of path names that do not encode well witn the windows # 'mbcs' encoding. This dict is used to work with such path names on # windows. # g_found_unicode_files = {} g_frames_path = {} g_signal_handlers = {} g_signals_pending = [] #g_profile = None g_fFirewallTest = True g_safe_base64_to = string.maketrans(as_bytes('/+='), as_bytes('_-#')) g_safe_base64_from = string.maketrans(as_bytes('_-#'), as_bytes('/+=')) g_alertable_waiters = {} g_builtins_module = sys.modules.get('__builtin__', sys.modules.get('builtins')) # # ---------------------------- General Utils ------------------------------ # def job_wrapper(event, foo, *args, **kwargs): try: #print_debug('Thread %d doing job %s' % (thread.get_ident(), foo.__name__)) foo(*args, **kwargs) finally: event.set() def send_job(tid, timeout, foo, *args, **kwargs): # # Attempt to send job to thread tid. # Will throw KeyError if thread tid is not available for jobs. # (lock, jobs) = g_alertable_waiters[tid] event = threading.Event() f = lambda: job_wrapper(event, foo, *args, **kwargs) jobs.append(f) try: lock.acquire() lock.notifyAll() finally: lock.release() safe_wait(event, timeout) def alertable_wait(lock, timeout = None): jobs = [] tid = thread.get_ident() g_alertable_waiters[tid] = (lock, jobs) try: safe_wait(lock, timeout) while len(jobs) != 0: job = jobs.pop(0) try: job() except: pass if len(jobs) == 0: time.sleep(0.1) finally: del g_alertable_waiters[tid] def safe_wait(lock, timeout = None): # # workaround windows bug where signal handlers might raise exceptions # even if they return normally. # while True: try: t0 = time.time() return lock.wait(timeout) except: if timeout == None: continue timeout -= (time.time() - t0) if timeout <= 0: return # # The following code is related to the ability of the debugger # to work both on Python 2.5 and 3.0. # class _stub_type: pass def _rpdb2_bytes(s, e): return s.encode(e) if not hasattr(g_builtins_module, 'unicode'): unicode = _stub_type if not hasattr(g_builtins_module, 'long'): long = _stub_type if not hasattr(g_builtins_module, 'str8'): str8 = _stub_type if not hasattr(g_builtins_module, 'bytearray'): bytearray = _stub_type if not hasattr(g_builtins_module, 'bytes'): bytes = _stub_type # # Pickle on Python 2.5 should know how to handle byte strings # that arrive from Python 3.0 over sockets. # g_builtins_module.bytes = _rpdb2_bytes if is_py3k(): class sets: Set = _stub_type BaseSet = _stub_type ImmutableSet = _stub_type if sys.version_info[:2] <= (2, 3): set = sets.Set def _raw_input(s): if is_py3k(): return input(s) i = raw_input(s) i = as_unicode(i, detect_encoding(sys.stdin), fstrict = True) return i def _print(s, f = sys.stdout, feol = True): s = as_unicode(s) encoding = detect_encoding(f) s = as_bytes(s, encoding, fstrict = False) s = as_string(s, encoding) if feol: f.write(s + '\n') else: f.write(s) def detect_encoding(file): try: encoding = file.encoding if encoding == None: return detect_locale() except: return detect_locale() try: codecs.lookup(encoding) return encoding except: pass if encoding.lower().startswith('utf_8'): return 'utf-8' return 'ascii' def detect_locale(): encoding = locale.getdefaultlocale()[1] if encoding == None: return 'ascii' try: codecs.lookup(encoding) return encoding except: pass if encoding.lower().startswith('utf_8'): return 'utf-8' return 'ascii' def class_name(c): s = safe_str(c) if "'" in s: s = s.split("'")[1] assert(s.startswith(__name__ + '.')) return s def clip_filename(path, n = DEFAULT_PATH_SUFFIX_LENGTH): suffix = calc_suffix(path, n) if not suffix.startswith('...'): return suffix index = suffix.find(os.sep) if index == -1: return suffix clip = '...' + suffix[index:] return clip def safe_str(x): try: return str(x) except: return 'N/A' def safe_repr(x): try: return repr(x) except: return 'N/A' def parse_type(t): rt = safe_repr(t) if not "'" in rt: return rt st = rt.split("'")[1] return st def repr_list(pattern, l, length, encoding, is_valid): length = max(0, length - len(pattern) + 2) s = '' index = 0 try: for i in l: # # Remove any trace of session password from data structures that # go over the network. # if type(i) == str and i in ['_rpdb2_args', '_rpdb2_pwd', 'm_rpdb2_pwd']: continue s += repr_ltd(i, length - len(s), encoding, is_valid) index += 1 if index < len(l) and len(s) > length: is_valid[0] = False if not s.endswith('...'): s += '...' break if index < len(l) or (index == 1 and pattern[0] == '('): s += ', ' except AttributeError: is_valid[0] = False return as_unicode(pattern % s) def repr_dict(pattern, d, length, encoding, is_valid): length = max(0, length - len(pattern) + 2) s = '' index = 0 try: for k in d: # # Remove any trace of session password from data structures that # go over the network. # if type(k) == str and k in ['_rpdb2_args', '_rpdb2_pwd', 'm_rpdb2_pwd']: continue v = d[k] s += repr_ltd(k, length - len(s), encoding, is_valid) if len(s) > length: is_valid[0] = False if not s.endswith('...'): s += '...' break s += ': ' + repr_ltd(v, length - len(s), encoding, is_valid) index += 1 if index < len(d) and len(s) > length: is_valid[0] = False if not s.endswith('...'): s += '...' break if index < len(d): s += ', ' except AttributeError: is_valid[0] = False return as_unicode(pattern % s) def repr_bytearray(s, length, encoding, is_valid): try: s = s.decode(encoding) r = repr_unicode(s, length, is_valid) return 'bytearray(b' + r[1:] + ')' except: # # If a string is not encoded as utf-8 its repr() will be done with # the regular repr() function. # return repr_str_raw(s, length, is_valid) def repr_bytes(s, length, encoding, is_valid): try: s = s.decode(encoding) r = repr_unicode(s, length, is_valid) return 'b' + r[1:] except: # # If a string is not encoded as utf-8 its repr() will be done with # the regular repr() function. # return repr_str_raw(s, length, is_valid) def repr_str8(s, length, encoding, is_valid): try: s = s.decode(encoding) r = repr_unicode(s, length, is_valid) return 's' + r[1:] except: # # If a string is not encoded as utf-8 its repr() will be done with # the regular repr() function. # return repr_str_raw(s, length, is_valid) def repr_str(s, length, encoding, is_valid): try: s = as_unicode(s, encoding, fstrict = True) r = repr_unicode(s, length, is_valid) return r[1:] except: # # If a string is not encoded as utf-8 its repr() will be done with # the regular repr() function. # return repr_str_raw(s, length, is_valid) def repr_unicode(s, length, is_valid): index = [2, 1][is_py3k()] rs = '' for c in s: if len(rs) > length: is_valid[0] = False rs += '...' break if ord(c) < 128: rs += repr(c)[index: -1] else: rs += c if not "'" in rs: return as_unicode("u'%s'" % rs) if not '"' in rs: return as_unicode('u"%s"' % rs) return as_unicode("u'%s'" % rs.replace("'", "\\'")) def repr_str_raw(s, length, is_valid): if is_unicode(s): eli = ELLIPSIS_UNICODE else: eli = ELLIPSIS_BYTES if len(s) > length: is_valid[0] = False s = s[: length] + eli return as_unicode(repr(s)) def repr_base(v, length, is_valid): r = repr(v) if len(r) > length: is_valid[0] = False r = r[: length] + '...' return as_unicode(r) def repr_ltd(x, length, encoding, is_valid = [True]): try: length = max(0, length) try: if isinstance(x, frozenset): return repr_list('frozenset([%s])', x, length, encoding, is_valid) if isinstance(x, set): return repr_list('set([%s])', x, length, encoding, is_valid) except NameError: pass if isinstance(x, sets.Set): return repr_list('sets.Set([%s])', x, length, encoding, is_valid) if isinstance(x, sets.ImmutableSet): return repr_list('sets.ImmutableSet([%s])', x, length, encoding, is_valid) if isinstance(x, list): return repr_list('[%s]', x, length, encoding, is_valid) if isinstance(x, tuple): return repr_list('(%s)', x, length, encoding, is_valid) if isinstance(x, dict): return repr_dict('{%s}', x, length, encoding, is_valid) if encoding == ENCODING_RAW_I and type(x) in [str, unicode, bytearray, bytes, str8]: return repr_str_raw(x, length, is_valid) if type(x) == unicode: return repr_unicode(x, length, is_valid) if type(x) == bytearray: return repr_bytearray(x, length, encoding, is_valid) if type(x) == bytes: return repr_bytes(x, length, encoding, is_valid) if type(x) == str8: return repr_str8(x, length, encoding, is_valid) if type(x) == str: return repr_str(x, length, encoding, is_valid) if type(x) in [bool, int, float, long, type(None)]: return repr_base(x, length, is_valid) is_valid[0] = False y = safe_repr(x)[: length] if len(y) == length: y += '...' if encoding == ENCODING_RAW_I: encoding = 'utf-8' try: y = as_unicode(y, encoding, fstrict = True) return y except: pass encoding = sys.getfilesystemencoding() y = as_unicode(y, encoding) return y except: print_debug_exception() return as_unicode('N/A') def print_debug(_str): if not g_fDebug: return t = time.time() l = time.localtime(t) s = time.strftime('%H:%M:%S', l) + '.%03d' % ((t - int(t)) * 1000) f = sys._getframe(1) filename = os.path.basename(f.f_code.co_filename) lineno = f.f_lineno name = f.f_code.co_name str = '%s %s:%d in %s: %s' % (s, filename, lineno, name, _str) _print(str, sys.__stderr__) def print_debug_exception(fForce = False): """ Print exceptions to stdout when in debug mode. """ if not g_fDebug and not fForce: return (t, v, tb) = sys.exc_info() print_exception(t, v, tb, fForce) class CFileWrapper: def __init__(self, f): self.m_f = f def write(self, s): _print(s, self.m_f, feol = False) def __getattr__(self, name): return self.m_f.__getattr__(name) def print_exception(t, v, tb, fForce = False): """ Print exceptions to stderr when in debug mode. """ if not g_fDebug and not fForce: return try: g_traceback_lock.acquire() traceback.print_exception(t, v, tb, file = CFileWrapper(sys.stderr)) finally: g_traceback_lock.release() def print_stack(): """ Print exceptions to stdout when in debug mode. """ if g_fDebug == True: try: g_traceback_lock.acquire() traceback.print_stack(file = CFileWrapper(sys.stderr)) finally: g_traceback_lock.release() # # myisfile() is similar to os.path.isfile() but also works with # Python eggs. # def myisfile(path): try: mygetfile(path, False) return True except: return False # # Read a file even if inside a Python egg. # def mygetfile(path, fread_file = True): if os.path.isfile(path): if not fread_file: return f = open(path, 'r') data = f.read() f.close() return data d = os.path.dirname(path) while True: if os.path.exists(d): break _d = os.path.dirname(d) if _d in [d, '']: raise IOError d = _d if not zipfile.is_zipfile(d): raise IOError z = zipimport.zipimporter(d) try: data = z.get_data(path[len(d) + 1:]) return data except: raise IOError def split_command_line_path_filename_args(command_line): """ Split command line to a 3 elements tuple (path, filename, args) """ command_line = command_line.strip() if len(command_line) == 0: return ('', '', '') if myisfile(command_line): (_path, _filename) = split_path(command_line) return (_path, _filename, '') if command_line[0] in ['"', "'"]: _command_line = command_line[1:] i = _command_line.find(command_line[0]) if i == -1: (_path, filename) = split_path(_command_line) return (_path, filename, '') else: (_path, filename) = split_path(_command_line[: i]) args = _command_line[i + 1:].strip() return (_path, filename, args) else: i = command_line.find(' ') if i == -1: (_path, filename) = split_path(command_line) return (_path, filename, '') else: args = command_line[i + 1:].strip() (_path, filename) = split_path(command_line[: i]) return (_path, filename, args) def split_path(path): (_path, filename) = os.path.split(path) # # Make sure path separator (e.g. '/') ends the splitted path if it was in # the original path. # if (_path[-1:] not in [os.path.sep, os.path.altsep]) and \ (path[len(_path): len(_path) + 1] in [os.path.sep, os.path.altsep]): _path = _path + path[len(_path): len(_path) + 1] return (_path, filename) def my_os_path_join(dirname, basename): if is_py3k() or (type(dirname) == str and type(basename) == str): return os.path.join(dirname, basename) encoding = sys.getfilesystemencoding() if type(dirname) == str: dirname = dirname.decode(encoding) if type(basename) == str: basename = basename.decode(encoding) return os.path.join(dirname, basename) def calc_frame_path(frame): globals_filename = frame.f_globals.get('__file__', None) filename = frame.f_code.co_filename if filename.startswith('<'): if globals_filename == None: return filename else: filename = CalcScriptName(os.path.basename(globals_filename)) if filename in g_frames_path: return g_frames_path[filename] if globals_filename != None: dirname = os.path.dirname(globals_filename) basename = os.path.basename(filename) path = my_os_path_join(dirname, basename) if os.path.isabs(path): abspath = my_abspath(path) lowered = winlower(abspath) g_frames_path[filename] = lowered return lowered try: abspath = FindFile(path, fModules = True) lowered = winlower(abspath) g_frames_path[filename] = lowered return lowered except IOError: pass if os.path.isabs(filename): abspath = my_abspath(filename) lowered = winlower(abspath) g_frames_path[filename] = lowered return lowered try: abspath = FindFile(filename, fModules = True) lowered = winlower(abspath) g_frames_path[filename] = lowered return lowered except IOError: lowered = winlower(filename) return lowered def my_abspath(path): """ We need our own little version of os.path.abspath since the original code imports modules in the 'nt' code path which can cause our debugger to deadlock in unexpected locations. """ if path[:1] == '<': # # 'path' may also be '' in which case it is left untouched. # return path if os.name == 'nt': return my_abspath1(path) return os.path.abspath(path) # # MOD # def my_abspath1(path): """ Modification of ntpath.abspath() that avoids doing an import. """ if path: try: path = _getfullpathname(path) except WindowsError: pass else: try: path = os.getcwd() except UnicodeDecodeError: # # This exception can be raised in py3k (alpha) on nt. # path = os.getcwdu() np = os.path.normpath(path) if (len(np) >= 2) and (np[1:2] == ':'): np = np[:1].upper() + np[1:] return np def IsPythonSourceFile(path): if path.endswith(PYTHON_FILE_EXTENSION): return True if path.endswith(PYTHONW_FILE_EXTENSION): return True path = g_found_unicode_files.get(path, path) for lineno in range(1, 10): line = get_source_line(path, lineno) if line.startswith('#!') and 'python' in line: return True if is_py3k(): # # py3k does not have compiler.parseFile, so return # True anyway... # return True try: compiler.parseFile(path) return True except: return False def CalcModuleName(filename): _basename = os.path.basename(filename) (modulename, ext) = os.path.splitext(_basename) if ext in PYTHON_EXT_LIST: return modulename return _basename def CalcScriptName(filename, fAllowAnyExt = True): if filename.endswith(PYTHON_FILE_EXTENSION): return filename if filename.endswith(PYTHONW_FILE_EXTENSION): return filename if filename.endswith(PYTHONW_SO_EXTENSION): scriptname = filename[:-3] + PYTHON_FILE_EXTENSION return scriptname if filename[:-1].endswith(PYTHON_FILE_EXTENSION): scriptname = filename[:-1] return scriptname if fAllowAnyExt: return filename scriptname = filename + PYTHON_FILE_EXTENSION return scriptname def FindModuleDir(module_name): if module_name == '': raise IOError dot_index = module_name.rfind('.') if dot_index != -1: parent = module_name[: dot_index] child = module_name[dot_index + 1:] else: parent = '' child = module_name m = sys.modules[module_name] if not hasattr(m, '__file__') or m.__file__ == None: parent_dir = FindModuleDir(parent) module_dir = my_os_path_join(parent_dir, winlower(child)) return module_dir if not os.path.isabs(m.__file__): parent_dir = FindModuleDir(parent) module_dir = my_os_path_join(parent_dir, winlower(child)) return module_dir (root, ext) = os.path.splitext(m.__file__) if root.endswith('__init__'): root = os.path.dirname(root) abspath = my_abspath(root) lowered = winlower(abspath) return lowered def FindFileAsModule(filename): lowered = winlower(filename) (root, ext) = os.path.splitext(lowered) root_dotted = root.replace('\\', '.').replace('/', '.').replace(':', '.') match_list = [] for (module_name, m) in list(sys.modules.items()): lowered_module_name = winlower(module_name) if (root_dotted + '.').startswith(lowered_module_name + '.'): match_list.append((len(module_name), module_name)) if lowered_module_name == root_dotted: break match_list.sort() match_list.reverse() for (matched_len, matched_module) in match_list: try: module_dir = FindModuleDir(matched_module) except IOError: continue suffix = root[matched_len:] if suffix == '': path = module_dir + ext else: path = my_os_path_join(module_dir, suffix.strip('\\')) + ext scriptname = CalcScriptName(path, fAllowAnyExt = False) if myisfile(scriptname): return scriptname # # Check .pyw files # scriptname += 'w' if scriptname.endswith(PYTHONW_FILE_EXTENSION) and myisfile(scriptname): return scriptname raise IOError def FindFile( filename, sources_paths = [], fModules = False, fAllowAnyExt = True ): """ FindFile looks for the full path of a script in a rather non-strict and human like behavior. ENCODING: filename should be either Unicode or encoded with sys.getfilesystemencoding()! Returned value is encoded with sys.getfilesystemencoding(). It will always look for .py or .pyw files even if a .pyc or no extension is given. 1. It will check against loaded modules if asked. 1. full path (if exists). 2. sources_paths. 2. current path. 3. PYTHONPATH 4. PATH """ if filename in g_found_unicode_files: return filename if filename.startswith('<'): raise IOError filename = filename.strip('\'"') filename = os.path.expanduser(filename) if fModules and not (os.path.isabs(filename) or filename.startswith('.')): try: return winlower(FindFileAsModule(filename)) except IOError: pass if fAllowAnyExt: try: abspath = FindFile( filename, sources_paths, fModules = False, fAllowAnyExt = False ) return abspath except IOError: pass if os.path.isabs(filename) or filename.startswith('.'): try: scriptname = None abspath = my_abspath(filename) lowered = winlower(abspath) scriptname = CalcScriptName(lowered, fAllowAnyExt) if myisfile(scriptname): return scriptname # # Check .pyw files # scriptname += 'w' if scriptname.endswith(PYTHONW_FILE_EXTENSION) and myisfile(scriptname): return scriptname scriptname = None raise IOError finally: if not is_py3k() and is_unicode(scriptname): fse = sys.getfilesystemencoding() _l = as_string(scriptname, fse) if '?' in _l: g_found_unicode_files[_l] = scriptname return _l scriptname = CalcScriptName(filename, fAllowAnyExt) try: cwd = [os.getcwd(), os.getcwdu()] except UnicodeDecodeError: # # This exception can be raised in py3k (alpha) on nt. # cwd = [os.getcwdu()] env_path = os.environ['PATH'] paths = sources_paths + cwd + g_initial_cwd + sys.path + env_path.split(os.pathsep) try: lowered = None for p in paths: f = my_os_path_join(p, scriptname) abspath = my_abspath(f) lowered = winlower(abspath) if myisfile(lowered): return lowered # # Check .pyw files # lowered += 'w' if lowered.endswith(PYTHONW_FILE_EXTENSION) and myisfile(lowered): return lowered lowered = None raise IOError finally: if not is_py3k() and is_unicode(lowered): fse = sys.getfilesystemencoding() _l = as_string(lowered, fse) if '?' in _l: g_found_unicode_files[_l] = lowered return _l def IsFileInPath(filename): if filename == '': return False try: FindFile(filename) return True except IOError: return False def IsPrefixInEnviron(_str): for e in os.environ.keys(): if e.startswith(_str): return True return False def CalcTerminalCommand(): """ Calc the unix command to start a new terminal, for example: xterm """ if RPDBTERM in os.environ: term = os.environ[RPDBTERM] if IsFileInPath(term): return term if COLORTERM in os.environ: term = os.environ[COLORTERM] if IsFileInPath(term): return term if IsPrefixInEnviron(KDE_PREFIX): (s, term) = commands.getstatusoutput(KDE_DEFAULT_TERM_QUERY) if (s == 0) and IsFileInPath(term): return term elif IsPrefixInEnviron(GNOME_PREFIX): if IsFileInPath(GNOME_DEFAULT_TERM): return GNOME_DEFAULT_TERM if IsFileInPath(XTERM): return XTERM if IsFileInPath(RXVT): return RXVT raise SpawnUnsupported def CalcMacTerminalCommand(command): """ Calculate what to put in popen to start a given script. Starts a tiny Applescript that performs the script action. """ # # Quoting is a bit tricky; we do it step by step. # Make Applescript string: put backslashes before double quotes and # backslashes. # command = command.replace('\\', '\\\\').replace('"', '\\"') # # Make complete Applescript command. # command = 'tell application "Terminal" to do script "%s"' % command # # Make a shell single quoted string (put backslashed single quotes # outside string). # command = command.replace("'", "'\\''") # # Make complete shell command. # return "osascript -e '%s'" % command def winlower(path): """ return lowercase version of 'path' on NT systems. On NT filenames are case insensitive so lowercase filenames for comparison purposes on NT. """ if os.name == 'nt': return path.lower() return path def source_provider_blender(filename): """ Return source code of the file referred by filename. Support for debugging of Blender Python scripts. Blender scripts are not always saved on disk, and their source has to be queried directly from the Blender API. http://www.blender.org """ if not 'Blender.Text' in sys.modules: raise IOError if filename.startswith('<'): # # This specifies blender source whose source is not # available. # raise IOError(BLENDER_SOURCE_NOT_AVAILABLE) _filename = os.path.basename(filename) try: t = sys.modules['Blender.Text'].get(_filename) lines = t.asLines() return '\n'.join(lines) + '\n' except NameError: f = winlower(_filename) tlist = sys.modules['Blender.Text'].get() t = None for _t in tlist: n = winlower(_t.getName()) if n == f: t = _t break if t == None: # # filename does not specify a blender file. Raise IOError # so that search can continue on file system. # raise IOError lines = t.asLines() return '\n'.join(lines) + '\n' def source_provider_filesystem(filename): l = mygetfile(filename) if l[:3] == as_bytes(ENCODING_UTF8_PREFIX_1): l = l[3:] return l def source_provider(filename): source = None ffilesystem = False try: if g_source_provider_aux != None: source = g_source_provider_aux(filename) except IOError: v = sys.exc_info()[1] if SOURCE_NOT_AVAILABLE in v.args: raise try: if source == None: source = source_provider_blender(filename) except IOError: v = sys.exc_info()[1] if BLENDER_SOURCE_NOT_AVAILABLE in v.args: raise if source == None: source = source_provider_filesystem(filename) ffilesystem = True encoding = ParseEncoding(source) if not is_unicode(source): source = as_unicode(source, encoding) return source, encoding, ffilesystem def lines_cache(filename): filename = g_found_unicode_files.get(filename, filename) if filename in g_lines_cache: return g_lines_cache[filename] (source, encoding, ffilesystem) = source_provider(filename) source = source.replace(as_unicode('\r\n'), as_unicode('\n')) lines = source.split(as_unicode('\n')) g_lines_cache[filename] = (lines, encoding, ffilesystem) return (lines, encoding, ffilesystem) def get_source(filename): (lines, encoding, ffilesystem) = lines_cache(filename) source = as_unicode('\n').join(lines) return (source, encoding) def get_source_line(filename, lineno): (lines, encoding, ffilesystem) = lines_cache(filename) if lineno > len(lines): return as_unicode('') return lines[lineno - 1] + as_unicode('\n') def is_provider_filesystem(filename): try: (lines, encoding, ffilesystem) = lines_cache(filename) return ffilesystem except IOError: v = sys.exc_info()[1] return not (BLENDER_SOURCE_NOT_AVAILABLE in v.args or SOURCE_NOT_AVAILABLE in v.args) def get_file_encoding(filename): (lines, encoding, ffilesystem) = lines_cache(filename) return encoding def ParseLineEncoding(l): if l.startswith('# -*- coding: '): e = l[len('# -*- coding: '):].split()[0] return e if l.startswith('# vim:fileencoding='): e = l[len('# vim:fileencoding='):].strip() return e return None def ParseEncoding(txt): """ Parse document encoding according to: http://docs.python.org/ref/encodings.html """ eol = '\n' if not is_unicode(txt): eol = as_bytes('\n') l = txt.split(eol, 20)[:-1] for line in l: line = as_unicode(line) encoding = ParseLineEncoding(line) if encoding is not None: try: codecs.lookup(encoding) return encoding except: return 'utf-8' return 'utf-8' def _getpid(): try: return os.getpid() except: return -1 def calcURL(host, port): """ Form HTTP URL from 'host' and 'port' arguments. """ url = "http://" + str(host) + ":" + str(port) return url def GetSocketError(e): if (not isinstance(e.args, tuple)) or (len(e.args) == 0): return -1 return e.args[0] def ControlRate(t_last_call, max_rate): """ Limits rate at which this function is called by sleeping. Returns the time of invocation. """ p = 1.0 / max_rate t_current = time.time() dt = t_current - t_last_call if dt < p: time.sleep(p - dt) return t_current def generate_rid(): """ Return a 7 digits random id. """ rid = repr(random.randint(1000000, 9999999)) rid = as_unicode(rid) return rid def generate_random_char(_str): """ Return a random character from string argument. """ if _str == '': return '' i = random.randint(0, len(_str) - 1) return _str[i] def generate_random_password(): """ Generate an 8 characters long password. """ s = 'abdefghijmnqrt' + 'ABDEFGHJLMNQRTY' ds = '23456789_' + s _rpdb2_pwd = generate_random_char(s) for i in range(0, 7): _rpdb2_pwd += generate_random_char(ds) _rpdb2_pwd = as_unicode(_rpdb2_pwd) return _rpdb2_pwd def is_valid_pwd(_rpdb2_pwd): if _rpdb2_pwd in [None, '']: return False try: if not is_unicode(_rpdb2_pwd): _rpdb2_pwd = _rpdb2_pwd.decode('ascii') _rpdb2_pwd.encode('ascii') except: return False for c in _rpdb2_pwd: if c.isalnum(): continue if c == '_': continue return False return True def is_encryption_supported(): """ Is the Crypto module imported/available. """ return 'DES' in globals() def calc_suffix(_str, n): """ Return an n charaters suffix of the argument string of the form '...suffix'. """ if len(_str) <= n: return _str return '...' + _str[-(n - 3):] def calc_prefix(_str, n): """ Return an n charaters prefix of the argument string of the form 'prefix...'. """ if len(_str) <= n: return _str return _str[: (n - 3)] + '...' def create_rpdb_settings_folder(): """ Create the settings folder on Posix systems: '~/.rpdb2_settings' with mode 700. """ if os.name != POSIX: return home = os.path.expanduser('~') rsf = os.path.join(home, RPDB_SETTINGS_FOLDER) if not os.path.exists(rsf): os.mkdir(rsf, int('0700', 8)) pwds = os.path.join(home, RPDB_PWD_FOLDER) if not os.path.exists(pwds): os.mkdir(pwds, int('0700', 8)) bpl = os.path.join(home, RPDB_BPL_FOLDER) if not os.path.exists(bpl): os.mkdir(bpl, int('0700', 8)) def cleanup_bpl_folder(path): if random.randint(0, 10) > 0: return l = os.listdir(path) if len(l) < MAX_BPL_FILES: return try: ll = [(os.stat(os.path.join(path, f))[stat.ST_ATIME], f) for f in l] except: return ll.sort() for (t, f) in ll[: -MAX_BPL_FILES]: try: os.remove(os.path.join(path, f)) except: pass def calc_bpl_filename(filename): key = as_bytes(filename) tmp_filename = hmac.new(key).hexdigest()[:10] if os.name == POSIX: home = os.path.expanduser('~') bpldir = os.path.join(home, RPDB_BPL_FOLDER) cleanup_bpl_folder(bpldir) path = os.path.join(bpldir, tmp_filename) + BREAKPOINTS_FILE_EXT return path # # gettempdir() is used since it works with unicode user names on # Windows. # tmpdir = tempfile.gettempdir() bpldir = os.path.join(tmpdir, RPDB_BPL_FOLDER_NT) if not os.path.exists(bpldir): # # Folder creation is done here since this is a temp folder. # try: os.mkdir(bpldir, int('0700', 8)) except: print_debug_exception() raise CException else: cleanup_bpl_folder(bpldir) path = os.path.join(bpldir, tmp_filename) + BREAKPOINTS_FILE_EXT return path def calc_pwd_file_path(rid): """ Calc password file path for Posix systems: '~/.rpdb2_settings/' """ home = os.path.expanduser('~') rsf = os.path.join(home, RPDB_PWD_FOLDER) pwd_file_path = os.path.join(rsf, rid) return pwd_file_path def create_pwd_file(rid, _rpdb2_pwd): """ Create password file for Posix systems. """ if os.name != POSIX: return path = calc_pwd_file_path(rid) fd = os.open(path, os.O_WRONLY | os.O_CREAT, int('0600', 8)) os.write(fd, _rpdb2_pwd) os.close(fd) def read_pwd_file(rid): """ Read password from password file for Posix systems. """ assert(os.name == POSIX) path = calc_pwd_file_path(rid) p = open(path, 'r') _rpdb2_pwd = p.read() p.close() _rpdb2_pwd = as_unicode(_rpdb2_pwd, fstrict = True) return _rpdb2_pwd def delete_pwd_file(rid): """ Delete password file for Posix systems. """ if os.name != POSIX: return path = calc_pwd_file_path(rid) try: os.remove(path) except: pass def CalcUserShell(): try: s = os.getenv('SHELL') if s != None: return s import getpass username = getpass.getuser() f = open('/etc/passwd', 'r') l = f.read() f.close() ll = l.split('\n') d = dict([(e.split(':', 1)[0], e.split(':')[-1]) for e in ll]) return d[username] except: return 'sh' def IsFilteredAttribute(a): if not (a.startswith('__') and a.endswith('__')): return False if a in ['__class__', '__bases__', '__file__', '__doc__', '__name__', '__all__', '__builtins__']: return False return True def IsFilteredAttribute2(r, a): try: o = getattr(r, a) r = parse_type(type(o)) if 'function' in r or 'method' in r or r == 'type': return True return False except: return False def CalcFilteredDir(r, filter_level): d = dir(r) if filter_level == 0: return d fd = [a for a in d if not IsFilteredAttribute(a)] return fd def CalcIdentity(r, filter_level): if filter_level == 0: return r if not hasattr(r, 'im_func'): return r return r.im_func def getattr_nothrow(o, a): try: return getattr(o, a) except AttributeError: return ERROR_NO_ATTRIBUTE except: print_debug_exception() return ERROR_NO_ATTRIBUTE def calc_attribute_list(r, filter_level): d = CalcFilteredDir(r, filter_level) rs = set(d) c = getattr_nothrow(r, '__class__') if not c is ERROR_NO_ATTRIBUTE: d = CalcFilteredDir(c, False) cs = set(d) s = rs & cs for e in s: o1 = getattr_nothrow(r, e) o2 = getattr_nothrow(c, e) if o1 is ERROR_NO_ATTRIBUTE or CalcIdentity(o1, filter_level) is CalcIdentity(o2, filter_level): rs.discard(e) try: if filter_level == 1 and getattr(o1, '__self__') is getattr(o2, '__self__'): rs.discard(e) except: pass bl = getattr_nothrow(r, '__bases__') if type(bl) == tuple: for b in bl: d = CalcFilteredDir(b, False) bs = set(d) s = rs & bs for e in s: o1 = getattr_nothrow(r, e) o2 = getattr_nothrow(b, e) if o1 is ERROR_NO_ATTRIBUTE or CalcIdentity(o1, filter_level) is CalcIdentity(o2, filter_level): rs.discard(e) try: if filter_level == 1 and getattr(o1, '__self__') is getattr(o2, '__self__'): rs.discard(e) except: pass l = [a for a in rs if (filter_level < 2 or not IsFilteredAttribute2(r, a))] if hasattr(r, '__class__') and not '__class__' in l: l = ['__class__'] + l if hasattr(r, '__bases__') and not '__bases__' in l: l = ['__bases__'] + l al = [a for a in l if hasattr(r, a)] return al class _RPDB2_FindRepr: def __init__(self, o, repr_limit): self.m_object = o self.m_repr_limit = repr_limit def __getitem__(self, key): index = 0 for i in self.m_object: if repr_ltd(i, self.m_repr_limit, encoding = ENCODING_RAW_I).replace('"', '"') == key: if isinstance(self.m_object, dict): return self.m_object[i] return i index += 1 if index > MAX_SORTABLE_LENGTH: return None def __setitem__(self, key, value): if not isinstance(self.m_object, dict): return index = 0 for i in self.m_object: if repr_ltd(i, self.m_repr_limit, encoding = ENCODING_RAW_I).replace('"', '"') == key: self.m_object[i] = value return index += 1 if index > MAX_SORTABLE_LENGTH: return def SafeCmp(x, y): try: return cmp(x, y) except: pass return cmp(repr_ltd(x, 256, encoding = ENCODING_RAW_I), repr_ltd(y, 256, encoding = ENCODING_RAW_I)) def recalc_sys_path(old_pythonpath): opl = old_pythonpath.split(os.path.pathsep) del sys.path[1: 1 + len(opl)] pythonpath = os.environ.get('PYTHONPATH', '') ppl = pythonpath.split(os.path.pathsep) for i, p in enumerate(ppl): abspath = my_abspath(p) lowered = winlower(abspath) sys.path.insert(1 + i, lowered) def calc_signame(signum): for k, v in vars(signal).items(): if not k.startswith('SIG') or k in ['SIG_IGN', 'SIG_DFL', 'SIGRTMIN', 'SIGRTMAX']: continue if v == signum: return k return '?' # # Similar to traceback.extract_stack() but fixes path with calc_frame_path() # def my_extract_stack(f): _s = traceback.extract_stack(f) _s.reverse() s = [] for (p, ln, fn, text) in _s: path = as_unicode(calc_frame_path(f), sys.getfilesystemencoding()) if text == None: text = '' s.append((path, ln, as_unicode(fn), as_unicode(text))) f = f.f_back if f == None: break s.reverse() return s # # Similar to traceback.extract_tb() but fixes path with calc_frame_path() # def my_extract_tb(tb): _s = traceback.extract_tb(tb) s = [] for (p, ln, fn, text) in _s: path = as_unicode(calc_frame_path(tb.tb_frame), sys.getfilesystemencoding()) if text == None: text = '' s.append((path, ln, as_unicode(fn), as_unicode(text))) tb = tb.tb_next if tb == None: break return s class CFirewallTest: m_port = None m_thread_server = None m_thread_client = None m_lock = threading.RLock() def __init__(self, fremote = False, timeout = 4): if fremote: self.m_loopback = '' else: self.m_loopback = LOOPBACK self.m_timeout = timeout self.m_result = None self.m_last_server_error = None self.m_last_client_error = None def run(self): CFirewallTest.m_lock.acquire() try: # # If either the server or client are alive after a timeout # it means they are blocked by a firewall. Return False. # server = CFirewallTest.m_thread_server if server != None and server.isAlive(): server.join(self.m_timeout * 1.5) if server.isAlive(): return False client = CFirewallTest.m_thread_client if client != None and client.isAlive(): client.join(self.m_timeout * 1.5) if client.isAlive(): return False CFirewallTest.m_port = None self.m_result = None t0 = time.time() server = threading.Thread(target = self.__server) server.start() CFirewallTest.m_thread_server = server # # If server exited or failed to setup after a timeout # it means it was blocked by a firewall. # while CFirewallTest.m_port == None and server.isAlive(): if time.time() - t0 > self.m_timeout * 1.5: return False time.sleep(0.1) if not server.isAlive(): return False t0 = time.time() client = threading.Thread(target = self.__client) client.start() CFirewallTest.m_thread_client = client while self.m_result == None and client.isAlive(): if time.time() - t0 > self.m_timeout * 1.5: return False time.sleep(0.1) return self.m_result finally: CFirewallTest.m_lock.release() def __client(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(self.m_timeout) try: try: s.connect((LOOPBACK, CFirewallTest.m_port)) s.send(as_bytes('Hello, world')) data = self.__recv(s, 1024) self.m_result = True except socket.error: e = sys.exc_info()[1] self.m_last_client_error = e self.m_result = False finally: s.close() def __server(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(self.m_timeout) if os.name == POSIX: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) port = SERVER_PORT_RANGE_START while True: try: s.bind((self.m_loopback, port)) break except socket.error: e = sys.exc_info()[1] if self.__GetSocketError(e) != errno.EADDRINUSE: self.m_last_server_error = e s.close() return if port >= SERVER_PORT_RANGE_START + SERVER_PORT_RANGE_LENGTH - 1: self.m_last_server_error = e s.close() return port += 1 CFirewallTest.m_port = port try: try: conn = None s.listen(1) conn, addr = s.accept() while True: data = self.__recv(conn, 1024) if not data: return conn.send(data) except socket.error: e = sys.exc_info()[1] self.m_last_server_error = e finally: if conn != None: conn.close() s.close() def __recv(self, s, len): t0 = time.time() while True: try: data = s.recv(1024) return data except socket.error: e = sys.exc_info()[1] if self.__GetSocketError(e) != errno.EWOULDBLOCK: print_debug('socket error was caught, %s' % repr(e)) raise if time.time() - t0 > self.m_timeout: raise continue def __GetSocketError(self, e): if (not isinstance(e.args, tuple)) or (len(e.args) == 0): return -1 return e.args[0] # # ---------------------------------- CThread --------------------------------------- # class CThread (threading.Thread): m_fstop = False m_threads = {} m_lock = threading.RLock() m_id = 0 def __init__(self, name = None, target = None, args = (), shutdown = None): threading.Thread.__init__(self, name = name, target = target, args = args) self.m_fstarted = False self.m_shutdown_callback = shutdown self.m_id = self.__getId() def __del__(self): #print_debug('Destructor called for ' + self.getName()) #threading.Thread.__del__(self) if self.m_fstarted: try: del CThread.m_threads[self.m_id] except KeyError: pass def start(self): if CThread.m_fstop: return CThread.m_threads[self.m_id] = weakref.ref(self) if CThread.m_fstop: del CThread.m_threads[self.m_id] return self.m_fstarted = True threading.Thread.start(self) def run(self): sys.settrace(None) sys.setprofile(None) threading.Thread.run(self) def join(self, timeout = None): try: threading.Thread.join(self, timeout) except AssertionError: pass def shutdown(self): if self.m_shutdown_callback: self.m_shutdown_callback() def joinAll(cls): print_debug('Shutting down debugger threads...') CThread.m_fstop = True for tid, w in list(CThread.m_threads.items()): t = w() if not t: continue try: #print_debug('Calling shutdown of thread %s.' % t.getName()) t.shutdown() except: pass t = None t0 = time.time() while len(CThread.m_threads) > 0: if time.time() - t0 > SHUTDOWN_TIMEOUT: print_debug('Shut down of debugger threads has TIMED OUT!') return #print_debug(repr(CThread.m_threads)) time.sleep(0.1) print_debug('Shut down debugger threads, done.') joinAll = classmethod(joinAll) def clearJoin(cls): CThread.m_fstop = False clearJoin = classmethod(clearJoin) def __getId(self): CThread.m_lock.acquire() id = CThread.m_id CThread.m_id += 1 CThread.m_lock.release() return id # #--------------------------------------- Crypto --------------------------------------- # class CCrypto: """ Handle authentication and encryption of data, using password protection. """ m_keys = {} def __init__(self, _rpdb2_pwd, fAllowUnencrypted, rid): assert(is_unicode(_rpdb2_pwd)) assert(is_unicode(rid)) self.m_rpdb2_pwd = _rpdb2_pwd self.m_key = self.__calc_key(_rpdb2_pwd) self.m_fAllowUnencrypted = fAllowUnencrypted self.m_rid = rid self.m_failure_lock = threading.RLock() self.m_lock = threading.RLock() self.m_index_anchor_in = random.randint(0, 1000000000) self.m_index_anchor_ex = 0 self.m_index = 0 self.m_index_table = {} self.m_index_table_size = INDEX_TABLE_SIZE self.m_max_index = 0 def __calc_key(self, _rpdb2_pwd): """ Create and return a key from a password. A Weak password means a weak key. """ if _rpdb2_pwd in CCrypto.m_keys: return CCrypto.m_keys[_rpdb2_pwd] key = as_bytes(_rpdb2_pwd) suffix = key[:16] d = hmac.new(key, digestmod = _md5) # # The following loop takes around a second to complete # and should strengthen the password by ~12 bits. # a good password is ~30 bits strong so we are looking # at ~42 bits strong key # for i in range(2 ** 12): d.update((key + suffix) * 16) key = d.digest() CCrypto.m_keys[_rpdb2_pwd] = key return key def set_index(self, i, anchor): try: self.m_lock.acquire() self.m_index = i self.m_index_anchor_ex = anchor finally: self.m_lock.release() def get_max_index(self): return self.m_max_index def do_crypto(self, args, fencrypt): """ Sign args and possibly encrypt. Return signed/encrypted string. """ if not fencrypt and not self.m_fAllowUnencrypted: raise EncryptionExpected if fencrypt and not is_encryption_supported(): raise EncryptionNotSupported (digest, s) = self.__sign(args) fcompress = False if len(s) > 50000: _s = zlib.compress(s) if len(_s) < len(s) * 0.4: s = _s fcompress = True if fencrypt: s = self.__encrypt(s) s = base64.encodestring(s) u = as_unicode(s) return (fcompress, digest, u) def undo_crypto(self, fencrypt, fcompress, digest, msg, fVerifyIndex = True): """ Take crypto string, verify its signature and decrypt it, if needed. """ if not fencrypt and not self.m_fAllowUnencrypted: raise EncryptionExpected if fencrypt and not is_encryption_supported(): raise EncryptionNotSupported s = as_bytes(msg) s = base64.decodestring(s) if fencrypt: s = self.__decrypt(s) if fcompress: s = zlib.decompress(s) args, id = self.__verify_signature(digest, s, fVerifyIndex) return (args, id) def __encrypt(self, s): s_padded = s + as_bytes('\x00') * (DES.block_size - (len(s) % DES.block_size)) key_padded = (self.m_key + as_bytes('0') * (DES.key_size - (len(self.m_key) % DES.key_size)))[:DES.key_size] iv = '0' * DES.block_size d = DES.new(key_padded, DES.MODE_CBC, iv) r = d.encrypt(s_padded) return r def __decrypt(self, s): try: key_padded = (self.m_key + as_bytes('0') * (DES.key_size - (len(self.m_key) % DES.key_size)))[:DES.key_size] iv = '0' * DES.block_size d = DES.new(key_padded, DES.MODE_CBC, iv) _s = d.decrypt(s).strip(as_bytes('\x00')) return _s except: self.__wait_a_little() raise DecryptionFailure def __sign(self, args): i = self.__get_next_index() pack = (self.m_index_anchor_ex, i, self.m_rid, args) #print_debug('***** 1' + repr(args)[:50]) s = pickle.dumps(pack, 2) #print_debug('***** 2' + repr(args)[:50]) h = hmac.new(self.m_key, s, digestmod = _md5) d = h.hexdigest() #if 'coding:' in s: # print_debug('%s, %s, %s\n\n==========\n\n%s' % (len(s), d, repr(args), repr(s))) return (d, s) def __get_next_index(self): try: self.m_lock.acquire() self.m_index += 1 return self.m_index finally: self.m_lock.release() def __verify_signature(self, digest, s, fVerifyIndex): try: h = hmac.new(self.m_key, s, digestmod = _md5) d = h.hexdigest() #if 'coding:' in s: # print_debug('%s, %s, %s, %s' % (len(s), digest, d, repr(s))) if d != digest: self.__wait_a_little() raise AuthenticationFailure pack = pickle.loads(s) (anchor, i, id, args) = pack except AuthenticationFailure: raise except: print_debug_exception() self.__wait_a_little() raise AuthenticationBadData if fVerifyIndex: self.__verify_index(anchor, i, id) return args, id def __verify_index(self, anchor, i, id): """ Manage messages ids to prevent replay of old messages. """ try: try: self.m_lock.acquire() if anchor != self.m_index_anchor_in: raise AuthenticationBadIndex(self.m_max_index, self.m_index_anchor_in) if i > self.m_max_index + INDEX_TABLE_SIZE // 2: raise AuthenticationBadIndex(self.m_max_index, self.m_index_anchor_in) i_mod = i % INDEX_TABLE_SIZE (iv, idl) = self.m_index_table.get(i_mod, (None, None)) #print >> sys.__stderr__, i, i_mod, iv, self.m_max_index if (iv is None) or (i > iv): idl = [id] elif (iv == i) and (not id in idl): idl.append(id) else: raise AuthenticationBadIndex(self.m_max_index, self.m_index_anchor_in) self.m_index_table[i_mod] = (i, idl) if i > self.m_max_index: self.m_max_index = i return self.m_index finally: self.m_lock.release() except: self.__wait_a_little() raise def __wait_a_little(self): self.m_failure_lock.acquire() time.sleep((1.0 + random.random()) / 2) self.m_failure_lock.release() # # --------------------------------- Events List -------------------------- # class CEvent(object): """ Base class for events. """ def __reduce__(self): rv = (copy_reg.__newobj__, (type(self), ), vars(self), None, None) return rv def is_match(self, arg): pass class CEventNull(CEvent): """ Sent to release event listeners (Internal, speeds up shutdown). """ pass class CEventEmbeddedSync(CEvent): """ Sent when an embedded interpreter becomes active if it needs to determine if there are pending break requests. (Internal) """ pass class CEventClearSourceCache(CEvent): """ Sent when the source cache is cleared. """ pass class CEventSignalIntercepted(CEvent): """ This event is sent when a signal is intercepted inside tracing code. Such signals are held pending until tracing code is returned from. """ def __init__(self, signum): self.m_signum = signum self.m_signame = calc_signame(signum) class CEventSignalException(CEvent): """ This event is sent when the handler of a previously intercepted signal raises an exception. Such exceptions are ignored because of technical limitations. """ def __init__(self, signum, description): self.m_signum = signum self.m_signame = calc_signame(signum) self.m_description = description class CEventEncoding(CEvent): """ The encoding has been set. """ def __init__(self, encoding, fraw): self.m_encoding = encoding self.m_fraw = fraw class CEventPsycoWarning(CEvent): """ The psyco module was detected. rpdb2 is incompatible with this module. """ pass class CEventConflictingModules(CEvent): """ Conflicting modules were detected. rpdb2 is incompatible with these modules. """ def __init__(self, modules_list): self.m_modules_list = modules_list class CEventSyncReceivers(CEvent): """ A base class for events that need to be received by all listeners at the same time. The synchronization mechanism is internal to rpdb2. """ def __init__(self, sync_n): self.m_sync_n = sync_n class CEventForkSwitch(CEventSyncReceivers): """ Debuggee is about to fork. Try to reconnect. """ pass class CEventExecSwitch(CEventSyncReceivers): """ Debuggee is about to exec. Try to reconnect. """ pass class CEventExit(CEvent): """ Debuggee is terminating. """ pass class CEventState(CEvent): """ State of the debugger. Value of m_state can be one of the STATE_* globals. """ def __init__(self, state): self.m_state = as_unicode(state) def is_match(self, arg): return self.m_state == as_unicode(arg) class CEventSynchronicity(CEvent): """ Mode of synchronicity. Sent when mode changes. """ def __init__(self, fsynchronicity): self.m_fsynchronicity = fsynchronicity def is_match(self, arg): return self.m_fsynchronicity == arg class CEventTrap(CEvent): """ Mode of "trap unhandled exceptions". Sent when the mode changes. """ def __init__(self, ftrap): self.m_ftrap = ftrap def is_match(self, arg): return self.m_ftrap == arg class CEventForkMode(CEvent): """ Mode of fork behavior has changed. Sent when the mode changes. """ def __init__(self, ffork_into_child, ffork_auto): self.m_ffork_into_child = ffork_into_child self.m_ffork_auto = ffork_auto class CEventUnhandledException(CEvent): """ Unhandled Exception Sent when an unhandled exception is caught. """ class CEventNamespace(CEvent): """ Namespace has changed. This tells the debugger it should query the namespace again. """ pass class CEventNoThreads(CEvent): """ No threads to debug. Debuggee notifies the debugger that it has no threads. This can happen in embedded debugging and in a python interpreter session. """ pass class CEventThreads(CEvent): """ State of threads. """ def __init__(self, current_thread, thread_list): self.m_current_thread = current_thread self.m_thread_list = thread_list class CEventThreadBroken(CEvent): """ A thread has broken. """ def __init__(self, tid, name): self.m_tid = tid self.m_name = as_unicode(name) class CEventStack(CEvent): """ Stack of current thread. """ def __init__(self, stack): self.m_stack = stack class CEventStackFrameChange(CEvent): """ Stack frame has changed. This event is sent when the debugger goes up or down the stack. """ def __init__(self, frame_index): self.m_frame_index = frame_index class CEventStackDepth(CEvent): """ Stack depth has changed. """ def __init__(self, stack_depth, stack_depth_exception): self.m_stack_depth = stack_depth self.m_stack_depth_exception = stack_depth_exception class CEventBreakpoint(CEvent): """ A breakpoint or breakpoints changed. """ DISABLE = as_unicode('disable') ENABLE = as_unicode('enable') REMOVE = as_unicode('remove') SET = as_unicode('set') def __init__(self, bp, action = SET, id_list = [], fAll = False): self.m_bp = breakpoint_copy(bp) self.m_action = action self.m_id_list = id_list self.m_fAll = fAll class CEventSync(CEvent): """ Internal (not sent to the debugger) event that trigers the firing of other events that help the debugger synchronize with the state of the debuggee. """ def __init__(self, fException, fSendUnhandled): self.m_fException = fException self.m_fSendUnhandled = fSendUnhandled # # --------------------------------- Event Manager -------------------------- # class CEventDispatcherRecord: """ Internal structure that binds a callback to particular events. """ def __init__(self, callback, event_type_dict, fSingleUse): self.m_callback = callback self.m_event_type_dict = copy.copy(event_type_dict) self.m_fSingleUse = fSingleUse def is_match(self, event): rtl = [t for t in self.m_event_type_dict.keys() if isinstance(event, t)] if len(rtl) == 0: return False # # Examine first match only. # rt = rtl[0] rte = self.m_event_type_dict[rt].get(EVENT_EXCLUDE, []) if len(rte) != 0: for e in rte: if event.is_match(e): return False return True rte = self.m_event_type_dict[rt].get(EVENT_INCLUDE, []) if len(rte) != 0: for e in rte: if event.is_match(e): return True return False return True class CEventDispatcher: """ Events dispatcher. Dispatchers can be chained together. """ def __init__(self, chained_event_dispatcher = None): self.m_chained_event_dispatcher = chained_event_dispatcher self.m_chain_override_types = {} self.m_registrants = {} def shutdown(self): for er in list(self.m_registrants.keys()): self.__remove_dispatcher_record(er) def register_callback(self, callback, event_type_dict, fSingleUse): er = CEventDispatcherRecord(callback, event_type_dict, fSingleUse) # # If we have a chained dispatcher, register the callback on the # chained dispatcher as well. # if self.m_chained_event_dispatcher is not None: _er = self.__register_callback_on_chain(er, event_type_dict, fSingleUse) self.m_registrants[er] = _er return er self.m_registrants[er] = True return er def remove_callback(self, callback): erl = [er for er in list(self.m_registrants.keys()) if er.m_callback == callback] for er in erl: self.__remove_dispatcher_record(er) def fire_events(self, event_list): for event in event_list: self.fire_event(event) def fire_event(self, event): for er in list(self.m_registrants.keys()): self.__fire_er(event, er) def __fire_er(self, event, er): if not er.is_match(event): return try: er.m_callback(event) except: pass if not er.m_fSingleUse: return try: del self.m_registrants[er] except KeyError: pass def register_chain_override(self, event_type_dict): """ Chain override prevents registration on chained dispatchers for specific event types. """ for t in list(event_type_dict.keys()): self.m_chain_override_types[t] = True def __register_callback_on_chain(self, er, event_type_dict, fSingleUse): _event_type_dict = copy.copy(event_type_dict) for t in self.m_chain_override_types: if t in _event_type_dict: del _event_type_dict[t] if len(_event_type_dict) == 0: return False def callback(event, er = er): self.__fire_er(event, er) _er = self.m_chained_event_dispatcher.register_callback(callback, _event_type_dict, fSingleUse) return _er def __remove_dispatcher_record(self, er): try: if self.m_chained_event_dispatcher is not None: _er = self.m_registrants[er] if _er != False: self.m_chained_event_dispatcher.__remove_dispatcher_record(_er) del self.m_registrants[er] except KeyError: pass class CEventQueue: """ Add queue semantics above an event dispatcher. Instead of firing event callbacks, new events are returned in a list upon request. """ def __init__(self, event_dispatcher, max_event_list_length = MAX_EVENT_LIST_LENGTH): self.m_event_dispatcher = event_dispatcher self.m_event_lock = threading.Condition() self.m_max_event_list_length = max_event_list_length self.m_event_list = [] self.m_event_index = 0 self.m_n_waiters = [] def shutdown(self): self.m_event_dispatcher.remove_callback(self.event_handler) def register_event_types(self, event_type_dict): self.m_event_dispatcher.register_callback(self.event_handler, event_type_dict, fSingleUse = False) def event_handler(self, event): try: self.m_event_lock.acquire() if isinstance(event, CEventSyncReceivers): t0 = time.time() while len(self.m_n_waiters) < event.m_sync_n and time.time() < t0 + HEARTBEAT_TIMEOUT: time.sleep(0.1) self.m_event_list.append(event) if len(self.m_event_list) > self.m_max_event_list_length: self.m_event_list.pop(0) self.m_event_index += 1 self.m_event_lock.notifyAll() finally: self.m_event_lock.release() def get_event_index(self): return self.m_event_index def wait_for_event(self, timeout, event_index): """ Return the new events which were fired. """ try: self.m_n_waiters.append(0) self.m_event_lock.acquire() if event_index >= self.m_event_index: safe_wait(self.m_event_lock, timeout) if event_index >= self.m_event_index: return (self.m_event_index, []) sub_event_list = self.m_event_list[event_index - self.m_event_index:] return (self.m_event_index, sub_event_list) finally: self.m_n_waiters.pop() self.m_event_lock.release() class CStateManager: """ Manage possible debugger states (broken, running, etc...) The state manager can receive state changes via an input event dispatcher or via the set_state() method It sends state changes forward to the output event dispatcher. The state can also be queried or waited for. """ def __init__(self, initial_state, event_dispatcher_output = None, event_dispatcher_input = None): self.m_event_dispatcher_input = event_dispatcher_input self.m_event_dispatcher_output = event_dispatcher_output if self.m_event_dispatcher_input is not None: event_type_dict = {CEventState: {}} self.m_event_dispatcher_input.register_callback(self.event_handler, event_type_dict, fSingleUse = False) if self.m_event_dispatcher_output is not None: self.m_event_dispatcher_output.register_chain_override(event_type_dict) self.m_state_lock = threading.Condition() self.m_state_queue = [] self.m_state_index = 0 self.m_waiter_list = {} self.set_state(initial_state) def shutdown(self): if self.m_event_dispatcher_input is not None: self.m_event_dispatcher_input.remove_callback(self.event_handler) def event_handler(self, event): self.set_state(event.m_state) def get_state(self): return self.m_state_queue[-1] def __add_state(self, state): self.m_state_queue.append(state) self.m_state_index += 1 self.__remove_states() def __remove_states(self, treshold = None): """ Clean up old state changes from the state queue. """ index = self.__calc_min_index() if (treshold is not None) and (index <= treshold): return _delta = 1 + self.m_state_index - index self.m_state_queue = self.m_state_queue[-_delta:] def __calc_min_index(self): """ Calc the minimum state index. The calculated index is the oldest state of which all state waiters are aware of. That is, no one cares for older states and these can be removed from the state queue. """ if len(self.m_waiter_list) == 0: return self.m_state_index index_list = list(self.m_waiter_list.keys()) min_index = min(index_list) return min_index def __add_waiter(self): index = self.m_state_index n = self.m_waiter_list.get(index, 0) self.m_waiter_list[index] = n + 1 return index def __remove_waiter(self, index): n = self.m_waiter_list[index] if n == 1: del self.m_waiter_list[index] self.__remove_states(index) else: self.m_waiter_list[index] = n - 1 def __get_states(self, index): _delta = 1 + self.m_state_index - index states = self.m_state_queue[-_delta:] return states def set_state(self, state = None, fLock = True): try: if fLock: self.m_state_lock.acquire() if state is None: state = self.get_state() self.__add_state(state) self.m_state_lock.notifyAll() finally: if fLock: self.m_state_lock.release() if self.m_event_dispatcher_output is not None: event = CEventState(state) self.m_event_dispatcher_output.fire_event(event) def wait_for_state(self, state_list): """ Wait for any of the states in the state list. """ try: self.m_state_lock.acquire() if self.get_state() in state_list: return self.get_state() while True: index = self.__add_waiter() alertable_wait(self.m_state_lock, PING_TIMEOUT) states = self.__get_states(index) self.__remove_waiter(index) for state in states: if state in state_list: return state finally: self.m_state_lock.release() def acquire(self): self.m_state_lock.acquire() def release(self): self.m_state_lock.release() # # -------------------------------------- Break Info manager --------------------------------------- # def myord(c): try: return ord(c) except: return c def CalcValidLines(code): l = code.co_firstlineno vl = [l] bl = [myord(c) for c in code.co_lnotab[2::2]] sl = [myord(c) for c in code.co_lnotab[1::2]] for (bi, si) in zip(bl, sl): l += si if bi == 0: continue if l != vl[-1]: vl.append(l) if len(sl) > 0: l += sl[-1] if l != vl[-1]: vl.append(l) return vl class CScopeBreakInfo: def __init__(self, fqn, valid_lines): self.m_fqn = fqn self.m_first_line = valid_lines[0] self.m_last_line = valid_lines[-1] self.m_valid_lines = valid_lines def CalcScopeLine(self, lineno): rvl = copy.copy(self.m_valid_lines) rvl.reverse() for l in rvl: if lineno >= l: break return l def __str__(self): return "('" + self.m_fqn + "', " + str(self.m_valid_lines) + ')' class CFileBreakInfo: """ Break info structure for a source file. """ def __init__(self, filename): self.m_filename = filename self.m_first_line = 0 self.m_last_line = 0 self.m_scope_break_info = [] def CalcBreakInfo(self): (source, encoding) = get_source(self.m_filename) _source = as_string(source + as_unicode('\n'), encoding) code = compile(_source, self.m_filename, "exec") self.m_scope_break_info = [] self.m_first_line = code.co_firstlineno self.m_last_line = 0 fqn = [] t = [code] while len(t) > 0: c = t.pop(0) if type(c) == tuple: self.m_scope_break_info.append(CScopeBreakInfo(*c)) fqn.pop() continue fqn = fqn + [c.co_name] valid_lines = CalcValidLines(c) self.m_last_line = max(self.m_last_line, valid_lines[-1]) _fqn = as_unicode('.'.join(fqn), encoding) si = (_fqn, valid_lines) subcodeslist = self.__CalcSubCodesList(c) t = subcodeslist + [si] + t def __CalcSubCodesList(self, code): tc = type(code) t = [(c.co_firstlineno, c) for c in code.co_consts if type(c) == tc] t.sort() scl = [c[1] for c in t] return scl def FindScopeByLineno(self, lineno): lineno = max(min(lineno, self.m_last_line), self.m_first_line) smaller_element = None exact_element = None for sbi in self.m_scope_break_info: if lineno > sbi.m_last_line: if (smaller_element is None) or (sbi.m_last_line >= smaller_element.m_last_line): smaller_element = sbi continue if (lineno >= sbi.m_first_line) and (lineno <= sbi.m_last_line): exact_element = sbi break assert(exact_element is not None) scope = exact_element l = exact_element.CalcScopeLine(lineno) if (smaller_element is not None) and (l <= smaller_element.m_last_line): scope = smaller_element l = smaller_element.CalcScopeLine(lineno) return (scope, l) def FindScopeByName(self, name, offset): if name.startswith(MODULE_SCOPE): alt_scope = MODULE_SCOPE2 + name[len(MODULE_SCOPE):] elif name.startswith(MODULE_SCOPE2): alt_scope = MODULE_SCOPE + name[len(MODULE_SCOPE2):] else: return self.FindScopeByName(MODULE_SCOPE2 + SCOPE_SEP + name, offset) for sbi in self.m_scope_break_info: if sbi.m_fqn in [name, alt_scope]: l = sbi.CalcScopeLine(sbi.m_first_line + offset) return (sbi, l) print_debug('Invalid scope: %s' % repr(name)) raise InvalidScopeName class CBreakInfoManager: """ Manage break info dictionary per filename. """ def __init__(self): self.m_file_info_dic = {} def addFile(self, filename): mbi = CFileBreakInfo(filename) mbi.CalcBreakInfo() self.m_file_info_dic[filename] = mbi def getFile(self, filename): if not filename in self.m_file_info_dic: self.addFile(filename) return self.m_file_info_dic[filename] # # -------------------------------- Break Point Manager ----------------------------- # def breakpoint_copy(bp): if bp is None: return None _bp = copy.copy(bp) #filename = g_found_unicode_files.get(bp.m_filename, bp.m_filename) _bp.m_filename = as_unicode(bp.m_filename, sys.getfilesystemencoding()) _bp.m_code = None return _bp class CBreakPoint(object): def __init__(self, filename, scope_fqn, scope_first_line, lineno, fEnabled, expr, encoding, fTemporary = False): """ Breakpoint constructor. scope_fqn - scope fully qualified name. e.g: module.class.method """ self.m_id = None self.m_fEnabled = fEnabled self.m_filename = filename self.m_scope_fqn = scope_fqn self.m_scope_name = scope_fqn.split(SCOPE_SEP)[-1] self.m_scope_first_line = scope_first_line self.m_scope_offset = lineno - scope_first_line self.m_lineno = lineno self.m_expr = expr self.m_encoding = encoding self.m_code = None self.m_fTemporary = fTemporary if (expr is not None) and (expr != ''): _expr = as_bytes(ENCODING_SOURCE % encoding + expr, encoding) print_debug('Breakpoint expression: %s' % repr(_expr)) self.m_code = compile(_expr, '', 'eval') def __reduce__(self): rv = (copy_reg.__newobj__, (type(self), ), vars(self), None, None) return rv def calc_enclosing_scope_name(self): if self.m_scope_offset != 0: return None if self.m_scope_fqn in [MODULE_SCOPE, MODULE_SCOPE2]: return None scope_name_list = self.m_scope_fqn.split(SCOPE_SEP) enclosing_scope_name = scope_name_list[-2] return enclosing_scope_name def enable(self): self.m_fEnabled = True def disable(self): self.m_fEnabled = False def isEnabled(self): return self.m_fEnabled def __str__(self): return "('" + self.m_filename + "', '" + self.m_scope_fqn + "', " + str(self.m_scope_first_line) + ', ' + str(self.m_scope_offset) + ', ' + str(self.m_lineno) + ')' class CBreakPointsManagerProxy: """ A proxy for the breakpoint manager. While the breakpoint manager resides on the debuggee (the server), the proxy resides in the debugger (the client - session manager) """ def __init__(self, session_manager): self.m_session_manager = session_manager self.m_break_points_by_file = {} self.m_break_points_by_id = {} self.m_lock = threading.Lock() # # The breakpoint proxy inserts itself between the two chained # event dispatchers in the session manager. # event_type_dict = {CEventBreakpoint: {}} self.m_session_manager.m_event_dispatcher_proxy.register_callback(self.update_bp, event_type_dict, fSingleUse = False) self.m_session_manager.m_event_dispatcher.register_chain_override(event_type_dict) def update_bp(self, event): """ Handle breakpoint updates that arrive via the event dispatcher. """ try: self.m_lock.acquire() if event.m_fAll: id_list = list(self.m_break_points_by_id.keys()) else: id_list = event.m_id_list if event.m_action == CEventBreakpoint.REMOVE: for id in id_list: try: bp = self.m_break_points_by_id.pop(id) bpm = self.m_break_points_by_file[bp.m_filename] del bpm[bp.m_lineno] if len(bpm) == 0: del self.m_break_points_by_file[bp.m_filename] except KeyError: pass return if event.m_action == CEventBreakpoint.DISABLE: for id in id_list: try: bp = self.m_break_points_by_id[id] bp.disable() except KeyError: pass return if event.m_action == CEventBreakpoint.ENABLE: for id in id_list: try: bp = self.m_break_points_by_id[id] bp.enable() except KeyError: pass return bpm = self.m_break_points_by_file.get(event.m_bp.m_filename, {}) bpm[event.m_bp.m_lineno] = event.m_bp self.m_break_points_by_id[event.m_bp.m_id] = event.m_bp finally: self.m_lock.release() self.m_session_manager.m_event_dispatcher.fire_event(event) def sync(self): try: self.m_lock.acquire() self.m_break_points_by_file = {} self.m_break_points_by_id = {} finally: self.m_lock.release() break_points_by_id = self.m_session_manager.getSession().getProxy().get_breakpoints() try: self.m_lock.acquire() self.m_break_points_by_id.update(break_points_by_id) for bp in list(self.m_break_points_by_id.values()): bpm = self.m_break_points_by_file.get(bp.m_filename, {}) bpm[bp.m_lineno] = bp finally: self.m_lock.release() def clear(self): try: self.m_lock.acquire() self.m_break_points_by_file = {} self.m_break_points_by_id = {} finally: self.m_lock.release() def get_breakpoints(self): return self.m_break_points_by_id def get_breakpoint(self, filename, lineno): bpm = self.m_break_points_by_file[filename] bp = bpm[lineno] return bp class CBreakPointsManager: def __init__(self): self.m_break_info_manager = CBreakInfoManager() self.m_active_break_points_by_file = {} self.m_break_points_by_function = {} self.m_break_points_by_file = {} self.m_break_points_by_id = {} self.m_lock = threading.Lock() self.m_temp_bp = None self.m_fhard_tbp = False def get_active_break_points_by_file(self, filename): """ Get active breakpoints for file. """ _filename = winlower(filename) return self.m_active_break_points_by_file.setdefault(_filename, {}) def __calc_active_break_points_by_file(self, filename): bpmpt = self.m_active_break_points_by_file.setdefault(filename, {}) bpmpt.clear() bpm = self.m_break_points_by_file.get(filename, {}) for bp in list(bpm.values()): if bp.m_fEnabled: bpmpt[bp.m_lineno] = bp tbp = self.m_temp_bp if (tbp is not None) and (tbp.m_filename == filename): bpmpt[tbp.m_lineno] = tbp def __remove_from_function_list(self, bp): function_name = bp.m_scope_name try: bpf = self.m_break_points_by_function[function_name] del bpf[bp] if len(bpf) == 0: del self.m_break_points_by_function[function_name] except KeyError: pass # # In some cases a breakpoint belongs to two scopes at the # same time. For example a breakpoint on the declaration line # of a function. # _function_name = bp.calc_enclosing_scope_name() if _function_name is None: return try: _bpf = self.m_break_points_by_function[_function_name] del _bpf[bp] if len(_bpf) == 0: del self.m_break_points_by_function[_function_name] except KeyError: pass def __add_to_function_list(self, bp): function_name = bp.m_scope_name bpf = self.m_break_points_by_function.setdefault(function_name, {}) bpf[bp] = True # # In some cases a breakpoint belongs to two scopes at the # same time. For example a breakpoint on the declaration line # of a function. # _function_name = bp.calc_enclosing_scope_name() if _function_name is None: return _bpf = self.m_break_points_by_function.setdefault(_function_name, {}) _bpf[bp] = True def get_breakpoint(self, filename, lineno): """ Get breakpoint by file and line number. """ bpm = self.m_break_points_by_file[filename] bp = bpm[lineno] return bp def del_temp_breakpoint(self, fLock = True, breakpoint = None): """ Delete a temoporary breakpoint. A temporary breakpoint is used when the debugger is asked to run-to a particular line. Hard temporary breakpoints are deleted only when actually hit. """ if self.m_temp_bp is None: return try: if fLock: self.m_lock.acquire() if self.m_temp_bp is None: return if self.m_fhard_tbp and not breakpoint is self.m_temp_bp: return bp = self.m_temp_bp self.m_temp_bp = None self.m_fhard_tbp = False self.__remove_from_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) finally: if fLock: self.m_lock.release() def set_temp_breakpoint(self, filename, scope, lineno, fhard = False): """ Set a temoporary breakpoint. A temporary breakpoint is used when the debugger is asked to run-to a particular line. Hard temporary breakpoints are deleted only when actually hit. """ _filename = winlower(filename) mbi = self.m_break_info_manager.getFile(_filename) if scope != '': (s, l) = mbi.FindScopeByName(scope, lineno) else: (s, l) = mbi.FindScopeByLineno(lineno) bp = CBreakPoint(_filename, s.m_fqn, s.m_first_line, l, fEnabled = True, expr = as_unicode(''), encoding = as_unicode('utf-8'), fTemporary = True) try: self.m_lock.acquire() self.m_fhard_tbp = False self.del_temp_breakpoint(fLock = False) self.m_fhard_tbp = fhard self.m_temp_bp = bp self.__add_to_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) finally: self.m_lock.release() def set_breakpoint(self, filename, scope, lineno, fEnabled, expr, encoding): """ Set breakpoint. scope - a string (possibly empty) with the dotted scope of the breakpoint. eg. 'my_module.my_class.foo' expr - a string (possibly empty) with a python expression that will be evaluated at the scope of the breakpoint. The breakpoint will be hit if the expression evaluates to True. """ _filename = winlower(filename) mbi = self.m_break_info_manager.getFile(_filename) if scope != '': (s, l) = mbi.FindScopeByName(scope, lineno) else: (s, l) = mbi.FindScopeByLineno(lineno) bp = CBreakPoint(_filename, s.m_fqn, s.m_first_line, l, fEnabled, expr, encoding) try: self.m_lock.acquire() bpm = self.m_break_points_by_file.setdefault(_filename, {}) # # If a breakpoint on the same line is found we use its ID. # Since the debugger lists breakpoints by IDs, this has # a similar effect to modifying the breakpoint. # try: old_bp = bpm[l] id = old_bp.m_id self.__remove_from_function_list(old_bp) except KeyError: # # Find the smallest available ID. # bpids = list(self.m_break_points_by_id.keys()) bpids.sort() id = 0 while id < len(bpids): if bpids[id] != id: break id += 1 bp.m_id = id self.m_break_points_by_id[id] = bp bpm[l] = bp if fEnabled: self.__add_to_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) return bp finally: self.m_lock.release() def disable_breakpoint(self, id_list, fAll): """ Disable breakpoint. """ try: self.m_lock.acquire() if fAll: id_list = list(self.m_break_points_by_id.keys()) for id in id_list: try: bp = self.m_break_points_by_id[id] except KeyError: continue bp.disable() self.__remove_from_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) finally: self.m_lock.release() def enable_breakpoint(self, id_list, fAll): """ Enable breakpoint. """ try: self.m_lock.acquire() if fAll: id_list = list(self.m_break_points_by_id.keys()) for id in id_list: try: bp = self.m_break_points_by_id[id] except KeyError: continue bp.enable() self.__add_to_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) finally: self.m_lock.release() def delete_breakpoint(self, id_list, fAll): """ Delete breakpoint. """ try: self.m_lock.acquire() if fAll: id_list = list(self.m_break_points_by_id.keys()) for id in id_list: try: bp = self.m_break_points_by_id[id] except KeyError: continue filename = bp.m_filename lineno = bp.m_lineno bpm = self.m_break_points_by_file[filename] if bp == bpm[lineno]: del bpm[lineno] if len(bpm) == 0: del self.m_break_points_by_file[filename] self.__remove_from_function_list(bp) self.__calc_active_break_points_by_file(bp.m_filename) del self.m_break_points_by_id[id] finally: self.m_lock.release() def get_breakpoints(self): return self.m_break_points_by_id # # ----------------------------------- Core Debugger ------------------------------------ # class CCodeContext: """ Class represents info related to code objects. """ def __init__(self, frame, bp_manager): self.m_code = frame.f_code self.m_filename = calc_frame_path(frame) self.m_basename = os.path.basename(self.m_filename) self.m_file_breakpoints = bp_manager.get_active_break_points_by_file(self.m_filename) self.m_fExceptionTrap = False def is_untraced(self): """ Return True if this code object should not be traced. """ return self.m_basename in [THREADING_FILENAME, DEBUGGER_FILENAME] def is_exception_trap_frame(self): """ Return True if this frame should be a trap for unhandled exceptions. """ if self.m_basename == THREADING_FILENAME: return True if self.m_basename == DEBUGGER_FILENAME and self.m_code.co_name in ['__execv', '__execve', '__function_wrapper']: return True return False class CDebuggerCoreThread: """ Class represents a debugged thread. This is a core structure of the debugger. It includes most of the optimization tricks and hacks, and includes a good amount of subtle bug fixes, be carefull not to mess it up... """ def __init__(self, name, core_debugger, frame, event): self.m_thread_id = thread.get_ident() self.m_thread_name = name self.m_fBroken = False self.m_fUnhandledException = False self.m_frame = frame self.m_event = event self.m_ue_lineno = None self.m_uef_lineno = None self.m_code_context = core_debugger.get_code_context(frame) self.m_locals_copy = {} self.m_core = core_debugger self.m_bp_manager = core_debugger.m_bp_manager self.m_frame_lock = threading.Condition() self.m_frame_external_references = 0 def profile(self, frame, event, arg): """ Profiler method. The Python profiling mechanism is used by the debugger mainly to handle synchronization issues related to the life time of the frame structure. """ #print_debug('profile: %s, %s, %s, %s, %s' % (repr(frame), event, frame.f_code.co_name, frame.f_code.co_filename, repr(arg)[:40])) if event == 'return': self.m_frame = frame.f_back try: self.m_code_context = self.m_core.m_code_contexts[self.m_frame.f_code] except AttributeError: if self.m_event != 'return' and self.m_core.m_ftrap: # # An exception is raised from the outer-most frame. # This means an unhandled exception. # self.m_frame = frame self.m_event = 'exception' self.m_uef_lineno = self.m_ue_lineno self.m_fUnhandledException = True self.m_core._break(self, frame, event, arg) self.m_uef_lineno = None if frame in self.m_locals_copy: self.update_locals() self.m_frame = None self.m_core.remove_thread(self.m_thread_id) sys.setprofile(None) sys.settrace(self.m_core.trace_dispatch_init) if self.m_frame_external_references == 0: return # # Wait until no one references the frame object # try: self.m_frame_lock.acquire() while self.m_frame_external_references != 0: safe_wait(self.m_frame_lock, 1.0) finally: self.m_frame_lock.release() def frame_acquire(self): """ Aquire a reference to the frame. """ try: self.m_frame_lock.acquire() self.m_frame_external_references += 1 f = self.m_frame if f is None: raise ThreadDone return f finally: self.m_frame_lock.release() def frame_release(self): """ Release a reference to the frame. """ try: self.m_frame_lock.acquire() self.m_frame_external_references -= 1 if self.m_frame_external_references == 0: self.m_frame_lock.notify() finally: self.m_frame_lock.release() def get_frame(self, base_frame, index, fException = False): """ Get frame at index depth down the stack. Starting from base_frame return the index depth frame down the stack. If fException is True use the exception stack (traceback). """ if fException: tb = base_frame.f_exc_traceback if tb is None: raise NoExceptionFound while tb.tb_next is not None: tb = tb.tb_next f = tb.tb_frame else: f = base_frame while f is not None: if not g_fDebug and f.f_code.co_name == 'rpdb2_import_wrapper': f = f.f_back continue if index <= 0: break f = f.f_back index -= 1 if (index < 0) or (f is None): raise InvalidFrame if (self.m_uef_lineno is not None) and (f.f_back is None): lineno = self.m_uef_lineno else: lineno = f.f_lineno if fException: tb = base_frame.f_exc_traceback while tb is not None: if tb.tb_frame == f: lineno = tb.tb_lineno break tb = tb.tb_next return (f, lineno) def get_locals_copy(self, frame_index, fException, fReadOnly): """ Get globals and locals of frame. A copy scheme is used for locals to work around a bug in Python 2.3 and 2.4 that prevents modifying the local dictionary. """ try: base_frame = self.frame_acquire() (f, lineno) = self.get_frame(base_frame, frame_index, fException) if fReadOnly: gc = copy.copy(f.f_globals) else: gc = f.f_globals try: (lc, olc) = self.m_locals_copy[f] except KeyError: if f.f_code.co_name in [MODULE_SCOPE, MODULE_SCOPE2]: lc = gc olc = gc else: lc = copy.copy(f.f_locals) olc = copy.copy(lc) if not fReadOnly: self.m_locals_copy[f] = (lc, olc) self.set_local_trace(f) return (gc, lc, olc) finally: f = None base_frame = None self.frame_release() def update_locals_copy(self): """ Update copy of locals with changes in locals. """ lct = self.m_locals_copy.get(self.m_frame, None) if lct is None: return (lc, base) = lct cr = copy.copy(self.m_frame.f_locals) for k in cr: if not k in base: lc[k] = cr[k] continue if not cr[k] is base[k]: lc[k] = cr[k] def update_locals(self): """ Update locals with changes from copy of locals. """ lct = self.m_locals_copy.pop(self.m_frame, None) if lct is None: return self.m_frame.f_locals.update(lct[0]) def __eval_breakpoint(self, frame, bp): """ Return True if the breakpoint is hit. """ if not bp.m_fEnabled: return False if bp.m_expr == '': return True try: if frame in self.m_locals_copy: l = self.m_locals_copy[frame][0] v = eval(bp.m_code, frame.f_globals, l) else: v = eval(bp.m_code, frame.f_globals, frame.f_locals) return (v != False) except: return False def set_local_trace(self, frame, fsignal_exception = False): """ Set trace callback of frame. Specialized trace methods are selected here to save switching time during actual tracing. """ if not self.m_core.m_ftrace: frame.f_trace = self.trace_dispatch_stop return if fsignal_exception: frame.f_trace = self.trace_dispatch_signal return code_context = self.m_core.get_code_context(frame) if self.m_core.is_break(self, frame): frame.f_trace = self.trace_dispatch_break elif code_context.m_fExceptionTrap or (frame.f_back is None): frame.f_trace = self.trace_dispatch_trap elif frame.f_code.co_name in self.m_bp_manager.m_break_points_by_function: frame.f_trace = self.trace_dispatch elif frame in self.m_locals_copy: frame.f_trace = self.trace_dispatch elif frame == self.m_core.m_return_frame: frame.f_trace = self.trace_dispatch else: del frame.f_trace def set_tracers(self, fsignal_exception = False): """ Set trace callbacks for all frames in stack. """ try: try: f = self.frame_acquire() while f is not None: self.set_local_trace(f, fsignal_exception) f = f.f_back except ThreadDone: f = None finally: f = None self.frame_release() def trace_dispatch_stop(self, frame, event, arg): """ Disable tracing for this thread. """ if frame in self.m_locals_copy: self.update_locals() sys.settrace(None) sys.setprofile(None) return None def trace_dispatch_break(self, frame, event, arg): """ Trace method for breaking a thread. """ if event not in ['line', 'return', 'exception']: return frame.f_trace if event == 'exception': self.set_exc_info(arg) self.m_event = event if frame in self.m_locals_copy: self.update_locals_copy() self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) return frame.f_trace def trace_dispatch_call(self, frame, event, arg): """ Initial trace method for thread. """ if not self.m_core.m_ftrace: return self.trace_dispatch_stop(frame, event, arg) self.m_frame = frame try: self.m_code_context = self.m_core.m_code_contexts[frame.f_code] except KeyError: self.m_code_context = self.m_core.get_code_context(frame) if self.m_core.m_fBreak or (self.m_core.m_step_tid == self.m_thread_id): self.m_event = event self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) return frame.f_trace if not frame.f_code.co_name in self.m_bp_manager.m_break_points_by_function: return None bp = self.m_code_context.m_file_breakpoints.get(frame.f_lineno, None) if bp is not None and self.__eval_breakpoint(frame, bp): self.m_event = event self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) return frame.f_trace return self.trace_dispatch def trace_dispatch(self, frame, event, arg): """ General trace method for thread. """ if (event == 'line'): if frame in self.m_locals_copy: self.update_locals_copy() bp = self.m_code_context.m_file_breakpoints.get(frame.f_lineno, None) if bp is not None and self.__eval_breakpoint(frame, bp): self.m_event = event self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) return frame.f_trace if event == 'return': if frame in self.m_locals_copy: self.update_locals_copy() if frame == self.m_core.m_return_frame: self.m_event = event self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() return None if event == 'exception': if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) if not frame.f_exc_traceback is arg[2]: (frame.f_exc_type, frame.f_exc_value, frame.f_exc_traceback) = arg return frame.f_trace return frame.f_trace def trace_dispatch_trap(self, frame, event, arg): """ Trace method used for frames in which unhandled exceptions should be caught. """ if (event == 'line'): self.m_event = event if frame in self.m_locals_copy: self.update_locals_copy() bp = self.m_code_context.m_file_breakpoints.get(frame.f_lineno, None) if bp is not None and self.__eval_breakpoint(frame, bp): self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) return frame.f_trace if event == 'return': last_event = self.m_event self.m_event = event if frame in self.m_locals_copy: self.update_locals_copy() if frame == self.m_core.m_return_frame: self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() if last_event == 'exception': self.m_event = last_event return None if event == 'exception': self.m_event = event if self.m_code_context.m_fExceptionTrap and self.m_core.m_ftrap: self.set_exc_info(arg) self.m_fUnhandledException = True self.m_core._break(self, frame, event, arg) if frame in self.m_locals_copy: self.update_locals() return frame.f_trace self.m_ue_lineno = frame.f_lineno if frame in self.m_locals_copy: self.update_locals() self.set_local_trace(frame) if not frame.f_exc_traceback is arg[2]: (frame.f_exc_type, frame.f_exc_value, frame.f_exc_traceback) = arg return frame.f_trace return frame.f_trace def trace_dispatch_signal(self, frame, event, arg): #print_debug('*** trace_dispatch_signal %s, %s, %s' % (frame.f_lineno, event, repr(arg))) self.set_exc_info(arg) self.set_tracers() sys.setprofile(self.profile) return self.trace_dispatch_trap(frame, event, arg) def set_exc_info(self, arg): """ Set exception information in frames of stack. """ (t, v, tb) = arg while tb is not None: f = tb.tb_frame f.f_exc_type = t f.f_exc_value = v f.f_exc_traceback = tb tb = tb.tb_next def is_breakpoint(self): """ Calc if current line is hit by breakpoint. """ bp = self.m_code_context.m_file_breakpoints.get(self.m_frame.f_lineno, None) if bp is not None and self.__eval_breakpoint(self.m_frame, bp): return True return False def get_breakpoint(self): """ Return current line breakpoint if any. """ return self.m_code_context.m_file_breakpoints.get(self.m_frame.f_lineno, None) class CDebuggerCore: """ Base class for the debugger. Handles basic debugger functionality. """ def __init__(self, fembedded = False): self.m_ftrace = True self.m_current_ctx = None self.m_f_first_to_break = True self.m_f_break_on_init = False self.m_builtins_hack = None self.m_timer_embedded_giveup = None self.m_threads_lock = threading.Condition() self.m_threads = {} self.m_event_dispatcher = CEventDispatcher() self.m_state_manager = CStateManager(STATE_RUNNING, self.m_event_dispatcher) self.m_ffork_into_child = False self.m_ffork_auto = False self.m_fsynchronicity = True self.m_ftrap = True self.m_fUnhandledException = False self.m_fBreak = False self.m_lastest_event = None self.m_step_tid = None self.m_next_frame = None self.m_return_frame = None self.m_saved_step = (None, None, None) self.m_saved_next = None self.m_bp_manager = CBreakPointsManager() self.m_code_contexts = {None: None} self.m_fembedded = fembedded self.m_embedded_event = threading.Event() self.m_embedded_sync_t0 = 0 self.m_embedded_sync_t1 = 0 self.m_heartbeats = {0: time.time() + 3600} def shutdown(self): self.m_event_dispatcher.shutdown() self.m_state_manager.shutdown() def is_embedded(self): return self.m_fembedded def send_fork_switch(self, sync_n): """ Notify client that debuggee is forking and that it should try to reconnect to the child. """ print_debug('Sending fork switch event') event = CEventForkSwitch(sync_n) self.m_event_dispatcher.fire_event(event) def send_exec_switch(self, sync_n): """ Notify client that debuggee is doing an exec and that it should try to reconnect (in case the exec failed). """ print_debug('Sending exec switch event') event = CEventExecSwitch(sync_n) self.m_event_dispatcher.fire_event(event) def send_event_exit(self): """ Notify client that the debuggee is shutting down. """ event = CEventExit() self.m_event_dispatcher.fire_event(event) def send_events(self, event): pass def set_request_go_timer(self, timeout): """ Set timeout thread to release debugger from waiting for a client to attach. """ self.cancel_request_go_timer() if timeout is None: return _timeout = max(1.0, timeout) f = lambda: ( self.record_client_heartbeat(0, False, True), self.request_go() ) self.m_timer_embedded_giveup = threading.Timer(_timeout, f) self.m_timer_embedded_giveup.start() # # sleep() releases control and allow timer thread to actually start # before this scope returns. # time.sleep(0.1) def cancel_request_go_timer(self): t = self.m_timer_embedded_giveup if t is not None: self.m_timer_embedded_giveup = None t.cancel() def setbreak(self, f): """ Set thread to break on next statement. """ if not self.m_ftrace: return tid = thread.get_ident() if not tid in self.m_threads: return self.settrace(f) ctx = self.m_threads[tid] f.f_trace = ctx.trace_dispatch_break self.m_saved_next = self.m_next_frame self.m_next_frame = f def settrace(self, f = None, f_break_on_init = True, timeout = None, builtins_hack = None): """ Start tracing mechanism for thread. """ if not self.m_ftrace: return tid = thread.get_ident() if tid in self.m_threads: return self.set_request_go_timer(timeout) self.m_f_break_on_init = f_break_on_init self.m_builtins_hack = builtins_hack threading.settrace(self.trace_dispatch_init) sys.settrace(self.trace_dispatch_init) if f is not None: f.f_trace = self.trace_dispatch_init def stoptrace(self): """ Stop tracing mechanism. """ global g_fignore_atexit g_fignore_atexit = True threading.settrace(None) sys.settrace(None) sys.setprofile(None) self.m_ftrace = False self.set_all_tracers() try: self.request_go() except DebuggerNotBroken: pass #self.m_threads = {} def get_code_context(self, frame): try: return self.m_code_contexts[frame.f_code] except KeyError: if self.m_builtins_hack != None: if calc_frame_path(frame) == self.m_builtins_hack: self.m_builtins_hack = None frame.f_globals['__builtins__'] = g_builtins_module code_context = CCodeContext(frame, self.m_bp_manager) return self.m_code_contexts.setdefault(frame.f_code, code_context) def get_current_ctx(self): if len(self.m_threads) == 0: raise NoThreads return self.m_current_ctx def get_ctx(self, tid): ctx = self.m_threads.get(tid, None) if ctx == None: raise ThreadNotFound return ctx def wait_for_first_thread(self): """ Wait until at least one debuggee thread is alive. Python can have 0 threads in some circumstances as embedded Python and the Python interpreter console. """ if self.m_current_ctx is not None: return try: self.m_threads_lock.acquire() while self.m_current_ctx is None: safe_wait(self.m_threads_lock, 1.0) finally: self.m_threads_lock.release() def notify_first_thread(self): """ Notify that first thread is available for tracing. """ try: self.m_threads_lock.acquire() self.m_threads_lock.notify() finally: self.m_threads_lock.release() def set_exception_trap_frame(self, frame): """ Set trap for unhandled exceptions in relevant frame. """ while frame is not None: code_context = self.get_code_context(frame) if code_context.is_exception_trap_frame(): code_context.m_fExceptionTrap = True return frame = frame.f_back def __set_signal_handler(self): """ Set rpdb2 to wrap all signal handlers. """ for key, value in list(vars(signal).items()): if not key.startswith('SIG') or key in ['SIG_IGN', 'SIG_DFL', 'SIGRTMIN', 'SIGRTMAX']: continue handler = signal.getsignal(value) if handler in [signal.SIG_IGN, signal.SIG_DFL]: continue try: signal.signal(value, handler) except: print_debug('Failed to set signal handler for signal %s(%d)' % (key, value)) def clear_source_cache(self): g_lines_cache.clear() event = CEventClearSourceCache() self.m_event_dispatcher.fire_event(event) def trace_dispatch_init(self, frame, event, arg): """ Initial tracing method. """ if event not in ['call', 'line', 'return']: return None code_context = self.get_code_context(frame) if event == 'call' and code_context.is_untraced(): return None self.set_exception_trap_frame(frame) try: t = threading.currentThread() name = t.getName() except: name = '' if name == 'MainThread': self.__set_signal_handler() ctx = CDebuggerCoreThread(name, self, frame, event) ctx.set_tracers() try: self.m_threads_lock.acquire() self.m_threads[ctx.m_thread_id] = ctx nthreads = len(self.m_threads) if nthreads == 1: self.prepare_embedded_sync() finally: self.m_threads_lock.release() if nthreads == 1: self.clear_source_cache() self.m_current_ctx = ctx self.notify_first_thread() if self.m_f_break_on_init: self.m_f_break_on_init = False self.request_break() sys.settrace(ctx.trace_dispatch_call) sys.setprofile(ctx.profile) self.wait_embedded_sync(nthreads == 1) if event == 'call': return ctx.trace_dispatch_call(frame, event, arg) elif hasattr(frame, 'f_trace') and (frame.f_trace is not None): return frame.f_trace(frame, event, arg) else: return None def prepare_embedded_sync(self): if not self.m_fembedded: return t = time.time() t0 = self.m_embedded_sync_t0 if t0 != 0: self.fix_heartbeats(t - t0) if self.get_clients_attached() == 0: return if t - t0 < EMBEDDED_SYNC_THRESHOLD: return self.m_embedded_sync_t1 = t self.m_embedded_event.clear() def wait_embedded_sync(self, ftrigger): if not self.m_fembedded: return t = time.time() t0 = self.m_embedded_sync_t0 t1 = self.m_embedded_sync_t1 if t - t0 < EMBEDDED_SYNC_THRESHOLD: return if t - t1 >= EMBEDDED_SYNC_TIMEOUT: return if ftrigger: event = CEventEmbeddedSync() self.m_event_dispatcher.fire_event(event) safe_wait(self.m_embedded_event, EMBEDDED_SYNC_TIMEOUT - (t - t1)) if ftrigger: self.m_embedded_sync_t1 = 0 def embedded_sync(self): self.m_embedded_event.set() def set_all_tracers(self): """ Set trace methods for all frames of all threads. """ for ctx in list(self.m_threads.values()): ctx.set_tracers() def remove_thread(self, thread_id): try: del self.m_threads[thread_id] if self.m_current_ctx.m_thread_id == thread_id: self.m_current_ctx = list(self.m_threads.values())[0] except (KeyError, IndexError): self.m_embedded_sync_t0 = time.time() def set_break_flag(self): self.m_fBreak = (self.m_state_manager.get_state() == STATE_BROKEN) def is_break(self, ctx, frame, event = None): if self.m_fBreak: return True if ctx.m_fUnhandledException: return True if self.m_step_tid == ctx.m_thread_id: return True if self.m_next_frame == frame: return True if (self.m_return_frame == frame) and (event == 'return'): return True return False def record_client_heartbeat(self, id, finit, fdetach): """ Record that client id is still attached. """ if finit: self.m_heartbeats.pop(0, None) if fdetach: self.m_heartbeats.pop(id, None) return if finit or id in self.m_heartbeats: self.m_heartbeats[id] = time.time() def fix_heartbeats(self, missing_pulse): for k, v in list(self.m_heartbeats.items()): self.m_heartbeats[k] = v + missing_pulse def get_clients_attached(self): n = 0 t = time.time() for v in list(self.m_heartbeats.values()): if t < v + HEARTBEAT_TIMEOUT: n += 1 return n def is_waiting_for_attach(self): if self.get_clients_attached() != 1: return False if list(self.m_heartbeats.keys()) != [0]: return False return True def _break(self, ctx, frame, event, arg): """ Main break logic. """ global g_fos_exit global g_module_main if not self.is_break(ctx, frame, event) and not ctx.is_breakpoint(): ctx.set_tracers() return ctx.m_fBroken = True f_full_notification = False f_uhe_notification = False step_tid = self.m_step_tid try: self.m_state_manager.acquire() if self.m_state_manager.get_state() != STATE_BROKEN: self.set_break_dont_lock() if g_module_main == -1: try: g_module_main = sys.modules['__main__'] except: g_module_main = None if not frame.f_exc_traceback is None: ctx.set_exc_info((frame.f_exc_type, frame.f_exc_value, frame.f_exc_traceback)) try: t = threading.currentThread() ctx.m_thread_name = t.getName() except: pass if ctx.m_fUnhandledException and not self.m_fUnhandledException: self.m_fUnhandledException = True f_uhe_notification = True if self.is_auto_fork_first_stage(ctx.m_thread_id): self.m_saved_step = (self.m_step_tid, self.m_saved_next, self.m_return_frame) self.m_saved_next = None self.m_bp_manager.m_fhard_tbp = True if self.m_f_first_to_break or (self.m_current_ctx == ctx): self.m_current_ctx = ctx self.m_lastest_event = event self.m_step_tid = None self.m_next_frame = None self.m_return_frame = None self.m_saved_next = None self.m_bp_manager.del_temp_breakpoint(breakpoint = ctx.get_breakpoint()) self.m_f_first_to_break = False f_full_notification = True finally: self.m_state_manager.release() ffork_second_stage = self.handle_fork(ctx) self.handle_exec(ctx) if self.is_auto_fork_first_stage(ctx.m_thread_id): self.request_go_quiet() elif self.m_ffork_auto and ffork_second_stage: (self.m_step_tid, self.m_next_frame, self.m_return_frame) = self.m_saved_step self.m_saved_step = (None, None, None) self.m_bp_manager.m_fhard_tbp = False self.request_go_quiet() elif self.get_clients_attached() == 0: #print_debug('state: %s' % self.m_state_manager.get_state()) self.request_go_quiet() elif step_tid == ctx.m_thread_id and frame.f_code.co_name == 'rpdb2_import_wrapper': self.request_step_quiet() else: if f_full_notification: self.send_events(None) else: self.notify_thread_broken(ctx.m_thread_id, ctx.m_thread_name) self.notify_namespace() if f_uhe_notification: self.send_unhandled_exception_event() state = self.m_state_manager.wait_for_state([STATE_RUNNING]) self.prepare_fork_step(ctx.m_thread_id) self.prepare_exec_step(ctx.m_thread_id) ctx.m_fUnhandledException = False ctx.m_fBroken = False ctx.set_tracers() if g_fos_exit: g_fos_exit = False self.send_event_exit() time.sleep(1.0) def is_auto_fork_first_stage(self, tid): if not self.m_ffork_auto: return False return tid == g_forktid and g_forkpid == None def prepare_fork_step(self, tid): global g_forkpid global g_ignore_broken_pipe if tid != g_forktid: return self.m_step_tid = tid g_forkpid = os.getpid() if not self.m_ffork_into_child: return n = self.get_clients_attached() self.send_fork_switch(n) time.sleep(0.5) g_server.shutdown() CThread.joinAll() g_ignore_broken_pipe = time.time() def handle_fork(self, ctx): global g_forktid global g_forkpid tid = ctx.m_thread_id if g_forkpid == None or tid != g_forktid: return False forkpid = g_forkpid g_forkpid = None g_forktid = None if os.getpid() == forkpid: # # Parent side of fork(). # if not self.m_ffork_into_child: #CThread.clearJoin() #g_server.jumpstart() return True self.stoptrace() return False # # Child side of fork(). # if not self.m_ffork_into_child: self.stoptrace() return False self.m_threads = {tid: ctx} CThread.clearJoin() g_server.jumpstart() return True def prepare_exec_step(self, tid): global g_execpid if tid != g_exectid: return self.m_step_tid = tid g_execpid = os.getpid() n = self.get_clients_attached() self.send_exec_switch(n) time.sleep(0.5) g_server.shutdown() CThread.joinAll() def handle_exec(self, ctx): global g_exectid global g_execpid tid = ctx.m_thread_id if g_execpid == None or tid != g_exectid: return False g_execpid = None g_exectid = None # # If we are here it means that the exec failed. # Jumpstart the debugger to allow debugging to continue. # CThread.clearJoin() g_server.jumpstart() return True def notify_thread_broken(self, tid, name): """ Notify that thread (tid) has broken. This notification is sent for each thread that breaks after the first one. """ _event = CEventThreadBroken(tid, name) self.m_event_dispatcher.fire_event(_event) def notify_namespace(self): """ Notify that a namespace update query should be done. """ _event = CEventNamespace() self.m_event_dispatcher.fire_event(_event) def get_state(self): return self.m_state_manager.get_state() def verify_broken(self): if self.m_state_manager.get_state() != STATE_BROKEN: raise DebuggerNotBroken def get_current_filename(self, frame_index, fException): """ Return path of sources corresponding to the frame at depth 'frame_index' down the stack of the current thread. """ ctx = self.get_current_ctx() try: f = None base_frame = ctx.frame_acquire() (f, frame_lineno) = ctx.get_frame(base_frame, frame_index, fException) frame_filename = calc_frame_path(f) return frame_filename finally: f = None base_frame = None ctx.frame_release() def get_threads(self): return self.m_threads def set_break_dont_lock(self): self.m_f_first_to_break = True self.m_state_manager.set_state(STATE_BROKEN, fLock = False) self.set_break_flag() self.set_all_tracers() def request_break(self): """ Ask debugger to break (pause debuggee). """ if len(self.m_threads) == 0: self.wait_for_first_thread() try: self.m_state_manager.acquire() if self.m_state_manager.get_state() == STATE_BROKEN: return self.set_break_dont_lock() finally: self.m_state_manager.release() self.send_events(None) def request_go_quiet(self, fLock = True): try: self.request_go(fLock) except DebuggerNotBroken: pass def request_go(self, fLock = True): """ Let debugger run. """ try: if fLock: self.m_state_manager.acquire() self.verify_broken() self.m_fUnhandledException = False self.m_state_manager.set_state(STATE_RUNNING, fLock = False) if self.m_fembedded: time.sleep(0.33) self.set_break_flag() finally: if fLock: self.m_state_manager.release() def request_go_breakpoint(self, filename, scope, lineno, frame_index, fException): """ Let debugger run until temp breakpoint as defined in the arguments. """ assert(is_unicode(filename)) assert(is_unicode(scope)) try: self.m_state_manager.acquire() self.verify_broken() if filename in [None, '']: _filename = self.get_current_filename(frame_index, fException) elif not is_provider_filesystem(filename): _filename = as_string(filename, sys.getfilesystemencoding()) else: _filename = FindFile(filename, fModules = True) self.m_bp_manager.set_temp_breakpoint(_filename, scope, lineno) self.set_all_tracers() self.request_go(fLock = False) finally: self.m_state_manager.release() def request_step_quiet(self, fLock = True): try: self.request_step(fLock) except DebuggerNotBroken: pass def request_step(self, fLock = True): """ Let debugger run until next statement is reached or a breakpoint is hit in another thread. """ try: if fLock: self.m_state_manager.acquire() self.verify_broken() try: ctx = self.get_current_ctx() except NoThreads: return self.m_step_tid = ctx.m_thread_id self.m_next_frame = None self.m_return_frame = None self.request_go(fLock = False) finally: if fLock: self.m_state_manager.release() def request_next(self): """ Let debugger run until next statement in the same frame is reached or a breakpoint is hit in another thread. """ try: self.m_state_manager.acquire() self.verify_broken() try: ctx = self.get_current_ctx() except NoThreads: return if self.m_lastest_event in ['return', 'exception']: return self.request_step(fLock = False) self.m_next_frame = ctx.m_frame self.m_return_frame = None self.request_go(fLock = False) finally: self.m_state_manager.release() def request_return(self): """ Let debugger run until end of frame frame is reached or a breakpoint is hit in another thread. """ try: self.m_state_manager.acquire() self.verify_broken() try: ctx = self.get_current_ctx() except NoThreads: return if self.m_lastest_event == 'return': return self.request_step(fLock = False) self.m_next_frame = None self.m_return_frame = ctx.m_frame self.request_go(fLock = False) finally: self.m_state_manager.release() def request_jump(self, lineno): """ Jump to line number 'lineno'. """ try: self.m_state_manager.acquire() self.verify_broken() try: ctx = self.get_current_ctx() except NoThreads: return frame = ctx.m_frame code = frame.f_code valid_lines = CalcValidLines(code) sbi = CScopeBreakInfo(as_unicode(''), valid_lines) l = sbi.CalcScopeLine(lineno) frame.f_lineno = l finally: frame = None self.m_state_manager.release() self.send_events(None) def set_thread(self, tid): """ Switch focus to specified thread. """ try: self.m_state_manager.acquire() self.verify_broken() try: if (tid >= 0) and (tid < 100): _tid = list(self.m_threads.keys())[tid] else: _tid = tid ctx = self.m_threads[_tid] except (IndexError, KeyError): raise ThreadNotFound self.m_current_ctx = ctx self.m_lastest_event = ctx.m_event finally: self.m_state_manager.release() self.send_events(None) class CDebuggerEngine(CDebuggerCore): """ Main class for the debugger. Adds functionality on top of CDebuggerCore. """ def __init__(self, fembedded = False): CDebuggerCore.__init__(self, fembedded) event_type_dict = { CEventState: {}, CEventStackDepth: {}, CEventBreakpoint: {}, CEventThreads: {}, CEventNoThreads: {}, CEventThreadBroken: {}, CEventNamespace: {}, CEventUnhandledException: {}, CEventStack: {}, CEventNull: {}, CEventExit: {}, CEventForkSwitch: {}, CEventExecSwitch: {}, CEventSynchronicity: {}, CEventTrap: {}, CEventForkMode: {}, CEventPsycoWarning: {}, CEventConflictingModules: {}, CEventSignalIntercepted: {}, CEventSignalException: {}, CEventClearSourceCache: {}, CEventEmbeddedSync: {} } self.m_event_queue = CEventQueue(self.m_event_dispatcher) self.m_event_queue.register_event_types(event_type_dict) event_type_dict = {CEventSync: {}} self.m_event_dispatcher.register_callback(self.send_events, event_type_dict, fSingleUse = False) def shutdown(self): self.m_event_queue.shutdown() CDebuggerCore.shutdown(self) def sync_with_events(self, fException, fSendUnhandled): """ Send debugger state to client. """ if len(self.m_threads) == 0: self.wait_for_first_thread() index = self.m_event_queue.get_event_index() event = CEventSync(fException, fSendUnhandled) self.m_event_dispatcher.fire_event(event) return index def trap_conflicting_modules(self): modules_list = [] for m in CONFLICTING_MODULES: if m in g_found_conflicting_modules: continue if not m in sys.modules: continue if m == 'psyco': # # Old event kept for compatibility. # event = CEventPsycoWarning() self.m_event_dispatcher.fire_event(event) g_found_conflicting_modules.append(m) modules_list.append(as_unicode(m)) if modules_list == []: return False event = CEventConflictingModules(modules_list) self.m_event_dispatcher.fire_event(event) return True def wait_for_event(self, timeout, event_index): """ Wait for new events and return them as list of events. """ self.cancel_request_go_timer() self.trap_conflicting_modules() (new_event_index, sel) = self.m_event_queue.wait_for_event(timeout, event_index) if self.trap_conflicting_modules(): (new_event_index, sel) = self.m_event_queue.wait_for_event(timeout, event_index) return (new_event_index, sel) def set_breakpoint(self, filename, scope, lineno, fEnabled, expr, frame_index, fException, encoding): print_debug('Setting breakpoint to: %s, %s, %d' % (repr(filename), scope, lineno)) assert(is_unicode(filename)) assert(is_unicode(scope)) assert(is_unicode(expr)) fLock = False try: if filename in [None, '']: self.m_state_manager.acquire() fLock = True self.verify_broken() _filename = self.get_current_filename(frame_index, fException) elif not is_provider_filesystem(filename): _filename = as_string(filename, sys.getfilesystemencoding()) else: _filename = FindFile(filename, fModules = True) if expr != '': try: encoding = self.__calc_encoding(encoding, filename = _filename) _expr = as_bytes(ENCODING_SOURCE % encoding + expr, encoding) compile(_expr, '', 'eval') except: raise SyntaxError encoding = as_unicode(encoding) bp = self.m_bp_manager.set_breakpoint(_filename, scope, lineno, fEnabled, expr, encoding) self.set_all_tracers() event = CEventBreakpoint(bp) #print_debug(repr(vars(bp))) self.m_event_dispatcher.fire_event(event) finally: if fLock: self.m_state_manager.release() def disable_breakpoint(self, id_list, fAll): self.m_bp_manager.disable_breakpoint(id_list, fAll) self.set_all_tracers() event = CEventBreakpoint(None, CEventBreakpoint.DISABLE, id_list, fAll) self.m_event_dispatcher.fire_event(event) def enable_breakpoint(self, id_list, fAll): self.m_bp_manager.enable_breakpoint(id_list, fAll) self.set_all_tracers() event = CEventBreakpoint(None, CEventBreakpoint.ENABLE, id_list, fAll) self.m_event_dispatcher.fire_event(event) def delete_breakpoint(self, id_list, fAll): self.m_bp_manager.delete_breakpoint(id_list, fAll) self.set_all_tracers() event = CEventBreakpoint(None, CEventBreakpoint.REMOVE, id_list, fAll) self.m_event_dispatcher.fire_event(event) def get_breakpoints(self): """ return id->breakpoint dictionary. """ bpl = self.m_bp_manager.get_breakpoints() _items = [(id, breakpoint_copy(bp)) for (id, bp) in bpl.items()] for (id, bp) in _items: bp.m_code = None _bpl = dict(_items) return _bpl def send_events(self, event): """ Send series of events that define the debugger state. """ if isinstance(event, CEventSync): fException = event.m_fException fSendUnhandled = event.m_fSendUnhandled else: fException = False fSendUnhandled = False try: if isinstance(event, CEventSync) and not fException: self.m_state_manager.set_state() self.send_stack_depth() self.send_threads_event(fException) self.send_stack_event(fException) self.send_namespace_event() if fSendUnhandled and self.m_fUnhandledException: self.send_unhandled_exception_event() except NoThreads: self.send_no_threads_event() except: print_debug_exception() raise def send_unhandled_exception_event(self): event = CEventUnhandledException() self.m_event_dispatcher.fire_event(event) def send_stack_depth(self): """ Send event with stack depth and exception stack depth. """ ctx = self.get_current_ctx() try: try: f = None f = ctx.frame_acquire() except ThreadDone: return try: g_traceback_lock.acquire() s = traceback.extract_stack(f) s = [1 for (a, b, c, d) in s if g_fDebug or c != 'rpdb2_import_wrapper'] finally: g_traceback_lock.release() stack_depth = len(s) if f.f_exc_traceback is None: stack_depth_exception = None else: try: g_traceback_lock.acquire() _s = traceback.extract_tb(f.f_exc_traceback) _s = [1 for (a, b, c, d) in _s if g_fDebug or c != 'rpdb2_import_wrapper'] finally: g_traceback_lock.release() stack_depth_exception = stack_depth + len(_s) - 1 event = CEventStackDepth(stack_depth, stack_depth_exception) self.m_event_dispatcher.fire_event(event) finally: f = None ctx.frame_release() def send_threads_event(self, fException): """ Send event with current thread list. In case of exception, send only the current thread. """ tl = self.get_thread_list() if fException: ctid = tl[0] itl = tl[1] _itl = [a for a in itl if a[DICT_KEY_TID] == ctid] _tl = (ctid, _itl) else: _tl = tl event = CEventThreads(*_tl) self.m_event_dispatcher.fire_event(event) def send_stack_event(self, fException): sl = self.get_stack([], False, fException) if len(sl) == 0: return event = CEventStack(sl[0]) self.m_event_dispatcher.fire_event(event) def send_namespace_event(self): """ Send event notifying namespace should be queried again. """ event = CEventNamespace() self.m_event_dispatcher.fire_event(event) def send_no_threads_event(self): _event = CEventNoThreads() self.m_event_dispatcher.fire_event(_event) def send_event_null(self): """ Make the event waiter return. """ event = CEventNull() self.m_event_dispatcher.fire_event(event) def __get_stack(self, ctx, ctid, fException): tid = ctx.m_thread_id try: try: f = None f = ctx.frame_acquire() except ThreadDone: return None _f = f try: g_traceback_lock.acquire() s = my_extract_stack(f) finally: g_traceback_lock.release() if fException: if f.f_exc_traceback is None: raise NoExceptionFound _tb = f.f_exc_traceback while _tb.tb_next is not None: _tb = _tb.tb_next _f = _tb.tb_frame try: g_traceback_lock.acquire() _s = my_extract_tb(f.f_exc_traceback) finally: g_traceback_lock.release() s = s[:-1] + _s code_list = [] while _f is not None: rc = repr(_f.f_code).split(',')[0].split()[-1] rc = as_unicode(rc) code_list.insert(0, rc) _f = _f.f_back finally: f = None _f = None ctx.frame_release() #print code_list __s = [(a, b, c, d) for (a, b, c, d) in s if g_fDebug or c != 'rpdb2_import_wrapper'] if (ctx.m_uef_lineno is not None) and (len(__s) > 0): (a, b, c, d) = __s[0] __s = [(a, ctx.m_uef_lineno, c, d)] + __s[1:] r = {} r[DICT_KEY_STACK] = __s r[DICT_KEY_CODE_LIST] = code_list r[DICT_KEY_TID] = tid r[DICT_KEY_BROKEN] = ctx.m_fBroken r[DICT_KEY_EVENT] = as_unicode(ctx.m_event) if tid == ctid: r[DICT_KEY_CURRENT_TID] = True return r def get_stack(self, tid_list, fAll, fException): if fException and (fAll or (len(tid_list) != 0)): raise BadArgument ctx = self.get_current_ctx() ctid = ctx.m_thread_id if fAll: ctx_list = list(self.get_threads().values()) elif fException or (len(tid_list) == 0): ctx_list = [ctx] else: ctx_list = [self.get_threads().get(t, None) for t in tid_list] _sl = [self.__get_stack(ctx, ctid, fException) for ctx in ctx_list if ctx is not None] sl = [s for s in _sl if s is not None] return sl def get_source_file(self, filename, lineno, nlines, frame_index, fException): assert(is_unicode(filename)) if lineno < 1: lineno = 1 nlines = -1 _lineno = lineno r = {} frame_filename = None try: ctx = self.get_current_ctx() try: f = None base_frame = None base_frame = ctx.frame_acquire() (f, frame_lineno) = ctx.get_frame(base_frame, frame_index, fException) frame_filename = calc_frame_path(f) finally: f = None base_frame = None ctx.frame_release() frame_event = [[ctx.m_event, 'call'][frame_index > 0], 'exception'][fException] except NoThreads: if filename in [None, '']: raise if filename in [None, '']: __filename = frame_filename r[DICT_KEY_TID] = ctx.m_thread_id elif not is_provider_filesystem(filename): __filename = as_string(filename, sys.getfilesystemencoding()) else: __filename = FindFile(filename, fModules = True) if not IsPythonSourceFile(__filename): raise NotPythonSource _filename = winlower(__filename) lines = [] breakpoints = {} fhide_pwd_mode = False while nlines != 0: try: g_traceback_lock.acquire() line = get_source_line(_filename, _lineno) finally: g_traceback_lock.release() if line == '': break # # Remove any trace of session password from data structures that # go over the network. # if fhide_pwd_mode: if not ')' in line: line = as_unicode('...\n') else: line = '...""")' + line.split(')', 1)[1] fhide_pwd_mode = False elif 'start_embedded_debugger(' in line: ls = line.split('start_embedded_debugger(', 1) line = ls[0] + 'start_embedded_debugger("""...Removed-password-from-output...' if ')' in ls[1]: line += '""")' + ls[1].split(')', 1)[1] else: line += '\n' fhide_pwd_mode = True lines.append(line) try: bp = self.m_bp_manager.get_breakpoint(_filename, _lineno) breakpoints[_lineno] = as_unicode([STATE_DISABLED, STATE_ENABLED][bp.isEnabled()]) except KeyError: pass _lineno += 1 nlines -= 1 if frame_filename == _filename: r[DICT_KEY_FRAME_LINENO] = frame_lineno r[DICT_KEY_EVENT] = as_unicode(frame_event) r[DICT_KEY_BROKEN] = ctx.m_fBroken r[DICT_KEY_LINES] = lines r[DICT_KEY_FILENAME] = as_unicode(_filename, sys.getfilesystemencoding()) r[DICT_KEY_BREAKPOINTS] = breakpoints r[DICT_KEY_FIRST_LINENO] = lineno return r def __get_source(self, ctx, nlines, frame_index, fException): tid = ctx.m_thread_id _frame_index = [0, frame_index][tid == self.m_current_ctx.m_thread_id] try: try: f = None base_frame = None base_frame = ctx.frame_acquire() (f, frame_lineno) = ctx.get_frame(base_frame, _frame_index, fException) frame_filename = calc_frame_path(f) except (ThreadDone, InvalidFrame): return None finally: f = None base_frame = None ctx.frame_release() frame_event = [[ctx.m_event, 'call'][frame_index > 0], 'exception'][fException] first_line = max(1, frame_lineno - nlines // 2) _lineno = first_line lines = [] breakpoints = {} fhide_pwd_mode = False while nlines != 0: try: g_traceback_lock.acquire() line = get_source_line(frame_filename, _lineno) finally: g_traceback_lock.release() if line == '': break # # Remove any trace of session password from data structures that # go over the network. # if fhide_pwd_mode: if not ')' in line: line = as_unicode('...\n') else: line = '...""")' + line.split(')', 1)[1] fhide_pwd_mode = False elif 'start_embedded_debugger(' in line: ls = line.split('start_embedded_debugger(', 1) line = ls[0] + 'start_embedded_debugger("""...Removed-password-from-output...' if ')' in ls[1]: line += '""")' + ls[1].split(')', 1)[1] else: line += '\n' fhide_pwd_mode = True lines.append(line) try: bp = self.m_bp_manager.get_breakpoint(frame_filename, _lineno) breakpoints[_lineno] = as_unicode([STATE_DISABLED, STATE_ENABLED][bp.isEnabled()]) except KeyError: pass _lineno += 1 nlines -= 1 r = {} r[DICT_KEY_FRAME_LINENO] = frame_lineno r[DICT_KEY_EVENT] = as_unicode(frame_event) r[DICT_KEY_BROKEN] = ctx.m_fBroken r[DICT_KEY_TID] = tid r[DICT_KEY_LINES] = lines r[DICT_KEY_FILENAME] = as_unicode(frame_filename, sys.getfilesystemencoding()) r[DICT_KEY_BREAKPOINTS] = breakpoints r[DICT_KEY_FIRST_LINENO] = first_line return r def get_source_lines(self, nlines, fAll, frame_index, fException): if fException and fAll: raise BadArgument if fAll: ctx_list = list(self.get_threads().values()) else: ctx = self.get_current_ctx() ctx_list = [ctx] _sl = [self.__get_source(ctx, nlines, frame_index, fException) for ctx in ctx_list] sl = [s for s in _sl if s is not None] return sl def __get_locals_globals(self, frame_index, fException, fReadOnly = False): ctx = self.get_current_ctx() (_globals, _locals, _original_locals_copy) = ctx.get_locals_copy(frame_index, fException, fReadOnly) return (_globals, _locals, _original_locals_copy) def __calc_number_of_subnodes(self, r): if parse_type(type(r)) in BASIC_TYPES_LIST: return 0 try: try: if isinstance(r, frozenset) or isinstance(r, set): return len(r) except NameError: pass if isinstance(r, sets.BaseSet): return len(r) if isinstance(r, dict): return len(r) if isinstance(r, list): return len(r) if isinstance(r, tuple): return len(r) if hasattr(r, '__class__') or hasattr(r, '__bases__'): return 1 except AttributeError: return 0 return 0 def __calc_subnodes(self, expr, r, fForceNames, filter_level, repr_limit, encoding): snl = [] try: if isinstance(r, frozenset) or isinstance(r, set): if len(r) > MAX_SORTABLE_LENGTH: g = r else: g = [i for i in r] g.sort(SafeCmp) for i in g: if len(snl) >= MAX_NAMESPACE_ITEMS: snl.append(MAX_NAMESPACE_WARNING) break is_valid = [True] rk = repr_ltd(i, REPR_ID_LENGTH, encoding = ENCODING_RAW_I) e = {} e[DICT_KEY_EXPR] = as_unicode('_RPDB2_FindRepr((%s), %d)["%s"]' % (expr, REPR_ID_LENGTH, rk.replace('"', '"'))) e[DICT_KEY_NAME] = repr_ltd(i, repr_limit, encoding) e[DICT_KEY_REPR] = repr_ltd(i, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(i))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(i) snl.append(e) return snl except NameError: pass if isinstance(r, sets.BaseSet): if len(r) > MAX_SORTABLE_LENGTH: g = r else: g = [i for i in r] g.sort(SafeCmp) for i in g: if len(snl) >= MAX_NAMESPACE_ITEMS: snl.append(MAX_NAMESPACE_WARNING) break is_valid = [True] rk = repr_ltd(i, REPR_ID_LENGTH, encoding = ENCODING_RAW_I) e = {} e[DICT_KEY_EXPR] = as_unicode('_RPDB2_FindRepr((%s), %d)["%s"]' % (expr, REPR_ID_LENGTH, rk.replace('"', '"'))) e[DICT_KEY_NAME] = repr_ltd(i, repr_limit, encoding) e[DICT_KEY_REPR] = repr_ltd(i, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(i))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(i) snl.append(e) return snl if isinstance(r, list) or isinstance(r, tuple): for i, v in enumerate(r[0: MAX_NAMESPACE_ITEMS]): is_valid = [True] e = {} e[DICT_KEY_EXPR] = as_unicode('(%s)[%d]' % (expr, i)) e[DICT_KEY_NAME] = as_unicode(repr(i)) e[DICT_KEY_REPR] = repr_ltd(v, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(v))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(v) snl.append(e) if len(r) > MAX_NAMESPACE_ITEMS: snl.append(MAX_NAMESPACE_WARNING) return snl if isinstance(r, dict): if filter_level == 2 and expr in ['locals()', 'globals()']: r = copy.copy(r) for k, v in list(r.items()): if parse_type(type(v)) in ['function', 'classobj', 'type']: del r[k] if len(r) > MAX_SORTABLE_LENGTH: kl = r else: kl = list(r.keys()) kl.sort(SafeCmp) for k in kl: # # Remove any trace of session password from data structures that # go over the network. # if k in ['_RPDB2_FindRepr', '_RPDB2_builtins', '_rpdb2_args', '_rpdb2_pwd', 'm_rpdb2_pwd']: continue v = r[k] if len(snl) >= MAX_NAMESPACE_ITEMS: snl.append(MAX_NAMESPACE_WARNING) break is_valid = [True] e = {} if type(k) in [bool, int, float, bytes, str, unicode, type(None)]: rk = repr(k) if len(rk) < REPR_ID_LENGTH: e[DICT_KEY_EXPR] = as_unicode('(%s)[%s]' % (expr, rk)) if type(k) == str8: rk = repr(k) if len(rk) < REPR_ID_LENGTH: e[DICT_KEY_EXPR] = as_unicode('(%s)[str8(%s)]' % (expr, rk[1:])) if not DICT_KEY_EXPR in e: rk = repr_ltd(k, REPR_ID_LENGTH, encoding = ENCODING_RAW_I) e[DICT_KEY_EXPR] = as_unicode('_RPDB2_FindRepr((%s), %d)["%s"]' % (expr, REPR_ID_LENGTH, rk.replace('"', '"'))) e[DICT_KEY_NAME] = as_unicode([repr_ltd(k, repr_limit, encoding), k][fForceNames]) e[DICT_KEY_REPR] = repr_ltd(v, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(v))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(v) snl.append(e) return snl al = calc_attribute_list(r, filter_level) al.sort(SafeCmp) for a in al: if a == 'm_rpdb2_pwd': continue try: v = getattr(r, a) except AttributeError: continue if len(snl) >= MAX_NAMESPACE_ITEMS: snl.append(MAX_NAMESPACE_WARNING) break is_valid = [True] e = {} e[DICT_KEY_EXPR] = as_unicode('(%s).%s' % (expr, a)) e[DICT_KEY_NAME] = as_unicode(a) e[DICT_KEY_REPR] = repr_ltd(v, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(v))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(v) snl.append(e) return snl def get_exception(self, frame_index, fException): ctx = self.get_current_ctx() try: f = None base_frame = None base_frame = ctx.frame_acquire() (f, frame_lineno) = ctx.get_frame(base_frame, frame_index, fException) e = {'type': f.f_exc_type, 'value': f.f_exc_value, 'traceback': f.f_exc_traceback} return e finally: f = None base_frame = None ctx.frame_release() def is_child_of_failure(self, failed_expr_list, expr): for failed_expr in failed_expr_list: if expr.startswith(failed_expr): return True return False def calc_expr(self, expr, fExpand, filter_level, frame_index, fException, _globals, _locals, lock, event, rl, index, repr_limit, encoding): e = {} try: __globals = _globals __locals = _locals if RPDB_EXEC_INFO in expr: rpdb_exception_info = self.get_exception(frame_index, fException) __globals = globals() __locals = locals() __locals['_RPDB2_FindRepr'] = _RPDB2_FindRepr is_valid = [True] r = eval(expr, __globals, __locals) e[DICT_KEY_EXPR] = as_unicode(expr) e[DICT_KEY_REPR] = repr_ltd(r, repr_limit, encoding, is_valid) e[DICT_KEY_IS_VALID] = is_valid[0] e[DICT_KEY_TYPE] = as_unicode(parse_type(type(r))) e[DICT_KEY_N_SUBNODES] = self.__calc_number_of_subnodes(r) if fExpand and (e[DICT_KEY_N_SUBNODES] > 0): fForceNames = (expr in ['globals()', 'locals()']) or (RPDB_EXEC_INFO in expr) e[DICT_KEY_SUBNODES] = self.__calc_subnodes(expr, r, fForceNames, filter_level, repr_limit, encoding) e[DICT_KEY_N_SUBNODES] = len(e[DICT_KEY_SUBNODES]) except: print_debug_exception() e[DICT_KEY_ERROR] = as_unicode(safe_repr(sys.exc_info())) lock.acquire() if len(rl) == index: rl.append(e) lock.release() event.set() def __calc_encoding(self, encoding, fvalidate = False, filename = None): if encoding != ENCODING_AUTO and not fvalidate: return encoding if encoding != ENCODING_AUTO: try: codecs.lookup(encoding) return encoding except: pass if filename == None: ctx = self.get_current_ctx() filename = ctx.m_code_context.m_filename try: encoding = get_file_encoding(filename) return encoding except: return 'utf-8' def get_namespace(self, nl, filter_level, frame_index, fException, repr_limit, encoding, fraw): if fraw: encoding = ENCODING_RAW_I else: encoding = self.__calc_encoding(encoding, fvalidate = True) try: (_globals, _locals, x) = self.__get_locals_globals(frame_index, fException, fReadOnly = True) except: print_debug_exception() raise failed_expr_list = [] rl = [] index = 0 lock = threading.Condition() for (expr, fExpand) in nl: if self.is_child_of_failure(failed_expr_list, expr): continue event = threading.Event() args = (expr, fExpand, filter_level, frame_index, fException, _globals, _locals, lock, event, rl, index, repr_limit, encoding) if self.m_fsynchronicity: g_server.m_work_queue.post_work_item(target = self.calc_expr, args = args, name = 'calc_expr %s' % expr) else: try: ctx = self.get_current_ctx() tid = ctx.m_thread_id send_job(tid, 0, self.calc_expr, *args) except: pass safe_wait(event, 2) lock.acquire() if len(rl) == index: rl.append('error') failed_expr_list.append(expr) index += 1 lock.release() if len(failed_expr_list) > 3: break _rl = [r for r in rl if r != 'error'] return _rl def evaluate(self, expr, frame_index, fException, encoding, fraw): """ Evaluate expression in context of frame at depth 'frame-index'. """ result = [(as_unicode(''), as_unicode(STR_SYNCHRONICITY_BAD), as_unicode(''))] if self.m_fsynchronicity: self._evaluate(result, expr, frame_index, fException, encoding, fraw) else: try: ctx = self.get_current_ctx() tid = ctx.m_thread_id send_job(tid, 1000, self._evaluate, result, expr, frame_index, fException, encoding, fraw) except: pass return result[-1] def _evaluate(self, result, expr, frame_index, fException, encoding, fraw): """ Evaluate expression in context of frame at depth 'frame-index'. """ encoding = self.__calc_encoding(encoding) (_globals, _locals, x) = self.__get_locals_globals(frame_index, fException) v = '' w = '' e = '' try: if '_rpdb2_pwd' in expr or '_rpdb2_args' in expr: r = '...Removed-password-from-output...' else: _expr = as_bytes(ENCODING_SOURCE % encoding + expr, encoding, fstrict = True) if '_RPDB2_builtins' in expr: _locals['_RPDB2_builtins'] = vars(g_builtins_module) try: redirect_exc_info = True r = eval(_expr, _globals, _locals) finally: del redirect_exc_info if '_RPDB2_builtins' in expr: del _locals['_RPDB2_builtins'] if fraw: encoding = ENCODING_RAW_I v = repr_ltd(r, MAX_EVALUATE_LENGTH, encoding) if len(v) > MAX_EVALUATE_LENGTH: v += '... *** %s ***' % STR_MAX_EVALUATE_LENGTH_WARNING w = STR_MAX_EVALUATE_LENGTH_WARNING except: exc_info = sys.exc_info() e = "%s, %s" % (safe_str(exc_info[0]), safe_str(exc_info[1])) self.notify_namespace() result.append((as_unicode(v), as_unicode(w), as_unicode(e))) def execute(self, suite, frame_index, fException, encoding): """ Execute suite (Python statement) in context of frame at depth 'frame-index'. """ result = [(as_unicode(STR_SYNCHRONICITY_BAD), as_unicode(''))] if self.m_fsynchronicity: self._execute(result, suite, frame_index, fException, encoding) else: try: ctx = self.get_current_ctx() tid = ctx.m_thread_id send_job(tid, 1000, self._execute, result, suite, frame_index, fException, encoding) except: pass return result[-1] def _execute(self, result, suite, frame_index, fException, encoding): """ Execute suite (Python statement) in context of frame at depth 'frame-index'. """ print_debug('exec called with: ' + repr(suite)) encoding = self.__calc_encoding(encoding) (_globals, _locals, _original_locals_copy) = self.__get_locals_globals(frame_index, fException) if frame_index > 0 and not _globals is _locals: _locals_copy = copy.copy(_locals) w = '' e = '' try: if '_RPDB2_FindRepr' in suite and not '_RPDB2_FindRepr' in _original_locals_copy: _locals['_RPDB2_FindRepr'] = _RPDB2_FindRepr try: _suite = as_bytes(ENCODING_SOURCE % encoding + suite, encoding, fstrict = True) #print_debug('suite is %s' % repr(_suite)) _code = compile(_suite, '', 'exec') try: redirect_exc_info = True exec(_code, _globals, _locals) finally: del redirect_exc_info finally: if '_RPDB2_FindRepr' in suite and not '_RPDB2_FindRepr' in _original_locals_copy: del _locals['_RPDB2_FindRepr'] except: exc_info = sys.exc_info() e = "%s, %s" % (safe_str(exc_info[0]), safe_str(exc_info[1])) if frame_index > 0 and (not _globals is _locals) and _locals != _locals_copy: l = [(k, safe_repr(v)) for k, v in _locals.items()] sl = set(l) lc = [(k, safe_repr(v)) for k, v in _locals_copy.items()] slc = set(lc) nsc = [k for (k, v) in sl - slc if k in _original_locals_copy] if len(nsc) != 0: w = STR_LOCAL_NAMESPACE_WARNING self.notify_namespace() result.append((as_unicode(w), as_unicode(e))) def __decode_thread_name(self, name): name = as_unicode(name) return name def get_thread_list(self): """ Return thread list with tid, state, and last event of each thread. """ ctx = self.get_current_ctx() if ctx is None: current_thread_id = -1 else: current_thread_id = ctx.m_thread_id ctx_list = list(self.get_threads().values()) tl = [] for c in ctx_list: d = {} d[DICT_KEY_TID] = c.m_thread_id d[DICT_KEY_NAME] = self.__decode_thread_name(c.m_thread_name) d[DICT_KEY_BROKEN] = c.m_fBroken d[DICT_KEY_EVENT] = as_unicode(c.m_event) tl.append(d) return (current_thread_id, tl) def stop_debuggee(self): """ Notify the client and terminate this proccess. """ g_server.m_work_queue.post_work_item(target = _atexit, args = (True, ), name = '_atexit') def set_synchronicity(self, fsynchronicity): self.m_fsynchronicity = fsynchronicity event = CEventSynchronicity(fsynchronicity) self.m_event_dispatcher.fire_event(event) if self.m_state_manager.get_state() == STATE_BROKEN: self.notify_namespace() def set_trap_unhandled_exceptions(self, ftrap): self.m_ftrap = ftrap event = CEventTrap(ftrap) self.m_event_dispatcher.fire_event(event) def is_unhandled_exception(self): return self.m_fUnhandledException def set_fork_mode(self, ffork_into_child, ffork_auto): self.m_ffork_into_child = ffork_into_child self.m_ffork_auto = ffork_auto event = CEventForkMode(ffork_into_child, ffork_auto) self.m_event_dispatcher.fire_event(event) def set_environ(self, envmap): global g_fignorefork print_debug('Entered set_environ() with envmap = %s' % repr(envmap)) if len(envmap) == 0: return old_pythonpath = os.environ.get('PYTHONPATH', '') encoding = detect_locale() for k, v in envmap: try: k = as_string(k, encoding, fstrict = True) v = as_string(v, encoding, fstrict = True) except: continue command = 'echo %s' % v try: g_fignorefork = True f = platform.popen(command) finally: g_fignorefork = False value = f.read() f.close() if value[-1:] == '\n': value = value[:-1] os.environ[k] = value if 'PYTHONPATH' in [k for (k, v) in envmap]: recalc_sys_path(old_pythonpath) # # ------------------------------------- RPC Server -------------------------------------------- # class CWorkQueue: """ Worker threads pool mechanism for RPC server. """ def __init__(self, size = N_WORK_QUEUE_THREADS): self.m_lock = threading.Condition() self.m_work_items = [] self.m_f_shutdown = False self.m_size = size self.m_n_threads = 0 self.m_n_available = 0 self.__create_thread() def __create_thread(self): t = CThread(name = '__worker_target', target = self.__worker_target, shutdown = self.shutdown) #t.setDaemon(True) t.start() def shutdown(self): """ Signal worker threads to exit, and wait until they do. """ if self.m_f_shutdown: return print_debug('Shutting down worker queue...') self.m_lock.acquire() self.m_f_shutdown = True self.m_lock.notifyAll() t0 = time.time() while self.m_n_threads > 0: if time.time() - t0 > SHUTDOWN_TIMEOUT: self.m_lock.release() print_debug('Shut down of worker queue has TIMED OUT!') return safe_wait(self.m_lock, 0.1) self.m_lock.release() print_debug('Shutting down worker queue, done.') def __worker_target(self): try: self.m_lock.acquire() self.m_n_threads += 1 self.m_n_available += 1 fcreate_thread = not self.m_f_shutdown and self.m_n_threads < self.m_size self.m_lock.release() if fcreate_thread: self.__create_thread() self.m_lock.acquire() while not self.m_f_shutdown: safe_wait(self.m_lock) if self.m_f_shutdown: break if len(self.m_work_items) == 0: continue fcreate_thread = self.m_n_available == 1 (target, args, name) = self.m_work_items.pop() self.m_n_available -= 1 self.m_lock.release() if fcreate_thread: print_debug('Creating an extra worker thread.') self.__create_thread() threading.currentThread().setName('__worker_target - ' + name) try: target(*args) except: print_debug_exception() threading.currentThread().setName('__worker_target') self.m_lock.acquire() self.m_n_available += 1 if self.m_n_available > self.m_size: break self.m_n_threads -= 1 self.m_n_available -= 1 self.m_lock.notifyAll() finally: self.m_lock.release() def post_work_item(self, target, args, name = ''): if self.m_f_shutdown: return try: self.m_lock.acquire() if self.m_f_shutdown: return self.m_work_items.append((target, args, name)) self.m_lock.notify() finally: self.m_lock.release() # # MOD # class CUnTracedThreadingMixIn(SocketServer.ThreadingMixIn): """ Modification of SocketServer.ThreadingMixIn that uses a worker thread queue instead of spawning threads to process requests. This mod was needed to resolve deadlocks that were generated in some circumstances. """ def process_request(self, request, client_address): g_server.m_work_queue.post_work_item(target = SocketServer.ThreadingMixIn.process_request_thread, args = (self, request, client_address), name = 'process_request') # # MOD # def my_xmlrpclib_loads(data): """ Modification of Python 2.3 xmlrpclib.loads() that does not do an import. Needed to prevent deadlocks. """ p, u = xmlrpclib.getparser() p.feed(data) p.close() return u.close(), u.getmethodname() # # MOD # class CXMLRPCServer(CUnTracedThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer): if os.name == POSIX: allow_reuse_address = True else: allow_reuse_address = False """ Modification of Python 2.3 SimpleXMLRPCServer.SimpleXMLRPCDispatcher that uses my_xmlrpclib_loads(). Needed to prevent deadlocks. """ def __marshaled_dispatch(self, data, dispatch_method = None): params, method = my_xmlrpclib_loads(data) # generate response try: if dispatch_method is not None: response = dispatch_method(method, params) else: response = self._dispatch(method, params) # wrap response in a singleton tuple response = (response,) response = xmlrpclib.dumps(response, methodresponse=1) except xmlrpclib.Fault: fault = sys.exc_info()[1] response = xmlrpclib.dumps(fault) except: # report exception back to server response = xmlrpclib.dumps( xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) ) print_debug_exception() return response if sys.version_info[:2] <= (2, 3): _marshaled_dispatch = __marshaled_dispatch #def server_activate(self): # self.socket.listen(1) def handle_error(self, request, client_address): print_debug("handle_error() in pid %d" % _getpid()) if g_ignore_broken_pipe + 5 > time.time(): return return SimpleXMLRPCServer.SimpleXMLRPCServer.handle_error(self, request, client_address) class CPwdServerProxy: """ Encrypted proxy to the debuggee. Works by wrapping a xmlrpclib.ServerProxy object. """ def __init__(self, crypto, uri, transport = None, target_rid = 0): self.m_crypto = crypto self.m_proxy = xmlrpclib.ServerProxy(uri, transport) self.m_fEncryption = is_encryption_supported() self.m_target_rid = target_rid self.m_method = getattr(self.m_proxy, DISPACHER_METHOD) def __set_encryption(self, fEncryption): self.m_fEncryption = fEncryption def get_encryption(self): return self.m_fEncryption def __request(self, name, params): """ Call debuggee method 'name' with parameters 'params'. """ while True: try: # # Encrypt method and params. # fencrypt = self.get_encryption() args = (as_unicode(name), params, self.m_target_rid) (fcompress, digest, msg) = self.m_crypto.do_crypto(args, fencrypt) rpdb_version = as_unicode(get_interface_compatibility_version()) r = self.m_method(rpdb_version, fencrypt, fcompress, digest, msg) (fencrypt, fcompress, digest, msg) = r # # Decrypt response. # ((max_index, _r, _e), id) = self.m_crypto.undo_crypto(fencrypt, fcompress, digest, msg, fVerifyIndex = False) if _e is not None: raise _e except AuthenticationBadIndex: e = sys.exc_info()[1] self.m_crypto.set_index(e.m_max_index, e.m_anchor) continue except xmlrpclib.Fault: fault = sys.exc_info()[1] if class_name(BadVersion) in fault.faultString: s = fault.faultString.split("'") version = ['', s[1]][len(s) > 0] raise BadVersion(version) if class_name(EncryptionExpected) in fault.faultString: raise EncryptionExpected elif class_name(EncryptionNotSupported) in fault.faultString: if self.m_crypto.m_fAllowUnencrypted: self.__set_encryption(False) continue raise EncryptionNotSupported elif class_name(DecryptionFailure) in fault.faultString: raise DecryptionFailure elif class_name(AuthenticationBadData) in fault.faultString: raise AuthenticationBadData elif class_name(AuthenticationFailure) in fault.faultString: raise AuthenticationFailure else: print_debug_exception() assert False except xmlrpclib.ProtocolError: print_debug("Caught ProtocolError for %s" % name) #print_debug_exception() raise CConnectionException return _r def __getattr__(self, name): return xmlrpclib._Method(self.__request, name) class CIOServer: """ Base class for debuggee server. """ def __init__(self, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, rid): assert(is_unicode(_rpdb2_pwd)) assert(is_unicode(rid)) self.m_thread = None self.m_crypto = CCrypto(_rpdb2_pwd, fAllowUnencrypted, rid) self.m_fAllowRemote = fAllowRemote self.m_rid = rid self.m_port = None self.m_stop = False self.m_server = None self.m_work_queue = None def shutdown(self): self.stop() def start(self): self.m_thread = CThread(name = 'ioserver', target = self.run, shutdown = self.shutdown) self.m_thread.setDaemon(True) self.m_thread.start() def jumpstart(self): self.m_stop = False self.start() def stop(self): if self.m_stop: return print_debug('Stopping IO server... (pid = %d)' % _getpid()) self.m_stop = True while self.m_thread.isAlive(): try: proxy = CPwdServerProxy(self.m_crypto, calcURL(LOOPBACK, self.m_port), CLocalTimeoutTransport()) proxy.null() except (socket.error, CException): pass self.m_thread.join(0.5) self.m_thread = None self.m_work_queue.shutdown() #try: # self.m_server.socket.close() #except: # pass print_debug('Stopping IO server, done.') def export_null(self): return 0 def run(self): if self.m_server == None: (self.m_port, self.m_server) = self.__StartXMLRPCServer() self.m_work_queue = CWorkQueue() self.m_server.register_function(self.dispatcher_method) while not self.m_stop: self.m_server.handle_request() def dispatcher_method(self, rpdb_version, fencrypt, fcompress, digest, msg): """ Process RPC call. """ #print_debug('dispatcher_method() called with: %s, %s, %s, %s' % (rpdb_version, fencrypt, digest, msg[:100])) if rpdb_version != as_unicode(get_interface_compatibility_version()): raise BadVersion(as_unicode(get_version())) try: try: # # Decrypt parameters. # ((name, __params, target_rid), client_id) = self.m_crypto.undo_crypto(fencrypt, fcompress, digest, msg) except AuthenticationBadIndex: e = sys.exc_info()[1] #print_debug_exception() # # Notify the caller on the expected index. # max_index = self.m_crypto.get_max_index() args = (max_index, None, e) (fcompress, digest, msg) = self.m_crypto.do_crypto(args, fencrypt) return (fencrypt, fcompress, digest, msg) r = None e = None try: # # We are forcing the 'export_' prefix on methods that are # callable through XML-RPC to prevent potential security # problems # func = getattr(self, 'export_' + name) except AttributeError: raise Exception('method "%s" is not supported' % ('export_' + name)) try: if (target_rid != 0) and (target_rid != self.m_rid): raise NotAttached # # Record that client id is still attached. # self.record_client_heartbeat(client_id, name, __params) r = func(*__params) except Exception: _e = sys.exc_info()[1] print_debug_exception() e = _e # # Send the encrypted result. # max_index = self.m_crypto.get_max_index() args = (max_index, r, e) (fcompress, digest, msg) = self.m_crypto.do_crypto(args, fencrypt) return (fencrypt, fcompress, digest, msg) except: print_debug_exception() raise def __StartXMLRPCServer(self): """ As the name says, start the XML RPC server. Looks for an available tcp port to listen on. """ host = [LOOPBACK, ""][self.m_fAllowRemote] port = SERVER_PORT_RANGE_START while True: try: server = CXMLRPCServer((host, port), logRequests = 0) return (port, server) except socket.error: e = sys.exc_info()[1] if GetSocketError(e) != errno.EADDRINUSE: raise if port >= SERVER_PORT_RANGE_START + SERVER_PORT_RANGE_LENGTH - 1: raise port += 1 continue def record_client_heartbeat(self, id, name, params): pass class CServerInfo(object): def __init__(self, age, port, pid, filename, rid, state, fembedded): assert(is_unicode(rid)) self.m_age = age self.m_port = port self.m_pid = pid self.m_filename = as_unicode(filename, sys.getfilesystemencoding()) self.m_module_name = as_unicode(CalcModuleName(filename), sys.getfilesystemencoding()) self.m_rid = rid self.m_state = as_unicode(state) self.m_fembedded = fembedded def __reduce__(self): rv = (copy_reg.__newobj__, (type(self), ), vars(self), None, None) return rv def __str__(self): return 'age: %d, port: %d, pid: %d, filename: %s, rid: %s' % (self.m_age, self.m_port, self.m_pid, self.m_filename, self.m_rid) class CDebuggeeServer(CIOServer): """ The debuggee XML RPC server class. """ def __init__(self, filename, debugger, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, rid = None): if rid is None: rid = generate_rid() assert(is_unicode(_rpdb2_pwd)) assert(is_unicode(rid)) CIOServer.__init__(self, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, rid) self.m_filename = filename self.m_pid = _getpid() self.m_time = time.time() self.m_debugger = debugger self.m_rid = rid def shutdown(self): CIOServer.shutdown(self) def record_client_heartbeat(self, id, name, params): finit = (name == 'request_break') fdetach = (name == 'request_go' and True in params) self.m_debugger.record_client_heartbeat(id, finit, fdetach) def export_null(self): return self.m_debugger.send_event_null() def export_server_info(self): age = time.time() - self.m_time state = self.m_debugger.get_state() fembedded = self.m_debugger.is_embedded() si = CServerInfo(age, self.m_port, self.m_pid, self.m_filename, self.m_rid, state, fembedded) return si def export_sync_with_events(self, fException, fSendUnhandled): ei = self.m_debugger.sync_with_events(fException, fSendUnhandled) return ei def export_wait_for_event(self, timeout, event_index): (new_event_index, s) = self.m_debugger.wait_for_event(timeout, event_index) return (new_event_index, s) def export_set_breakpoint(self, filename, scope, lineno, fEnabled, expr, frame_index, fException, encoding): self.m_debugger.set_breakpoint(filename, scope, lineno, fEnabled, expr, frame_index, fException, encoding) return 0 def export_disable_breakpoint(self, id_list, fAll): self.m_debugger.disable_breakpoint(id_list, fAll) return 0 def export_enable_breakpoint(self, id_list, fAll): self.m_debugger.enable_breakpoint(id_list, fAll) return 0 def export_delete_breakpoint(self, id_list, fAll): self.m_debugger.delete_breakpoint(id_list, fAll) return 0 def export_get_breakpoints(self): bpl = self.m_debugger.get_breakpoints() return bpl def export_request_break(self): self.m_debugger.request_break() return 0 def export_request_go(self, fdetach = False): self.m_debugger.request_go() return 0 def export_request_go_breakpoint(self, filename, scope, lineno, frame_index, fException): self.m_debugger.request_go_breakpoint(filename, scope, lineno, frame_index, fException) return 0 def export_request_step(self): self.m_debugger.request_step() return 0 def export_request_next(self): self.m_debugger.request_next() return 0 def export_request_return(self): self.m_debugger.request_return() return 0 def export_request_jump(self, lineno): self.m_debugger.request_jump(lineno) return 0 def export_get_stack(self, tid_list, fAll, fException): r = self.m_debugger.get_stack(tid_list, fAll, fException) return r def export_get_source_file(self, filename, lineno, nlines, frame_index, fException): r = self.m_debugger.get_source_file(filename, lineno, nlines, frame_index, fException) return r def export_get_source_lines(self, nlines, fAll, frame_index, fException): r = self.m_debugger.get_source_lines(nlines, fAll, frame_index, fException) return r def export_get_thread_list(self): r = self.m_debugger.get_thread_list() return r def export_set_thread(self, tid): self.m_debugger.set_thread(tid) return 0 def export_get_namespace(self, nl, filter_level, frame_index, fException, repr_limit, encoding, fraw): r = self.m_debugger.get_namespace(nl, filter_level, frame_index, fException, repr_limit, encoding, fraw) return r def export_evaluate(self, expr, frame_index, fException, encoding, fraw): (v, w, e) = self.m_debugger.evaluate(expr, frame_index, fException, encoding, fraw) return (v, w, e) def export_execute(self, suite, frame_index, fException, encoding): (w, e) = self.m_debugger.execute(suite, frame_index, fException, encoding) return (w, e) def export_stop_debuggee(self): self.m_debugger.stop_debuggee() return 0 def export_set_synchronicity(self, fsynchronicity): self.m_debugger.set_synchronicity(fsynchronicity) return 0 def export_set_trap_unhandled_exceptions(self, ftrap): self.m_debugger.set_trap_unhandled_exceptions(ftrap) return 0 def export_is_unhandled_exception(self): return self.m_debugger.is_unhandled_exception() def export_set_fork_mode(self, ffork_into_child, ffork_auto): self.m_debugger.set_fork_mode(ffork_into_child, ffork_auto) return 0 def export_set_environ(self, envmap): self.m_debugger.set_environ(envmap) return 0 def export_embedded_sync(self): self.m_debugger.embedded_sync() return 0 # # ------------------------------------- RPC Client -------------------------------------------- # if not is_py3k(): # # MOD # class CTimeoutHTTPConnection(httplib.HTTPConnection): """ Modification of httplib.HTTPConnection with timeout for sockets. """ _rpdb2_timeout = PING_TIMEOUT def connect(self): """Connect to the host and port specified in __init__.""" msg = "getaddrinfo returns an empty list" for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: self.sock = socket.socket(af, socktype, proto) self.sock.settimeout(self._rpdb2_timeout) if self.debuglevel > 0: print_debug("connect: (%s, %s)" % (self.host, self.port)) self.sock.connect(sa) except socket.error: msg = sys.exc_info()[1] if self.debuglevel > 0: print_debug('connect fail: ' + repr((self.host, self.port))) if self.sock: self.sock.close() self.sock = None continue break if not self.sock: raise socket.error(msg) # # MOD # class CLocalTimeoutHTTPConnection(CTimeoutHTTPConnection): """ Modification of httplib.HTTPConnection with timeout for sockets. """ _rpdb2_timeout = LOCAL_TIMEOUT # # MOD # class CTimeoutHTTP(httplib.HTTP): """ Modification of httplib.HTTP with timeout for sockets. """ _connection_class = CTimeoutHTTPConnection # # MOD # class CLocalTimeoutHTTP(httplib.HTTP): """ Modification of httplib.HTTP with timeout for sockets. """ _connection_class = CLocalTimeoutHTTPConnection # # MOD # class CTimeoutTransport(xmlrpclib.Transport): """ Modification of xmlrpclib.Transport with timeout for sockets. """ def make_connection(self, host): # create a HTTP connection object from a host descriptor host, extra_headers, x509 = self.get_host_info(host) return CTimeoutHTTP(host) # # MOD # class CLocalTimeoutTransport(xmlrpclib.Transport): """ Modification of xmlrpclib.Transport with timeout for sockets. """ def make_connection(self, host): # create a HTTP connection object from a host descriptor host, extra_headers, x509 = self.get_host_info(host) return CLocalTimeoutHTTP(host) else: # # MOD # class CTimeoutTransport(xmlrpclib.Transport): """ Modification of xmlrpclib.Transport with timeout for sockets. """ def send_request(self, host, handler, request_body, debug): host, extra_headers, x509 = self.get_host_info(host) connection = httplib.HTTPConnection(host, timeout = PING_TIMEOUT) if debug: connection.set_debuglevel(1) headers = {} if extra_headers: for key, val in extra_headers: header[key] = val headers["Content-Type"] = "text/xml" headers["User-Agent"] = self.user_agent connection.request("POST", handler, request_body, headers) return connection # # MOD # class CLocalTimeoutTransport(xmlrpclib.Transport): """ Modification of xmlrpclib.Transport with timeout for sockets. """ def send_request(self, host, handler, request_body, debug): host, extra_headers, x509 = self.get_host_info(host) connection = httplib.HTTPConnection(host, timeout = LOCAL_TIMEOUT) if debug: connection.set_debuglevel(1) headers = {} if extra_headers: for key, val in extra_headers: header[key] = val headers["Content-Type"] = "text/xml" headers["User-Agent"] = self.user_agent connection.request("POST", handler, request_body, headers) return connection # # MOD # class CLocalTransport(xmlrpclib.Transport): """ Modification of xmlrpclib.Transport to work around Zonealarm sockets bug. """ def __parse_response(self, file, sock): # read response from input file/socket, and parse it p, u = self.getparser() while 1: if sock: response = sock.recv(1024) else: time.sleep(0.002) response = file.read(1024) if not response: break if self.verbose: _print("body: " + repr(response)) p.feed(response) file.close() p.close() return u.close() if os.name == 'nt': _parse_response = __parse_response class CSession: """ Basic class that communicates with the debuggee server. """ def __init__(self, host, port, _rpdb2_pwd, fAllowUnencrypted, rid): self.m_crypto = CCrypto(_rpdb2_pwd, fAllowUnencrypted, rid) self.m_host = host self.m_port = port self.m_proxy = None self.m_server_info = None self.m_exc_info = None self.m_fShutDown = False self.m_fRestart = False def get_encryption(self): return self.m_proxy.get_encryption() def getServerInfo(self): return self.m_server_info def pause(self): self.m_fRestart = True def restart(self, sleep = 0, timeout = 10): self.m_fRestart = True time.sleep(sleep) t0 = time.time() try: try: while time.time() < t0 + timeout: try: self.Connect() return except socket.error: continue raise CConnectionException except: self.m_fShutDown = True raise finally: self.m_fRestart = False def shut_down(self): self.m_fShutDown = True def getProxy(self): """ Return the proxy object. With this object you can invoke methods on the server. """ while self.m_fRestart: time.sleep(0.1) if self.m_fShutDown: raise NotAttached return self.m_proxy def ConnectAsync(self): t = threading.Thread(target = self.ConnectNoThrow) #t.setDaemon(True) t.start() return t def ConnectNoThrow(self): try: self.Connect() except: self.m_exc_info = sys.exc_info() def Connect(self): host = self.m_host if host.lower() == LOCALHOST: host = LOOPBACK server = CPwdServerProxy(self.m_crypto, calcURL(host, self.m_port), CTimeoutTransport()) server_info = server.server_info() self.m_proxy = CPwdServerProxy(self.m_crypto, calcURL(host, self.m_port), CLocalTransport(), target_rid = server_info.m_rid) self.m_server_info = server_info def isConnected(self): return self.m_proxy is not None class CServerList: def __init__(self, host): self.m_host = host self.m_list = [] self.m_errors = {} def calcList(self, _rpdb2_pwd, rid, key = None): sil = [] sessions = [] self.m_errors = {} port = SERVER_PORT_RANGE_START while port < SERVER_PORT_RANGE_START + SERVER_PORT_RANGE_LENGTH: s = CSession(self.m_host, port, _rpdb2_pwd, fAllowUnencrypted = True, rid = rid) t = s.ConnectAsync() sessions.append((s, t)) port += 1 for (s, t) in sessions: t.join() if (s.m_exc_info is not None): if not issubclass(s.m_exc_info[0], socket.error): self.m_errors.setdefault(s.m_exc_info[0], []).append(s.m_exc_info) continue si = s.getServerInfo() if si is not None: sil.append((-si.m_age, si)) sil.sort() self.m_list = [s[1] for s in sil] if key != None: try: return self.findServers(key)[0] except: pass if key != None: raise UnknownServer sil.sort() self.m_list = [s[1] for s in sil] return self.m_list def get_errors(self): return self.m_errors def findServers(self, key): try: n = int(key) _s = [s for s in self.m_list if (s.m_pid == n) or (s.m_rid == key)] except ValueError: key = as_string(key, sys.getfilesystemencoding()) _s = [s for s in self.m_list if key in s.m_filename] if _s == []: raise UnknownServer return _s class CSessionManagerInternal: def __init__(self, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host): self.m_rpdb2_pwd = [_rpdb2_pwd, None][_rpdb2_pwd in [None, '']] self.m_fAllowUnencrypted = fAllowUnencrypted self.m_fAllowRemote = fAllowRemote self.m_rid = generate_rid() self.m_host = host self.m_server_list_object = CServerList(host) self.m_session = None self.m_server_info = None self.m_worker_thread = None self.m_worker_thread_ident = None self.m_fStop = False self.m_stack_depth = None self.m_stack_depth_exception = None self.m_frame_index = 0 self.m_frame_index_exception = 0 self.m_completions = {} self.m_remote_event_index = 0 self.m_event_dispatcher_proxy = CEventDispatcher() self.m_event_dispatcher = CEventDispatcher(self.m_event_dispatcher_proxy) self.m_state_manager = CStateManager(STATE_DETACHED, self.m_event_dispatcher, self.m_event_dispatcher_proxy) self.m_breakpoints_proxy = CBreakPointsManagerProxy(self) event_type_dict = {CEventState: {EVENT_EXCLUDE: [STATE_BROKEN, STATE_ANALYZE]}} self.register_callback(self.reset_frame_indexes, event_type_dict, fSingleUse = False) event_type_dict = {CEventStackDepth: {}} self.register_callback(self.set_stack_depth, event_type_dict, fSingleUse = False) event_type_dict = {CEventNoThreads: {}} self.register_callback(self._reset_frame_indexes, event_type_dict, fSingleUse = False) event_type_dict = {CEventExit: {}} self.register_callback(self.on_event_exit, event_type_dict, fSingleUse = False) event_type_dict = {CEventConflictingModules: {}} self.register_callback(self.on_event_conflicting_modules, event_type_dict, fSingleUse = False) event_type_dict = {CEventSignalIntercepted: {}} self.register_callback(self.on_event_signal_intercept, event_type_dict, fSingleUse = False) event_type_dict = {CEventSignalException: {}} self.register_callback(self.on_event_signal_exception, event_type_dict, fSingleUse = False) event_type_dict = {CEventEmbeddedSync: {}} self.register_callback(self.on_event_embedded_sync, event_type_dict, fSingleUse = False) event_type_dict = {CEventSynchronicity: {}} self.m_event_dispatcher_proxy.register_callback(self.on_event_synchronicity, event_type_dict, fSingleUse = False) self.m_event_dispatcher.register_chain_override(event_type_dict) event_type_dict = {CEventTrap: {}} self.m_event_dispatcher_proxy.register_callback(self.on_event_trap, event_type_dict, fSingleUse = False) self.m_event_dispatcher.register_chain_override(event_type_dict) event_type_dict = {CEventForkMode: {}} self.m_event_dispatcher_proxy.register_callback(self.on_event_fork_mode, event_type_dict, fSingleUse = False) self.m_event_dispatcher.register_chain_override(event_type_dict) self.m_printer = self.__nul_printer self.m_last_command_line = None self.m_last_fchdir = None self.m_fsynchronicity = True self.m_ftrap = True self.m_ffork_into_child = False self.m_ffork_auto = False self.m_environment = [] self.m_encoding = ENCODING_AUTO self.m_fraw = False def shutdown(self): self.m_event_dispatcher_proxy.shutdown() self.m_event_dispatcher.shutdown() self.m_state_manager.shutdown() def __nul_printer(self, _str): pass def set_printer(self, printer): self.m_printer = printer def register_callback(self, callback, event_type_dict, fSingleUse): return self.m_event_dispatcher.register_callback(callback, event_type_dict, fSingleUse) def remove_callback(self, callback): return self.m_event_dispatcher.remove_callback(callback) def __wait_for_debuggee(self, rid): try: time.sleep(STARTUP_TIMEOUT / 2) for i in range(STARTUP_RETRIES): try: print_debug('Scanning for debuggee...') t0 = time.time() return self.m_server_list_object.calcList(self.m_rpdb2_pwd, self.m_rid, rid) except UnknownServer: dt = time.time() - t0 if dt < STARTUP_TIMEOUT: time.sleep(STARTUP_TIMEOUT - dt) continue return self.m_server_list_object.calcList(self.m_rpdb2_pwd, self.m_rid, rid) finally: errors = self.m_server_list_object.get_errors() self.__report_server_errors(errors, fsupress_pwd_warning = True) def get_encryption(self): return self.getSession().get_encryption() def launch(self, fchdir, command_line, fload_breakpoints = True): assert(is_unicode(command_line)) self.__verify_unattached() if not os.name in [POSIX, 'nt']: self.m_printer(STR_SPAWN_UNSUPPORTED) raise SpawnUnsupported if g_fFirewallTest: firewall_test = CFirewallTest(self.get_remote()) if not firewall_test.run(): raise FirewallBlock else: print_debug('Skipping firewall test.') if self.m_rpdb2_pwd is None: self.set_random_password() if command_line == '': raise BadArgument (path, filename, args) = split_command_line_path_filename_args(command_line) #if not IsPythonSourceFile(filename): # raise NotPythonSource _filename = my_os_path_join(path, filename) ExpandedFilename = FindFile(_filename) self.set_host(LOCALHOST) self.m_printer(STR_STARTUP_SPAWN_NOTICE) rid = generate_rid() create_pwd_file(rid, self.m_rpdb2_pwd) self.m_state_manager.set_state(STATE_SPAWNING) try: try: self._spawn_server(fchdir, ExpandedFilename, args, rid) server = self.__wait_for_debuggee(rid) self.attach(server.m_rid, server.m_filename, fsupress_pwd_warning = True, fsetenv = True, ffirewall_test = False, server = server, fload_breakpoints = fload_breakpoints) self.m_last_command_line = command_line self.m_last_fchdir = fchdir except: if self.m_state_manager.get_state() != STATE_DETACHED: self.m_state_manager.set_state(STATE_DETACHED) raise finally: delete_pwd_file(rid) def restart(self): """ Restart debug session with same command_line and fchdir arguments which were used in last launch. """ if None in (self.m_last_fchdir, self.m_last_command_line): return if self.m_state_manager.get_state() != STATE_DETACHED: self.stop_debuggee() self.launch(self.m_last_fchdir, self.m_last_command_line) def get_launch_args(self): """ Return command_line and fchdir arguments which were used in last launch as (last_fchdir, last_command_line). Returns None if there is no info. """ if None in (self.m_last_fchdir, self.m_last_command_line): return (None, None) return (self.m_last_fchdir, self.m_last_command_line) def _spawn_server(self, fchdir, ExpandedFilename, args, rid): """ Start an OS console to act as server. What it does is to start rpdb again in a new console in server only mode. """ if g_fScreen: name = SCREEN elif sys.platform == DARWIN: name = DARWIN else: try: import terminalcommand name = MAC except: name = os.name if name == 'nt' and g_fDebug: name = NT_DEBUG e = ['', ' --encrypt'][not self.m_fAllowUnencrypted] r = ['', ' --remote'][self.m_fAllowRemote] c = ['', ' --chdir'][fchdir] p = ['', ' --pwd="%s"' % self.m_rpdb2_pwd][os.name == 'nt'] b = '' encoding = detect_locale() fse = sys.getfilesystemencoding() ExpandedFilename = g_found_unicode_files.get(ExpandedFilename, ExpandedFilename) ExpandedFilename = as_unicode(ExpandedFilename, fse) if as_bytes('?') in as_bytes(ExpandedFilename, encoding, fstrict = False): _u = as_bytes(ExpandedFilename) _b = base64.encodestring(_u) _b = _b.strip(as_bytes('\n')).translate(g_safe_base64_to) _b = as_string(_b, fstrict = True) b = ' --base64=%s' % _b debugger = os.path.abspath(__file__) if debugger[-1:] == 'c': debugger = debugger[:-1] debugger = as_unicode(debugger, fse) debug_prints = ['', ' --debug'][g_fDebug] options = '"%s"%s --debugee%s%s%s%s%s --rid=%s "%s" %s' % (debugger, debug_prints, p, e, r, c, b, rid, ExpandedFilename, args) python_exec = sys.executable if python_exec.endswith('w.exe'): python_exec = python_exec[:-5] + '.exe' python_exec = as_unicode(python_exec, fse) if as_bytes('?') in as_bytes(python_exec + debugger, encoding, fstrict = False): raise BadMBCSPath if name == POSIX: shell = CalcUserShell() terminal_command = CalcTerminalCommand() if terminal_command in osSpawn: command = osSpawn[terminal_command] % {'shell': shell, 'exec': python_exec, 'options': options} else: command = osSpawn[name] % {'term': terminal_command, 'shell': shell, 'exec': python_exec, 'options': options} else: command = osSpawn[name] % {'exec': python_exec, 'options': options} if name == DARWIN: s = 'cd "%s" ; %s' % (os.getcwdu(), command) command = CalcMacTerminalCommand(s) print_debug('Terminal open string: %s' % repr(command)) command = as_string(command, encoding) if name == MAC: terminalcommand.run(command) else: os.popen(command) def attach(self, key, name = None, fsupress_pwd_warning = False, fsetenv = False, ffirewall_test = True, server = None, fload_breakpoints = True): assert(is_unicode(key)) self.__verify_unattached() if key == '': raise BadArgument if self.m_rpdb2_pwd is None: #self.m_printer(STR_PASSWORD_MUST_BE_SET) raise UnsetPassword if g_fFirewallTest and ffirewall_test: firewall_test = CFirewallTest(self.get_remote()) if not firewall_test.run(): raise FirewallBlock elif not g_fFirewallTest and ffirewall_test: print_debug('Skipping firewall test.') if name is None: name = key _name = name self.m_printer(STR_STARTUP_NOTICE) self.m_state_manager.set_state(STATE_ATTACHING) try: servers = [server] if server == None: self.m_server_list_object.calcList(self.m_rpdb2_pwd, self.m_rid) servers = self.m_server_list_object.findServers(key) server = servers[0] _name = server.m_filename errors = self.m_server_list_object.get_errors() if not key in [server.m_rid, str(server.m_pid)]: self.__report_server_errors(errors, fsupress_pwd_warning) self.__attach(server, fsetenv) if len(servers) > 1: self.m_printer(STR_MULTIPLE_DEBUGGEES % key) self.m_printer(STR_ATTACH_CRYPTO_MODE % ([' ' + STR_ATTACH_CRYPTO_MODE_NOT, ''][self.get_encryption()])) self.m_printer(STR_ATTACH_SUCCEEDED % server.m_filename) try: if fload_breakpoints: self.load_breakpoints() except: pass except (socket.error, CConnectionException): self.m_printer(STR_ATTACH_FAILED_NAME % _name) self.m_state_manager.set_state(STATE_DETACHED) raise except: print_debug_exception() assert False def report_exception(self, _type, value, tb): msg = g_error_mapping.get(_type, STR_ERROR_OTHER) if _type == SpawnUnsupported and os.name == POSIX and not g_fScreen and g_fDefaultStd: msg += ' ' + STR_SPAWN_UNSUPPORTED_SCREEN_SUFFIX if _type == UnknownServer and os.name == POSIX and not g_fScreen and g_fDefaultStd: msg += ' ' + STR_DISPLAY_ERROR _str = msg % {'type': _type, 'value': value, 'traceback': tb} self.m_printer(_str) if not _type in g_error_mapping: print_exception(_type, value, tb, True) def __report_server_errors(self, errors, fsupress_pwd_warning = False): for k, el in errors.items(): if fsupress_pwd_warning and k in [BadVersion, AuthenticationBadData, AuthenticationFailure]: continue if k in [BadVersion]: for (t, v, tb) in el: self.report_exception(t, v, None) continue (t, v, tb) = el[0] self.report_exception(t, v, tb) def __attach(self, server, fsetenv): self.__verify_unattached() session = CSession(self.m_host, server.m_port, self.m_rpdb2_pwd, self.m_fAllowUnencrypted, self.m_rid) session.Connect() if (session.getServerInfo().m_pid != server.m_pid) or (session.getServerInfo().m_filename != server.m_filename): raise UnexpectedData self.m_session = session self.m_server_info = self.get_server_info() self.getSession().getProxy().set_synchronicity(self.m_fsynchronicity) self.getSession().getProxy().set_trap_unhandled_exceptions(self.m_ftrap) self.getSession().getProxy().set_fork_mode(self.m_ffork_into_child, self.m_ffork_auto) if fsetenv and len(self.m_environment) != 0: self.getSession().getProxy().set_environ(self.m_environment) self.request_break() self.refresh(True) self.__start_event_monitor() print_debug('Attached to debuggee on port %d.' % session.m_port) #self.enable_breakpoint([], fAll = True) def __verify_unattached(self): if self.__is_attached(): raise AlreadyAttached def __verify_attached(self): if not self.__is_attached(): raise NotAttached def __is_attached(self): return (self.m_state_manager.get_state() != STATE_DETACHED) and (self.m_session is not None) def __verify_broken(self): if self.m_state_manager.get_state() not in [STATE_BROKEN, STATE_ANALYZE]: raise DebuggerNotBroken def refresh(self, fSendUnhandled = False): fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) self.m_remote_event_index = self.getSession().getProxy().sync_with_events(fAnalyzeMode, fSendUnhandled) self.m_breakpoints_proxy.sync() def __start_event_monitor(self): self.m_fStop = False self.m_worker_thread = threading.Thread(target = self.__event_monitor_proc) #self.m_worker_thread.setDaemon(True) self.m_worker_thread.start() def __event_monitor_proc(self): self.m_worker_thread_ident = thread.get_ident() t = 0 nfailures = 0 while not self.m_fStop: try: t = ControlRate(t, IDLE_MAX_RATE) if self.m_fStop: return (n, sel) = self.getSession().getProxy().wait_for_event(PING_TIMEOUT, self.m_remote_event_index) if True in [isinstance(e, CEventForkSwitch) for e in sel]: print_debug('Received fork switch event.') self.getSession().pause() threading.Thread(target = self.restart_session_job).start() if True in [isinstance(e, CEventExecSwitch) for e in sel]: print_debug('Received exec switch event.') self.getSession().pause() threading.Thread(target = self.restart_session_job, args = (True, )).start() if True in [isinstance(e, CEventExit) for e in sel]: self.getSession().shut_down() self.m_fStop = True if n > self.m_remote_event_index: #print >> sys.__stderr__, (n, sel) self.m_remote_event_index = n self.m_event_dispatcher_proxy.fire_events(sel) nfailures = 0 except CConnectionException: if not self.m_fStop: self.report_exception(*sys.exc_info()) threading.Thread(target = self.detach_job).start() return except socket.error: if nfailures < COMMUNICATION_RETRIES: nfailures += 1 continue if not self.m_fStop: self.report_exception(*sys.exc_info()) threading.Thread(target = self.detach_job).start() return def on_event_conflicting_modules(self, event): s = ', '.join(event.m_modules_list) self.m_printer(STR_CONFLICTING_MODULES % s) def on_event_signal_intercept(self, event): if self.m_state_manager.get_state() in [STATE_ANALYZE, STATE_BROKEN]: self.m_printer(STR_SIGNAL_INTERCEPT % (event.m_signame, event.m_signum)) def on_event_signal_exception(self, event): self.m_printer(STR_SIGNAL_EXCEPTION % (event.m_description, event.m_signame, event.m_signum)) def on_event_embedded_sync(self, event): # # time.sleep() allows pending break requests to go through... # time.sleep(0.001) self.getSession().getProxy().embedded_sync() def on_event_exit(self, event): self.m_printer(STR_DEBUGGEE_TERMINATED) threading.Thread(target = self.detach_job).start() def restart_session_job(self, fSendExitOnFailure = False): try: self.getSession().restart(sleep = 3) return except: pass self.m_fStop = True if fSendExitOnFailure: e = CEventExit() self.m_event_dispatcher_proxy.fire_event(e) return self.m_printer(STR_LOST_CONNECTION) self.detach_job() def detach_job(self): try: self.detach() except: pass def detach(self): self.__verify_attached() try: self.save_breakpoints() except: print_debug_exception() pass self.m_printer(STR_ATTEMPTING_TO_DETACH) self.m_state_manager.set_state(STATE_DETACHING) self.__stop_event_monitor() try: #self.disable_breakpoint([], fAll = True) try: self.getSession().getProxy().set_trap_unhandled_exceptions(False) self.request_go(fdetach = True) except DebuggerNotBroken: pass finally: self.m_state_manager.set_state(STATE_DETACHED) self.m_session = None self.m_printer(STR_DETACH_SUCCEEDED) def __stop_event_monitor(self): self.m_fStop = True if self.m_worker_thread is not None: if thread.get_ident() != self.m_worker_thread_ident: try: self.getSession().getProxy().null() except: pass self.m_worker_thread.join() self.m_worker_thread = None self.m_worker_thread_ident = None def request_break(self): self.getSession().getProxy().request_break() def request_go(self, fdetach = False): self.getSession().getProxy().request_go(fdetach) def request_go_breakpoint(self, filename, scope, lineno): frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) self.getSession().getProxy().request_go_breakpoint(filename, scope, lineno, frame_index, fAnalyzeMode) def request_step(self): self.getSession().getProxy().request_step() def request_next(self): self.getSession().getProxy().request_next() def request_return(self): self.getSession().getProxy().request_return() def request_jump(self, lineno): self.getSession().getProxy().request_jump(lineno) def set_breakpoint(self, filename, scope, lineno, fEnabled, expr, encoding = None): frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) if encoding == None: encoding = self.m_encoding self.getSession().getProxy().set_breakpoint(filename, scope, lineno, fEnabled, expr, frame_index, fAnalyzeMode, encoding) def disable_breakpoint(self, id_list, fAll): self.getSession().getProxy().disable_breakpoint(id_list, fAll) def enable_breakpoint(self, id_list, fAll): self.getSession().getProxy().enable_breakpoint(id_list, fAll) def delete_breakpoint(self, id_list, fAll): self.getSession().getProxy().delete_breakpoint(id_list, fAll) def get_breakpoints(self): self.__verify_attached() bpl = self.m_breakpoints_proxy.get_breakpoints() return bpl def save_breakpoints(self, filename = ''): self.__verify_attached() module_name = self.getSession().getServerInfo().m_module_name if module_name[:1] == '<': return path = calc_bpl_filename(module_name + filename) file = open(path, 'wb') try: try: bpl = self.get_breakpoints() sbpl = pickle.dumps(bpl) file.write(sbpl) except: print_debug_exception() raise CException finally: file.close() def load_breakpoints(self, filename = ''): self.__verify_attached() module_name = self.getSession().getServerInfo().m_module_name if module_name[:1] == '<': return path = calc_bpl_filename(module_name + filename) file = open(path, 'rb') ferror = False try: try: bpl = pickle.load(file) self.delete_breakpoint([], True) except: print_debug_exception() raise CException # # No Breakpoints were found in file. # if filename == '' and len(bpl.values()) == 0: raise IOError for bp in bpl.values(): try: if bp.m_scope_fqn != None: bp.m_scope_fqn = as_unicode(bp.m_scope_fqn) if bp.m_filename != None: bp.m_filename = as_unicode(bp.m_filename) if bp.m_expr != None: bp.m_expr = as_unicode(bp.m_expr) if bp.m_expr in [None, '']: bp.m_encoding = as_unicode('utf-8') self.set_breakpoint(bp.m_filename, bp.m_scope_fqn, bp.m_scope_offset, bp.m_fEnabled, bp.m_expr, bp.m_encoding) except: print_debug_exception() ferror = True if ferror: raise CException finally: file.close() def on_event_synchronicity(self, event): ffire = self.m_fsynchronicity != event.m_fsynchronicity self.m_fsynchronicity = event.m_fsynchronicity if ffire: event = CEventSynchronicity(event.m_fsynchronicity) self.m_event_dispatcher.fire_event(event) def set_synchronicity(self, fsynchronicity): self.m_fsynchronicity = fsynchronicity if self.__is_attached(): try: self.getSession().getProxy().set_synchronicity(fsynchronicity) except NotAttached: pass event = CEventSynchronicity(fsynchronicity) self.m_event_dispatcher.fire_event(event) def get_synchronicity(self): return self.m_fsynchronicity def on_event_trap(self, event): ffire = self.m_ftrap != event.m_ftrap self.m_ftrap = event.m_ftrap if ffire: event = CEventTrap(event.m_ftrap) self.m_event_dispatcher.fire_event(event) def set_trap_unhandled_exceptions(self, ftrap): self.m_ftrap = ftrap if self.__is_attached(): try: self.getSession().getProxy().set_trap_unhandled_exceptions(self.m_ftrap) except NotAttached: pass event = CEventTrap(ftrap) self.m_event_dispatcher.fire_event(event) def get_trap_unhandled_exceptions(self): return self.m_ftrap def is_unhandled_exception(self): self.__verify_attached() return self.getSession().getProxy().is_unhandled_exception() def on_event_fork_mode(self, event): ffire = ((self.m_ffork_into_child , self.m_ffork_auto) != (event.m_ffork_into_child, event.m_ffork_auto)) self.m_ffork_into_child = event.m_ffork_into_child self.m_ffork_auto = event.m_ffork_auto if ffire: event = CEventForkMode(self.m_ffork_into_child, self.m_ffork_auto) self.m_event_dispatcher.fire_event(event) def set_fork_mode(self, ffork_into_child, ffork_auto): self.m_ffork_into_child = ffork_into_child self.m_ffork_auto = ffork_auto if self.__is_attached(): try: self.getSession().getProxy().set_fork_mode( self.m_ffork_into_child, self.m_ffork_auto ) except NotAttached: pass event = CEventForkMode(ffork_into_child, ffork_auto) self.m_event_dispatcher.fire_event(event) def get_fork_mode(self): return (self.m_ffork_into_child, self.m_ffork_auto) def get_stack(self, tid_list, fAll): fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) r = self.getSession().getProxy().get_stack(tid_list, fAll, fAnalyzeMode) return r def get_source_file(self, filename, lineno, nlines): assert(is_unicode(filename)) frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) r = self.getSession().getProxy().get_source_file(filename, lineno, nlines, frame_index, fAnalyzeMode) return r def get_source_lines(self, nlines, fAll): frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) r = self.getSession().getProxy().get_source_lines(nlines, fAll, frame_index, fAnalyzeMode) return r def get_thread_list(self): (current_thread_id, thread_list) = self.getSession().getProxy().get_thread_list() return (current_thread_id, thread_list) def set_thread(self, tid): self.reset_frame_indexes(None) self.getSession().getProxy().set_thread(tid) def get_namespace(self, nl, filter_level, repr_limit): frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) r = self.getSession().getProxy().get_namespace(nl, filter_level, frame_index, fAnalyzeMode, repr_limit, self.m_encoding, self.m_fraw) return r def evaluate(self, expr, fclear_completions = True): assert(is_unicode(expr)) self.__verify_attached() self.__verify_broken() frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) (value, warning, error) = self.getSession().getProxy().evaluate(expr, frame_index, fAnalyzeMode, self.m_encoding, self.m_fraw) if fclear_completions: self.m_completions.clear() return (value, warning, error) def execute(self, suite): assert(is_unicode(suite)) self.__verify_attached() self.__verify_broken() frame_index = self.get_frame_index() fAnalyzeMode = (self.m_state_manager.get_state() == STATE_ANALYZE) (warning, error) = self.getSession().getProxy().execute(suite, frame_index, fAnalyzeMode, self.m_encoding) self.m_completions.clear() return (warning, error) def set_encoding(self, encoding, fraw): if (self.m_encoding, self.m_fraw) == (encoding, fraw): return self.m_encoding = encoding self.m_fraw = fraw event = CEventEncoding(encoding, fraw) self.m_event_dispatcher.fire_event(event) if self.__is_attached(): self.refresh() def get_encoding(self): return (self.m_encoding, self.m_fraw) def set_host(self, host): self.__verify_unattached() try: if not is_unicode(host): host = host.decode('ascii') host.encode('ascii') except: raise BadArgument host = as_string(host, 'ascii') try: socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM) except socket.gaierror: if host.lower() != LOCALHOST: raise # # Work-around for gaierror: (-8, 'Servname not supported for ai_socktype') # return self.set_host(LOOPBACK) self.m_host = host self.m_server_list_object = CServerList(host) def get_host(self): return as_unicode(self.m_host) def calc_server_list(self): if self.m_rpdb2_pwd is None: raise UnsetPassword if g_fFirewallTest: firewall_test = CFirewallTest(self.get_remote()) if not firewall_test.run(): raise FirewallBlock else: print_debug('Skipping firewall test.') server_list = self.m_server_list_object.calcList(self.m_rpdb2_pwd, self.m_rid) errors = self.m_server_list_object.get_errors() self.__report_server_errors(errors) return (server_list, errors) def get_server_info(self): return self.getSession().getServerInfo() def complete_expression(self, expr): match = re.search( r'(?P \.)? (?P ((?P (\w+\.)* \w+) \.)? (?P\w*) $)', expr, re.U | re.X ) if match == None: raise BadArgument d = match.groupdict() unsupported, scope, complete = (d['unsupported'], d['scope'], d['complete']) if unsupported != None: raise BadArgument if scope == None: _scope = as_unicode('list(globals().keys()) + list(locals().keys()) + list(_RPDB2_builtins.keys())') else: _scope = as_unicode('dir(%s)' % scope) if not _scope in self.m_completions: (v, w, e) = self.evaluate(_scope, fclear_completions = False) if w != '' or e != '': print_debug('evaluate() returned the following warning/error: %s' % w + e) return (expr, []) cl = list(set(eval(v))) if '_RPDB2_builtins' in cl: cl.remove('_RPDB2_builtins') self.m_completions[_scope] = cl completions = [attr for attr in self.m_completions[_scope] if attr.startswith(complete)] completions.sort() if complete == '': prefix = expr else: prefix = expr[:-len(complete)] return (prefix, completions) def _reset_frame_indexes(self, event): self.reset_frame_indexes(None) def reset_frame_indexes(self, event): try: self.m_state_manager.acquire() if event is None: self.__verify_broken() elif self.m_state_manager.get_state() in [STATE_BROKEN, STATE_ANALYZE]: return self.m_stack_depth = None self.m_stack_depth_exception = None self.m_frame_index = 0 self.m_frame_index_exception = 0 self.m_completions.clear() finally: self.m_state_manager.release() def set_stack_depth(self, event): try: self.m_state_manager.acquire() self.__verify_broken() self.m_stack_depth = event.m_stack_depth self.m_stack_depth_exception = event.m_stack_depth_exception self.m_frame_index = min(self.m_frame_index, self.m_stack_depth - 1) self.m_frame_index_exception = min(self.m_frame_index_exception, self.m_stack_depth_exception - 1) finally: self.m_state_manager.release() def set_frame_index(self, frame_index): try: self.m_state_manager.acquire() self.__verify_broken() if (frame_index < 0) or (self.m_stack_depth is None): return self.get_frame_index(fLock = False) if self.m_state_manager.get_state() == STATE_ANALYZE: self.m_frame_index_exception = min(frame_index, self.m_stack_depth_exception - 1) si = self.m_frame_index_exception else: self.m_frame_index = min(frame_index, self.m_stack_depth - 1) si = self.m_frame_index finally: self.m_state_manager.release() event = CEventStackFrameChange(si) self.m_event_dispatcher.fire_event(event) event = CEventNamespace() self.m_event_dispatcher.fire_event(event) return si def get_frame_index(self, fLock = True): try: if fLock: self.m_state_manager.acquire() self.__verify_attached() if self.m_state_manager.get_state() == STATE_ANALYZE: return self.m_frame_index_exception else: return self.m_frame_index finally: if fLock: self.m_state_manager.release() def set_analyze(self, fAnalyze): try: self.m_state_manager.acquire() if fAnalyze and (self.m_state_manager.get_state() != STATE_BROKEN): raise DebuggerNotBroken if (not fAnalyze) and (self.m_state_manager.get_state() != STATE_ANALYZE): return state = [STATE_BROKEN, STATE_ANALYZE][fAnalyze] self.m_state_manager.set_state(state, fLock = False) finally: self.m_state_manager.release() self.refresh() def getSession(self): self.__verify_attached() return self.m_session def get_state(self): return as_unicode(self.m_state_manager.get_state()) def set_password(self, _rpdb2_pwd): assert(is_unicode(_rpdb2_pwd)) if not is_valid_pwd(_rpdb2_pwd): raise BadArgument try: self.m_state_manager.acquire() self.__verify_unattached() self.m_rpdb2_pwd = _rpdb2_pwd finally: self.m_state_manager.release() def set_random_password(self): try: self.m_state_manager.acquire() self.__verify_unattached() self.m_rpdb2_pwd = generate_random_password() self.m_printer(STR_RANDOM_PASSWORD) finally: self.m_state_manager.release() def get_password(self): return self.m_rpdb2_pwd def set_remote(self, fAllowRemote): try: self.m_state_manager.acquire() self.__verify_unattached() self.m_fAllowRemote = fAllowRemote finally: self.m_state_manager.release() def get_remote(self): return self.m_fAllowRemote def set_environ(self, envmap): self.m_environment = [] try: for k, v in envmap: k = as_unicode(k, fstrict = True) v = as_unicode(v, fstrict = True) self.m_environment.append((k, v)) except: raise BadArgument def get_environ(self): return self.m_environment def stop_debuggee(self): self.__verify_attached() try: self.save_breakpoints() except: print_debug_exception() pass self.m_printer(STR_ATTEMPTING_TO_STOP) self.m_printer(STR_ATTEMPTING_TO_DETACH) self.m_state_manager.set_state(STATE_DETACHING) self.__stop_event_monitor() try: self.getSession().getProxy().stop_debuggee() finally: self.m_state_manager.set_state(STATE_DETACHED) self.m_session = None self.m_printer(STR_DETACH_SUCCEEDED) class CConsoleInternal(cmd.Cmd, threading.Thread): def __init__(self, session_manager, stdin = None, stdout = None, fSplit = False): global g_fDefaultStd cmd.Cmd.__init__(self, stdin = stdin, stdout = stdout) threading.Thread.__init__(self) self.fAnalyzeMode = False self.fPrintBroken = True self.m_filename = as_unicode('') self.m_completion_thread = None self.use_rawinput = [1, 0][fSplit] self.m_fSplit = fSplit self.prompt = [[CONSOLE_PROMPT, CONSOLE_PROMPT_ANALYZE][self.fAnalyzeMode], ""][fSplit] self.intro = CONSOLE_INTRO if fSplit: self.intro += '\n' #self.setDaemon(True) self.m_session_manager = session_manager self.m_session_manager.set_printer(self.printer) event_type_dict = {CEventState: {}} self.m_session_manager.register_callback(self.event_handler, event_type_dict, fSingleUse = False) event_type_dict = {CEventSynchronicity: {}} self.m_session_manager.register_callback(self.synchronicity_handler, event_type_dict, fSingleUse = False) event_type_dict = {CEventTrap: {}} self.m_session_manager.register_callback(self.trap_handler, event_type_dict, fSingleUse = False) event_type_dict = {CEventForkMode: {}} self.m_session_manager.register_callback(self.fork_mode_handler, event_type_dict, fSingleUse = False) self.m_last_source_line = None self.m_last_nlines = DEFAULT_NUMBER_OF_LINES self.m_fAddPromptBeforeMsg = False self.m_eInLoop = threading.Event() self.cmdqueue.insert(0, '') self.m_stdout = self.stdout self.m_encoding = detect_encoding(self.stdin) g_fDefaultStd = (stdin == None) if self.use_rawinput: try: import readline cd = readline.get_completer_delims() if not '.' in cd: readline.set_completer_delims(cd + '.') except: pass def set_filename(self, filename): assert(is_unicode(filename)) self.m_filename = filename def precmd(self, line): line = as_unicode(line, self.m_encoding) self.m_fAddPromptBeforeMsg = True if not self.m_eInLoop.isSet(): self.m_eInLoop.set() time.sleep(0.01) if not line.strip(): return line command = line.split(' ', 1)[0].split(SOURCE_MORE, 1)[0].split(SOURCE_LESS, 1)[0] if command not in ['list', 'l']: self.m_last_source_line = None self.m_last_nlines = DEFAULT_NUMBER_OF_LINES return line def postcmd(self, stop, line): self.m_fAddPromptBeforeMsg = False return stop def onecmd(self, line): """ Default Error handling and reporting of session manager errors. """ try: return cmd.Cmd.onecmd(self, line) except (socket.error, CConnectionException): self.m_session_manager.report_exception(*sys.exc_info()) except CException: self.m_session_manager.report_exception(*sys.exc_info()) except: self.m_session_manager.report_exception(*sys.exc_info()) print_debug_exception(True) return False def emptyline(self): pass def complete(self, text, state): """ Return the next possible completion for 'text'. If a command has not been entered, then complete against command list. Otherwise try to call complete_ to get list of completions. """ if self.use_rawinput: # # Import cmd to workaround a strange bug in Python. # import cmd return cmd.Cmd.complete(self, text, state) # # Without rawinput assuming text includes entire buffer up to cursor. # try: if state != 0: return self.completion_matches[state] if not ' ' in text: self.completion_matches = self.completenames(text) return self.completion_matches[state] cmd, args, foo = self.parseline(text) if cmd == '' or not hasattr(self, 'complete_' + cmd): self.completion_matches = self.completedefault(text) return self.completion_matches[state] compfunc = getattr(self, 'complete_' + cmd) self.completion_matches = compfunc(text) return self.completion_matches[state] except IndexError: return None def complete_launch(self, text, line = None, begidx = None, endidx = None): if line != None and endidx != None: text = line[:endidx] if text.endswith(' '): dn, bn = '', '' else: path = text.split()[-1] dn, bn = os.path.split(path) prefix = text if bn != '': prefix = prefix[:-len(bn)] if dn == '' and bn.startswith('~'): if bn == os.path.expanduser(bn): c = text else: c = os.path.join(text, '') if begidx != None: c = c[begidx:] return [c] pl = [dn] if dn == '': pl += os.environ['PATH'].split(os.pathsep) fl = [] for p in pl: if p == '': p = '.' try: ep = os.path.expanduser(p) l = os.listdir(ep) for f in l: if not f.startswith(bn): continue root, ext = os.path.splitext(f) if not ext in ['.py', '.pyw', '']: continue if os.path.isdir(os.path.join(ep, f)): c = prefix + os.path.join(f, '') else: c = prefix + f if begidx != None: c = c[begidx:] fl.append(c) except: pass fs = set(fl) cl = list(fs) cl.sort() return cl def complete_eval(self, text, line = None, begidx = None, endidx = None): t = self.m_completion_thread if t != None and t.isAlive(): return [] self.m_completion_thread = None result = [('', [])] if line != None and endidx != None: text = line[:endidx] t = threading.Thread(target = self.complete_expression_job, args = (text, result)) t.start() t.join(PING_TIMEOUT) if t.isAlive(): self.m_completion_thread = t return [] (prefix, completions) = result[-1] if begidx != None: prefix = prefix[begidx:] ce = [prefix + c for c in completions] return ce complete_v = complete_eval complete_exec = complete_eval complete_x = complete_exec def complete_expression_job(self, text, result): try: (prefix, completions) = self.m_session_manager.complete_expression(text) result.append((prefix, completions)) except: print_debug_exception() def run(self): self.cmdloop() def __get_str_wrap(self, _str, max_len): if len(_str) <= max_len and not '\n' in _str: return (_str, '') s = _str[: max_len] i = s.find('\n') if i == -1: i = s.rfind(' ') if i == -1: return (s, _str[max_len:]) return (_str[: i], _str[i + 1:]) def printer(self, _str): if not self.m_eInLoop.isSet(): self.m_eInLoop.wait() fAPBM = self.m_fAddPromptBeforeMsg prefix = ['', self.prompt.strip('\n')][fAPBM] + CONSOLE_PRINTER suffix = '\n' + [self.prompt.strip('\n'), ''][fAPBM] s = _str while s != '': s, _s = self.__get_str_wrap(s, CONSOLE_WRAP_INDEX - len(prefix + suffix)) _print(prefix + s + suffix, self.m_stdout, feol = False) s = _s self.m_stdout.flush() def print_notice(self, notice): nl = notice.split('\n') i = 0 for l in nl: _print(l, self.m_stdout) i += 1 if i % PRINT_NOTICE_LINES_PER_SECTION == 0: _print("\n" + PRINT_NOTICE_PROMPT, self.m_stdout, feol = False) response = self.stdin.readline() if response != '\n': break _print('', self.m_stdout) def event_handler(self, event): state = event.m_state if (state == STATE_BROKEN) and self.fPrintBroken: self.fPrintBroken = False self.printer(STR_DEBUGGER_HAS_BROKEN) return if (state != STATE_ANALYZE) and self.fAnalyzeMode: self.fAnalyzeMode = False self.prompt = [CONSOLE_PROMPT, ""][self.m_fSplit] self.printer(STR_ANALYZE_MODE_TOGGLE % MODE_OFF) return if (state == STATE_ANALYZE) and not self.fAnalyzeMode: self.fAnalyzeMode = True self.prompt = [CONSOLE_PROMPT_ANALYZE, ""][self.m_fSplit] self.printer(STR_ANALYZE_MODE_TOGGLE % MODE_ON) return def synchronicity_handler(self, event): self.printer(STR_SYNCHRONICITY_MODE % str(event.m_fsynchronicity)) def trap_handler(self, event): self.printer(STR_TRAP_MODE_SET % str(event.m_ftrap)) def fork_mode_handler(self, event): x = [FORK_PARENT, FORK_CHILD][event.m_ffork_into_child] y = [FORK_MANUAL, FORK_AUTO][event.m_ffork_auto] self.printer(STR_FORK_MODE_SET % (x, y)) def do_launch(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return if arg[:2] == '-k': fchdir = False _arg = arg[2:].strip() else: fchdir = True _arg = arg self.fPrintBroken = True try: self.m_session_manager.launch(fchdir, _arg) return except BadArgument: self.printer(STR_BAD_ARGUMENT) except IOError: self.printer(STR_FILE_NOT_FOUND % arg) except: self.fPrintBroken = False raise self.fPrintBroken = False def do_restart(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return try: self.m_session_manager.restart() return except BadArgument: self.printer(STR_BAD_ARGUMENT) except IOError: self.printer(STR_FILE_NOT_FOUND % arg) except: self.fPrintBroken = False raise self.fPrintBroken = False def do_attach(self, arg): if arg == '': return self.__scripts(arg) self.fPrintBroken = True try: self.m_session_manager.attach(arg) return except BadArgument: self.printer(STR_BAD_ARGUMENT) except: self.fPrintBroken = False raise self.fPrintBroken = False def __scripts(self, arg): if self.m_session_manager.get_password() is None: _print(STR_PASSWORD_MUST_BE_SET, self.m_stdout) return host = self.m_session_manager.get_host() _print(STR_SCRIPTS_CONNECTING % host, self.m_stdout) (server_list, errors) = self.m_session_manager.calc_server_list() if server_list == []: _print(STR_SCRIPTS_NO_SCRIPTS % host, self.m_stdout) return try: spid = self.m_session_manager.get_server_info().m_pid except NotAttached: spid = None _print(STR_SCRIPTS_TO_DEBUG % host, self.m_stdout) for s in server_list: m = ['', SYMBOL_MARKER][spid == s.m_pid] _print(' %1s %-5d %s' % (m, s.m_pid, s.m_filename), self.m_stdout) def do_detach(self, arg): if not arg == '': self.printer(STR_BAD_ARGUMENT) return self.m_session_manager.detach() def do_host(self, arg): if arg == '': host = self.m_session_manager.get_host() _print(host, self.m_stdout) return try: self.m_session_manager.set_host(arg) except socket.gaierror: e = sys.exc_info()[1] self.printer(MSG_ERROR_HOST_TEXT % (arg, e)) def do_break(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return self.m_session_manager.request_break() do_b = do_break def __parse_bp_arg(self, arg, fAllowExpr = True): _args = arg.split(BP_EVAL_SEP) if (len(_args) > 1) and (not fAllowExpr): raise BadArgument if len(_args) > 1: expr = _args[1].strip() else: expr = '' rf = _args[0].rfind(BP_FILENAME_SEP) if rf == -1: args = [_args[0]] else: args = [_args[0][:rf], _args[0][rf + 1:]] filename = ['', args[0]][len(args) > 1] if filename in [None, '']: filename = self.m_filename try: lineno = int(args[-1]) scope = '' except ValueError: lineno = 0 scope = args[-1].strip() return (filename, scope, lineno, expr) def do_go(self, arg): if self.fAnalyzeMode: self.printer(STR_ILEGAL_ANALYZE_MODE_CMD) return try: if arg != '': (filename, scope, lineno, expr) = self.__parse_bp_arg(arg, fAllowExpr = False) self.fPrintBroken = True self.m_session_manager.request_go_breakpoint(filename, scope, lineno) return self.fPrintBroken = True self.m_session_manager.request_go() return except BadArgument: self.printer(STR_BAD_ARGUMENT) except IOError: self.printer(STR_FILE_NOT_FOUND % filename) except InvalidScopeName: self.printer(STR_SCOPE_NOT_FOUND % scope) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) except: self.fPrintBroken = False raise self.fPrintBroken = False do_g = do_go def do_step(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return if self.fAnalyzeMode: self.printer(STR_ILEGAL_ANALYZE_MODE_CMD) return try: self.m_session_manager.request_step() except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_s = do_step def do_next(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return if self.fAnalyzeMode: self.printer(STR_ILEGAL_ANALYZE_MODE_CMD) return try: self.m_session_manager.request_next() except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_n = do_next def do_return(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return if self.fAnalyzeMode: self.printer(STR_ILEGAL_ANALYZE_MODE_CMD) return try: self.m_session_manager.request_return() except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_r = do_return def do_jump(self, arg): try: lineno = int(arg) except ValueError: self.printer(STR_BAD_ARGUMENT) return try: self.m_session_manager.request_jump(lineno) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_j = do_jump def do_bp(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return try: (filename, scope, lineno, expr) = self.__parse_bp_arg(arg, fAllowExpr = True) self.m_session_manager.set_breakpoint(filename, scope, lineno, True, expr) except BadArgument: self.printer(STR_BAD_ARGUMENT) except IOError: self.printer(STR_FILE_NOT_FOUND % filename) except InvalidScopeName: self.printer(STR_SCOPE_NOT_FOUND % scope) except SyntaxError: self.printer(STR_BAD_EXPRESSION % expr) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) def do_be(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return try: id_list = [] fAll = (arg == SYMBOL_ALL) if not fAll: sid_list = arg.split() id_list = [int(sid) for sid in sid_list] self.m_session_manager.enable_breakpoint(id_list, fAll) except ValueError: self.printer(STR_BAD_ARGUMENT) def do_bd(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return try: id_list = [] fAll = (arg == SYMBOL_ALL) if not fAll: sid_list = arg.split() id_list = [int(sid) for sid in sid_list] self.m_session_manager.disable_breakpoint(id_list, fAll) except ValueError: self.printer(STR_BAD_ARGUMENT) def do_bc(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return try: id_list = [] fAll = (arg == SYMBOL_ALL) if not fAll: sid_list = arg.split() id_list = [int(sid) for sid in sid_list] self.m_session_manager.delete_breakpoint(id_list, fAll) except ValueError: self.printer(STR_BAD_ARGUMENT) def do_bl(self, arg): bpl = self.m_session_manager.get_breakpoints() bplk = list(bpl.keys()) bplk.sort() _print(STR_BREAKPOINTS_LIST, self.m_stdout) for id in bplk: bp = bpl[id] if bp.m_expr: expr = bp.m_expr else: expr = '' try: expr.encode('ascii', 'strict') encoding = '' except: encoding = bp.m_encoding scope = bp.m_scope_fqn if scope.startswith(MODULE_SCOPE + '.'): scope = scope[len(MODULE_SCOPE) + 1:] elif scope.startswith(MODULE_SCOPE2 + '.'): scope = scope[len(MODULE_SCOPE2) + 1:] state = [STATE_DISABLED, STATE_ENABLED][bp.isEnabled()] s = STR_BREAKPOINTS_TEMPLATE % (id, state, bp.m_lineno, clip_filename(bp.m_filename, 45), calc_suffix(scope, 45), calc_prefix(expr, 50), encoding) _print(s.rstrip() + '\n', self.m_stdout) def do_save(self, arg): self.m_session_manager.save_breakpoints(arg) _print(STR_BREAKPOINTS_SAVED, self.m_stdout) return def do_load(self, arg): try: self.m_session_manager.load_breakpoints(arg) _print(STR_BREAKPOINTS_LOADED, self.m_stdout) return except IOError: error = [STR_BREAKPOINTS_FILE_NOT_FOUND, STR_BREAKPOINTS_NOT_FOUND][arg == ''] self.printer(error) def do_stack(self, arg): if self.fAnalyzeMode and (arg != ''): self.printer(STR_ILEGAL_ANALYZE_MODE_ARG) return try: tid_list = [] fAll = (arg == SYMBOL_ALL) if not fAll: sid_list = arg.split() tid_list = [int(sid) for sid in sid_list] sl = self.m_session_manager.get_stack(tid_list, fAll) if len(sl) == 0: self.printer(STR_NO_THREADS_FOUND) return frame_index = self.m_session_manager.get_frame_index() m = None for st in sl: s = st.get(DICT_KEY_STACK, []) tid = st.get(DICT_KEY_TID, 0) fBroken = st.get(DICT_KEY_BROKEN, False) fCurrent = st.get(DICT_KEY_CURRENT_TID, False) if m is not None: _print('', self.m_stdout) _print(STR_STACK_TRACE % tid, self.m_stdout) i = 0 while i < len(s): e = s[-(1 + i)] marker = [SOURCE_STATE_UNBROKEN, SYMBOL_MARKER][fBroken] if fCurrent: m = ['', marker][i == frame_index] else: m = ['', marker][i == 0] _print(' %1s %5d %-28s %4d %s' % (m, i, calc_suffix(e[0], 28), e[1], calc_prefix(e[2], 20)), self.m_stdout) i += 1 except ValueError: self.printer(STR_BAD_ARGUMENT) except (NoExceptionFound, NoThreads): self.m_session_manager.report_exception(*sys.exc_info()) do_k = do_stack def do_list(self, arg): rf = arg.rfind(BP_FILENAME_SEP) if rf == -1: _filename = '' __args2 = arg else: _filename = arg[:rf] __args2 = arg[rf + 1:] _args = __args2.split(BP_EVAL_SEP) fAll = (_args[0] == SYMBOL_ALL) fMore = (_args[0] == SOURCE_MORE) fLess = (_args[0] == SOURCE_LESS) fEntire = (_args[0] == SOURCE_ENTIRE_FILE) fCurrent = (_args[0] == '') fLine = False l = 1 try: if len(_args) > 1: nlines = int(_args[1]) else: nlines = self.m_last_nlines if not (fAll or fMore or fLess or fEntire or fCurrent): l = int(_args[0]) fLine = True except ValueError: self.printer(STR_BAD_ARGUMENT) return if self.fAnalyzeMode and fAll: self.printer(STR_ILEGAL_ANALYZE_MODE_ARG) return if fMore and self.m_last_source_line: l = max(1, self.m_last_source_line + self.m_last_nlines // 2 + 1) fLine = True elif fLess and self.m_last_source_line: l = max(1, self.m_last_source_line - (self.m_last_nlines - 1) // 2 - nlines) fLine = True try: if fEntire: r = [self.m_session_manager.get_source_file(_filename, -1, -1)] elif fLine: r = [self.m_session_manager.get_source_file(_filename, l, nlines)] elif _filename != '': r = [self.m_session_manager.get_source_file(_filename, l, nlines)] else: r = self.m_session_manager.get_source_lines(nlines, fAll) if len(r) == 0: self.printer(STR_NO_THREADS_FOUND) return m = None for d in r: tid = d.get(DICT_KEY_TID, 0) filename = d.get(DICT_KEY_FILENAME, '') breakpoints = d.get(DICT_KEY_BREAKPOINTS, {}) source_lines = d.get(DICT_KEY_LINES, []) first_lineno = d.get(DICT_KEY_FIRST_LINENO, 0) if len(r) == 1 and first_lineno != 0: l = first_lineno fBroken = d.get(DICT_KEY_BROKEN, False) frame_event = d.get(DICT_KEY_EVENT, '') frame_lineno = d.get(DICT_KEY_FRAME_LINENO, 0) if m is not None: _print('', self.m_stdout) _print(STR_SOURCE_LINES % (tid, filename), self.m_stdout) for i, line in enumerate(source_lines): lineno = first_lineno + i if lineno != frame_lineno: m = '' elif not fBroken: m = SOURCE_STATE_UNBROKEN + SYMBOL_MARKER elif frame_event == 'call': m = SOURCE_EVENT_CALL + SYMBOL_MARKER elif frame_event == 'line': m = SOURCE_EVENT_LINE + SYMBOL_MARKER elif frame_event == 'return': m = SOURCE_EVENT_RETURN + SYMBOL_MARKER elif frame_event == 'exception': m = SOURCE_EVENT_EXCEPTION + SYMBOL_MARKER if breakpoints.get(lineno, None) == STATE_ENABLED: b = SOURCE_BP_ENABLED elif breakpoints.get(lineno, None) == STATE_DISABLED: b = SOURCE_BP_DISABLED else: b = '' line = line.replace('\t', ' ' * PYTHON_TAB_WIDTH) _print(' %2s %1s %5d %s' % (m, b, lineno, calc_prefix(line[:-1], 60)), self.m_stdout) if fAll or fEntire: self.m_last_source_line = None elif len(source_lines) != 0: self.m_last_source_line = [l + (nlines - 1) // 2, frame_lineno][l == -1] self.m_last_nlines = nlines except (InvalidFrame, IOError): self.printer(STR_SOURCE_NOT_FOUND) except (NoExceptionFound, NoThreads): self.m_session_manager.report_exception(*sys.exc_info()) do_l = do_list def do_up(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return try: fi = self.m_session_manager.get_frame_index() self.m_session_manager.set_frame_index(fi - 1) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) def do_down(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return try: fi = self.m_session_manager.get_frame_index() self.m_session_manager.set_frame_index(fi + 1) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) def evaluate_job(self, sync_event, expr): try: (value, warning, error) = self.m_session_manager.evaluate(expr) if warning: self.printer(STR_WARNING % warning) if error: _print(error + '\n', self.m_stdout) _print(value, self.m_stdout) if sync_event.isSet(): _print(self.prompt, self.m_stdout, feol = False) return except (NoExceptionFound, DebuggerNotBroken): self.m_session_manager.report_exception(*sys.exc_info()) except (socket.error, CConnectionException): self.m_session_manager.report_exception(*sys.exc_info()) except CException: self.m_session_manager.report_exception(*sys.exc_info()) except: self.m_session_manager.report_exception(*sys.exc_info()) print_debug_exception(True) def do_eval(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return sync_event = threading.Event() t = threading.Thread(target = self.evaluate_job, args = (sync_event, arg)) t.start() t.join(WAIT_FOR_BREAK_TIMEOUT) if t.isAlive(): _print(STR_OUTPUT_WARNING_ASYNC, self.m_stdout) sync_event.set() do_v = do_eval def execute_job(self, sync_event, suite): try: (warning, error) = self.m_session_manager.execute(suite) if warning: self.printer(STR_WARNING % warning) if error: _print(error + '\n', self.m_stdout) if sync_event.isSet(): _print(self.prompt, self.m_stdout, feol = False) return except (NoExceptionFound, DebuggerNotBroken): self.m_session_manager.report_exception(*sys.exc_info()) except (socket.error, CConnectionException): self.m_session_manager.report_exception(*sys.exc_info()) except CException: self.m_session_manager.report_exception(*sys.exc_info()) except: self.m_session_manager.report_exception(*sys.exc_info()) print_debug_exception(True) def do_exec(self, arg): if arg == '': self.printer(STR_BAD_ARGUMENT) return _print(STR_OUTPUT_WARNING, self.m_stdout) sync_event = threading.Event() t = threading.Thread(target = self.execute_job, args = (sync_event, arg)) t.start() t.join(WAIT_FOR_BREAK_TIMEOUT) if t.isAlive(): _print(STR_OUTPUT_WARNING_ASYNC, self.m_stdout) sync_event.set() do_x = do_exec def do_encoding(self, arg): if arg == '': encoding, fraw = self.m_session_manager.get_encoding() if encoding != ENCODING_AUTO: try: codecs.lookup(encoding) except: encoding += ' (?)' if fraw: encoding += ', ' + ENCODING_RAW _print(STR_ENCODING_MODE % encoding, self.m_stdout) return if ',' in arg: encoding, raw = arg.split(',') else: encoding, raw = arg, '' encoding = encoding.strip() if encoding == '': encoding, fraw = self.m_session_manager.get_encoding() fraw = 'raw' in raw self.m_session_manager.set_encoding(encoding, fraw) if encoding != ENCODING_AUTO: try: codecs.lookup(encoding) except: encoding += ' (?)' _print(STR_ENCODING_BAD, self.m_stdout) if fraw: encoding += ', ' + ENCODING_RAW _print(STR_ENCODING_MODE_SET % encoding, self.m_stdout) def do_thread(self, arg): if self.fAnalyzeMode and (arg != ''): self.printer(STR_ILEGAL_ANALYZE_MODE_ARG) return try: if arg != '': tid = int(arg) self.m_session_manager.set_thread(tid) _print(STR_THREAD_FOCUS_SET, self.m_stdout) return (current_thread_id, tl) = self.m_session_manager.get_thread_list() _print(STR_ACTIVE_THREADS, self.m_stdout) for i, t in enumerate(tl): m = ['', SYMBOL_MARKER][t[DICT_KEY_TID] == current_thread_id] state = [STATE_RUNNING, STR_STATE_BROKEN][t[DICT_KEY_BROKEN]] _print(' %1s %3d %5d %-15s %s' % (m, i, t[DICT_KEY_TID], t[DICT_KEY_NAME], state[:25]), self.m_stdout) except ValueError: self.printer(STR_BAD_ARGUMENT) except ThreadNotFound: self.printer(STR_THREAD_NOT_FOUND) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_t = do_thread def do_analyze(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return try: self.m_session_manager.set_analyze(not self.fAnalyzeMode) except DebuggerNotBroken: self.m_session_manager.report_exception(*sys.exc_info()) do_a = do_analyze def do_synchro(self, arg): if arg == '': fsynchronicity = self.m_session_manager.get_synchronicity() _print(STR_SYNCHRONICITY_MODE % str(fsynchronicity), self.m_stdout) return if arg == str(True): fsynchronicity = True elif arg == str(False): fsynchronicity = False else: _print(STR_BAD_ARGUMENT, self.m_stdout) return self.m_session_manager.set_synchronicity(fsynchronicity) def do_trap(self, arg): if arg == '': ftrap = self.m_session_manager.get_trap_unhandled_exceptions() _print(STR_TRAP_MODE % str(ftrap), self.m_stdout) return if arg == str(True): ftrap = True elif arg == str(False): ftrap = False else: _print(STR_BAD_ARGUMENT, self.m_stdout) return self.m_session_manager.set_trap_unhandled_exceptions(ftrap) def do_fork(self, arg): (ffork_into_child, ffork_auto) = self.m_session_manager.get_fork_mode() if arg == '': x = [FORK_PARENT, FORK_CHILD][ffork_into_child] y = [FORK_MANUAL, FORK_AUTO][ffork_auto] _print(STR_FORK_MODE % (x, y), self.m_stdout) return arg = arg.lower() if FORK_PARENT in arg: ffork_into_child = False elif FORK_CHILD in arg: ffork_into_child = True if FORK_AUTO in arg: ffork_auto = True elif FORK_MANUAL in arg: ffork_auto = False self.m_session_manager.set_fork_mode(ffork_into_child, ffork_auto) def do_password(self, arg): if arg == '': _rpdb2_pwd = self.m_session_manager.get_password() if _rpdb2_pwd is None: _print(STR_PASSWORD_NOT_SET, self.m_stdout) else: _print(STR_PASSWORD_SET % _rpdb2_pwd, self.m_stdout) return _rpdb2_pwd = arg.strip('"\'') try: self.m_session_manager.set_password(_rpdb2_pwd) _print(STR_PASSWORD_SET % _rpdb2_pwd, self.m_stdout) except BadArgument: _print(STR_PASSWORD_BAD, self.m_stdout) def do_remote(self, arg): if arg == '': fAllowRemote = self.m_session_manager.get_remote() _print(STR_REMOTE_MODE % str(fAllowRemote), self.m_stdout) return if arg == str(True): fAllowRemote = True elif arg == str(False): fAllowRemote = False else: _print(STR_BAD_ARGUMENT, self.m_stdout) return self.m_session_manager.set_remote(fAllowRemote) _print(STR_REMOTE_MODE % str(fAllowRemote), self.m_stdout) def do_env(self, arg): env = self.m_session_manager.get_environ() if arg == '': if len(env) == 0: _print(STR_ENVIRONMENT_EMPTY, self.m_stdout) return _print(STR_ENVIRONMENT, self.m_stdout) for k, v in env: _print('%s=%s' % (k, v), self.m_stdout) return if arg[:2] == '-d': k = arg[2:].strip() _env = [(_k, _v) for (_k, _v) in env if _k != k] self.m_session_manager.set_environ(_env) return try: k, v = arg.split('=') k = k.strip() v = v.strip() except ValueError: self.printer(STR_BAD_ARGUMENT) return _env = [(_k, _v) for (_k, _v) in env if _k != k] _env.append((k, v)) self.m_session_manager.set_environ(_env) def do_stop(self, arg): self.m_session_manager.stop_debuggee() def do_exit(self, arg): if arg != '': self.printer(STR_BAD_ARGUMENT) return if self.m_session_manager.get_state() != STATE_DETACHED: try: self.do_stop('') except (socket.error, CConnectionException): self.m_session_manager.report_exception(*sys.exc_info()) except CException: self.m_session_manager.report_exception(*sys.exc_info()) except: self.m_session_manager.report_exception(*sys.exc_info()) print_debug_exception(True) _print('', self.m_stdout) return True do_EOF = do_exit def do_copyright(self, arg): self.print_notice(COPYRIGHT_NOTICE) def do_license(self, arg): self.print_notice(LICENSE_NOTICE + COPY_OF_THE_GPL_LICENSE) def do_credits(self, arg): self.print_notice(CREDITS_NOTICE) def do_help(self, arg): cmd.Cmd.do_help(self, arg) if arg == '': help_notice = """Security: ---------------- password - Get or set the channel password. remote - Get or set "allow connections from remote machines" mode. Session Control: ----------------- env - Display or set the environment setting for new sessions. host - Display or change host. attach - Display scripts or attach to a script on host. detach - Detach from script. launch - Start a script and attach to it. restart - Restart a script. stop - Shutdown the debugged script. exit - Exit from debugger. Debuggee Control: ----------------- break - Request an immediate break. step - Continue to the next execution line. next - Continue to the next execution line in the current frame. return - Continue until the debugger is about to return from the frame. jump - Jump to a line in the current scope. go - Continue execution. Breakpoints Control: -------------------- bp - Set a break point. bd - Disable a breakpoint. be - Enable a breakpoint. bc - Clear (delete) a breakpoint. bl - List all breakpoints. load - Load session breakpoints. save - save session breakpoints. Misc: ----- thread - Display threads or switch to a particular thread. list - List source code. stack - Display stack trace. up - Go up one frame in stack. down - Go down one frame in stack. encoding - Set the source encoding used by exec and eval commands. eval - Evaluate expression in the context of the current frame. exec - Execute suite in the context of the current frame. analyze - Toggle analyze last exception mode. trap - Get or set "trap unhandled exceptions" mode. fork - Get or set fork handling mode. synchro - Get or set synchronicity mode. License: ---------------- copyright - Print copyright notice. license - Print license. credits - Print credits information. type help for futher information.""" self.print_notice(help_notice) def help_copyright(self): _print("""copyright Print copyright notice.""", self.m_stdout) def help_license(self): _print("""license Print license.""", self.m_stdout) def help_credits(self): _print("""credits Print credits information.""", self.m_stdout) def help_help(self): _print("""help Print help for command . On the other hand I guess that you already know that, don't you?""", self.m_stdout) def help_analyze(self): _print("""analyze (shorthand - a) Toggle analyze last exception mode. The following changes to the debugger behavior apply in analyze mode: The debugger prompt changes to 'Analyze>'. 'go', 'step', 'next', and 'return' are not allowed. 'thread' does not allow to change the thread focus. 'stack' allows no arguments. 'list' does not accept the '*' (all threads) argument 'stack', 'list', 'eval', 'exec', 'up', and 'down' operate on the thrown exception.""", self.m_stdout) help_a = help_analyze def help_password(self): _print("""password Get or set the channel password. Communication between the console and the debuggee is always authenticated and optionally encrypted. The password (A secret known to the console and the debuggee alone) governs both security methods. The password is never communicated between the two components on the communication channel. A password is always required since unsecured communication between the console and the debuggee might expose your machine to attacks.""", self.m_stdout) def help_remote(self): _print("""remote [True | False] Get or set "allow connections from remote machines" mode. When set to False: Newly launched debuggees will listen on localhost only. In this mode, debugger consoles on remote machines will NOT BE able to see or attach to the debuggee. When set to True: Newly launched debuggees will listen on INADDR_ANY. In this mode, debugger consoles on remote machines will BE able to see and attach to the debuggee.""", self.m_stdout) def help_trap(self): _print("""trap [True | False] Get or set "trap unhandled exceptions" mode. When set to False: Debuggee will ignore unhandled exceptions. When set to True: Debuggee will pause on unhandled exceptions for inspection.""", self.m_stdout) def help_synchro(self): _print("""synchro [True | False] Get or set the synchronicity mode. Traditional Python debuggers that use the inspected thread (usually the main thread) to query or modify the script name-space have to wait until the script hits a break-point. Synchronicity allows the debugger to query and modify the script name-space even if its threads are still running or blocked in C library code by using special worker threads. In some rare cases querying or modifying data in synchronicity can crash the script. For example in some Linux builds of wxPython querying the state of wx objects from a thread other than the GUI thread can crash the script. If this happens or if you want to restrict these operations to the inspected thread, turn synchronicity off. Default is True.""", self.m_stdout) def help_fork(self): _print("""fork [parent | child] [manual | auto] Get or set fork handling mode. Without arguments returns the current mode. When 'parent' is specified the debugger will continue to debug the original parent process after a fork. When 'child' is specified the debugger will switch to debug the forked child process after a fork. When 'manual' is specified the debugger will pause before doing a fork. When 'auto' is specified the debugger will go through the fork without pausing and will make the forking decision based on the parent/child setting. WARNING: On some Posix OS such as FreeBSD, Stepping into the child fork can result in termination of the child process since the debugger uses threading for its operation and on these systems threading and forking can conflict. """, self.m_stdout) def help_stop(self): _print("""stop Shutdown the debugged script.""", self.m_stdout) def help_launch(self): _print("""launch [-k] [] Start script and attach to it. -k Don't change the current working directory. By default the working directory of the launched script is set to its folder.""", self.m_stdout) def help_restart(self): _print("""restart Restart a script with same arguments from last launch.""", self.m_stdout) def help_attach(self): _print("""attach [] Without an argument, 'attach' prints the scripts available for debugging on the selected host. To select a host use the 'host' command. A script is considered available for debugging only if it is using the rpdb2 module or has been executed by the debugger. If the debugger is already attached to a script, a special character will mark that script in the list. When is an integer the debugger will try to attach to a script with that pid. When is a string the debugger will try to attach to a script with that name in the list.""", self.m_stdout) def help_detach(self): _print("""detach Detach from the script the debugger is currently attached to. The detached script will continue execution.""", self.m_stdout) def help_break(self): _print("""break (shorthand - b) Request script to break (pause execution as if it hit a breakpoint). The 'break' command returns immdeiately but the break is only established when an active thread submits to the debugger control. If a thread is doing a system call or executing C code, this will happen only when it returns to do python code.""", self.m_stdout) help_b = help_break def help_bp(self): _print("""bp [':'] ( | ) [',' ] Set a breakpoint. - either the filename or the module name. - is the line number to assign the breakpoint to. - is a "fully qualified" function name. That is, not only the function name but also the class name (in case of a member function), such as MyClass.MyMemberFunction. - condition to evaluate in the context of the frame. If it evaluates to 'True' the break point will break into the debugger. In case the is omitted, the current file is assumed. In this case the debuggee has to be waiting at break point. Examples: bp test_file.py:20 bp test_file.py:MyClass.Foo bp 304 Type 'help break' for more information on breakpoints and threads.""", self.m_stdout) def help_be(self): _print("""be ( | '*') Enable breakpoints. - is a space delimited list of at least one breakpoint id '*' - Enable all breakpoints.""", self.m_stdout) def help_bd(self): _print("""bd ( | '*') Disable breakpoints. - is a space delimited list of at least one breakpoint id '*' - disable all breakpoints.""", self.m_stdout) def help_bc(self): _print("""bc ( | '*') Clear (delete) breakpoints. - is a space delimited list of at least one breakpoint id '*' - clear all breakpoints.""", self.m_stdout) def help_bl(self): _print("""bl List all breakpoints, sorted by their id.""", self.m_stdout) def help_load(self): _print("""load [] Load breakpoints. - optional breakpoints filename. The filename should not include a file extension.""", self.m_stdout) def help_save(self): _print("""save [] save breakpoints. - optional breakpoints filename. The filename should not include a file extension.""", self.m_stdout) def help_go(self): _print("""go [[':'] ( | )] (shorthand - g) Resume execution of a script that is waiting at break point. If an argument is present, continue execution until that argument is reached. - is the file name which basically is the script's name without the '.py' extension. - is the line number to assign the breakpoint to. - is a "fully qualified" function name. That is, not only the function name but also the class name (in case of a member function), such as MyClass.MyMemberFunction.""", self.m_stdout) help_g = help_go def help_exit(self): _print("""exit Exit the debugger. If the debugger is attached to a script, the debugger will attempt to detach from the script first.""", self.m_stdout) help_EOF = help_exit def help_host(self): _print("""host [] Without an argument, 'host' prints the current selected host. With an argument , 'host' attempts to resolve to a known ip address or a domain name. If it is successful, that host will become the selected host. The default selected host is the local host. Subsequent 'attach' commands will be done on the selected host. Type 'help attach' for more information.""", self.m_stdout) def help_stack(self): _print("""stack [ | '*'] (shorthand - k) Without an argument, 'stack' prints the stack trace of the focused thread. If the thread is waiting at break point a special character will mark the focused frame. - print the stack of thread '*' - print the stacks of all active threads. Type 'help break' for more information on breakpoints and threads. Type 'help up' or 'help down' for more information on focused frames.""", self.m_stdout) help_k = help_stack def help_list(self): _print("""list [:][ | '+' | '-' | '^' | '*'] [',' ] (shorthand - l) Without an argument, 'list' prints the source lines around the current line of the focused thread in the focused frame. A special character sequence will mark the current line according to the event: 'C>' - call - A function is called. 'L>' - line - The interpreter is about to execute a new line of code. 'R>' - return - A function is about to return. 'E>' - exception - An exception has been thrown. '*>' - running - The thread is running. If a breakpoint is assigned to a line, that line will be marked with: 'B' - if the breakpoint is enabled 'D' - if the breakpoint is disabled - List source from filename - Print the source lines around that line number in the same file of the current line. '+' - Print the next lines in the file. '-' - Print the previous lines in the file. '^' - Print the entire file. '*' - Print the source lines for each of the active threads. - Print of source Type 'help break' for more information on breakpoints and threads. Type 'help up' or 'help down' for more information on focused frames.""", self.m_stdout) help_l = help_list def help_thread(self): _print("""thread [ | ] (shorthand - t) Without an argument, 'thread' prints the list of known active threads, with their corresponding state, which can be either 'running' or 'waiting at break point'. A special character will mark the focused thread. With an argument , 'thread' will attempt to set the debugger focus to the thread of that tid. With an argument , 'thread' will attempt to set the debugger focus to the thread of that order in the thread list. Type 'help break' for more information on breakpoints and threads.""", self.m_stdout) help_t = help_thread def help_jump(self): _print("""jump (shorthand - j) Jump to line in the current scope.""", self.m_stdout) help_j = help_jump def help_next(self): _print("""next (shorthand - n) Continue execution until the next line in the current function is reached or it returns.""", self.m_stdout) help_n = help_next def help_step(self): _print("""step (shorthand - s) Execute the current line, stop at the first possible occasion (either in a function that is called or in the current function).""", self.m_stdout) help_s = help_step def help_return(self): _print("""next (shorthand - r) Continue execution until the current function returns.""", self.m_stdout) help_r = help_return def help_up(self): _print("""up move the debugger focus one frame up the stack of the debugged thread (closer to the current, most recently executed frame). Evaluation of expressions or execution of statements will be done at the local and global name spaces of the focused frame. Type 'help eval' for more information on evaluation of expressions. Type 'help exec' for more information on execution of statements.""", self.m_stdout) def help_down(self): _print("""down move the debugger focus one frame down the stack of the debugged thread (closer to the current, most recently executed frame). Evaluation of expressions or execution of statements will be done at the local and global name spaces of the focused frame. Type 'help eval' for more information on evaluation of expressions. Type 'help exec' for more information on execution of statements.""", self.m_stdout) def help_eval(self): _print("""eval (shorthand - v) Evaluate the python expression under the global and local name spaces of the currently focused frame. Example: 'eval locals()' - will display the dictionary of the local variables. IMPORTANT: Any changes to the global name space will be discarded unless the focused stack frame is the top most frame. Type 'help up' or 'help down' for more information on focused frames.""", self.m_stdout) help_v = help_eval def help_exec(self): _print("""exec (shorthand - x) Execute the python suite under the global and local name spaces of the currently focused frame. Example: 'exec i += 1' IMPORTANT: Any changes to the global name space will be discarded unless the focused stack frame is the top most frame. Type 'help up' or 'help down' for more information on focused frames.""", self.m_stdout) help_x = help_exec def help_encoding(self): _print("""encoding [ [, raw]] Set the source encoding for the exec and eval commands. Without an argument returns the current encoding. The specified encoding can be either 'auto' or any encoding accepted by the codecs module. If 'auto' is specified, the source encoding of the active scope will be used, which is utf-8 by default. The default encoding value is 'auto'. If 'raw' is specified, strings returned by the eval command will represent non ASCII characters as an escape sequence.""", self.m_stdout) def help_env(self): _print("""env [-d key | key = value] Set the environment variables mapping. This mapping is used when a new script is launched to modify its environment. Example for a mapping on Windows: env Path = %Path%;c:\\mydir Example for a mapping on Linux: env PATH = $PATH:~/mydir To delete the mapping for PATH env -d PATH Without an argument returns the current list of mappings. Note that the mapping will be evaluated and used to modify the environment after the debugger engine at the debuggee has imported the modules it requires. The order in which the mappings will be evaluated and applied is: last set, last evaluated.""", self.m_stdout) # # ---------------------------------------- Replacement Functions ------------------------------------ # def rpdb2_import_wrapper(*args, **kwargs): if len(args) > 0: name = args[0] elif 'name' in kwargs: name = kwargs['name'] else: return g_import(*args, **kwargs) if name in sys.modules: return g_import(*args, **kwargs) # # rpdb2 avoids stepping through this # function (rpdb2_import_wrapper) to # prevent confusion when stepping into # an import statement. # m = g_import(*args, **kwargs) if name != 'gtk': return m try: m.gdk.threads_init() return m except: pass try: m.threads_init() return m except: pass return m g_import = None if __name__ == 'rpdb2' and g_builtins_module.__import__ != rpdb2_import_wrapper: g_import = g_builtins_module.__import__ g_builtins_module.__import__ = rpdb2_import_wrapper def __find_eval_exec_frame_in_stack(): f = sys._getframe(0) while f != None: filename = f.f_code.co_filename name = f.f_code.co_name if DEBUGGER_FILENAME in filename and name in ['_evaluate', '_execute'] and 'redirect_exc_info' in f.f_locals: return f f = f.f_back return None def __exc_info(): f = __find_eval_exec_frame_in_stack() if f == None: return g_sys_exc_info() try: frame_index = f.f_locals['frame_index'] fException = f.f_locals['fException'] e = g_debugger.get_exception(frame_index, fException) exc_info = (e['type'], e['value'], e['traceback']) return exc_info except: return g_sys_exc_info() g_sys_exc_info = None if __name__ == 'rpdb2' and 'exc_info' in dir(sys) and sys.exc_info != __exc_info: g_sys_exc_info = sys.exc_info sys.exc_info = __exc_info def __find_debugger_frame(): frame = None f = sys._getframe(0) while f != None: filename = f.f_code.co_filename name = f.f_code.co_name if DEBUGGER_FILENAME in filename and (name.startswith('trace_dispatch') or name == 'profile'): frame = f f = f.f_back return frame class CSignalHandler: def __del__(self): while len(g_signals_pending) != 0: (handler, signum, frameobj) = g_signals_pending.pop(0) print_debug('Handling pending signal: %s, %s' % (repr(signum), repr(frameobj))) try: handler(signum, frameobj) except: # # Can not raise from inside a destructor. Report that handler # exception will be ignored. # (t, v, tb) = sys.exc_info() _t = safe_repr(t) if _t.startswith(" [...]] %(rpdb)s uses the client-server model where the debugger UI/console is the client and the debugged script is the server (also called debuggee). The client and the server are separate processes and communicate over sockets. Example: The following command starts the debugger UI/console and then launches and attaches to the specified script: %(rpdb)s some_script.py Options can be a combination of the following: -h, --help Print this help. -d, --debuggee Start the debugged script (server) paused and wait for a debugger console (client) to attach. -a, --attach Start the debugger console (client) and attach to the specified debugged script (server) which is assumed to be running already. -o, --host= Specify host (or IP address) for remote connections. -r, --remote Allow debuggees to accept connections from remote machines. -e, --encrypt Force encrypted socket communication. -p, --pwd= Specify password for socket communication. This flag is available only on NT systems. On other systems the password will be queried interactively if it is needed. -s, --screen Use the Unix screen utility when starting the debuggee. Note that the debugger should be started as follows: screen rpdb2 -s [options] [ [...]] -c, --chdir Change the working directory to that of the launched script. --debug Debug prints. Note that each option is available in short form (example -e) and in a long form (example --encrypt). Options that end with '=' accept an argument that should follow without a space. For example to specify 192.168.0.10 as host use the following option: long form: --host=192.168.0.10 short form: -o192.168.0.10 """ % {"rpdb": scriptName}) if not fExtended: return _print(__doc__) def main(StartClient_func = StartClient): global g_fScreen global g_fDebug global g_fFirewallTest create_rpdb_settings_folder() encoding = detect_locale() argv = [as_unicode(arg, encoding) for arg in sys.argv] try: options, _rpdb2_args = getopt.getopt( argv[1:], 'hdao:rtep:sc', ['help', 'debugee', 'debuggee', 'attach', 'host=', 'remote', 'plaintext', 'encrypt', 'pwd=', 'rid=', 'screen', 'chdir', 'base64=', 'nofwtest', 'debug'] ) except getopt.GetoptError: e = sys.exc_info()[1] _print(e) return 2 fWrap = False fAttach = False fSpawn = False fStart = False encoded_path = None secret = None host = None _rpdb2_pwd = None fchdir = False fAllowRemote = False fAllowUnencrypted = True for o, a in options: if o in ['-h', '--help']: PrintUsage() return 0 if o in ['--debug']: g_fDebug = True if o in ['-d', '--debugee', '--debuggee']: fWrap = True if o in ['-a', '--attach']: fAttach = True if o in ['-o', '--host']: host = a if o in ['-r', '--remote']: fAllowRemote = True if o in ['-t', '--plaintext']: fAllowUnencrypted = True if o in ['-e', '--encrypt']: fAllowUnencrypted = False if o in ['-p', '--pwd']: _rpdb2_pwd = a if o in ['--rid']: secret = a if o in ['-s', '--screen']: g_fScreen = True if o in ['-c', '--chdir']: fchdir = True if o in ['--base64']: encoded_path = a if o in ['--nofwtest']: g_fFirewallTest = False arg = None argv = None options = None o = None a = None if (_rpdb2_pwd is not None) and (os.name != 'nt'): _print(STR_PASSWORD_NOT_SUPPORTED) return 2 if _rpdb2_pwd is not None and not is_valid_pwd(_rpdb2_pwd): _print(STR_PASSWORD_BAD) return 2 if fWrap and (len(_rpdb2_args) == 0): _print("--debuggee option requires a script name with optional arguments") return 2 if fWrap and fAttach: _print("--debuggee and --attach can not be used together.") return 2 if fAttach and (len(_rpdb2_args) == 0): _print("--attach option requires a script name to attach to.") return 2 if fAttach and (len(_rpdb2_args) > 1): _print("--attach option does not accept arguments.") return 2 if fAttach and fAllowRemote: _print("--attach and --remote can not be used together.") return 2 if (host is not None) and not fAttach: _print("--host can only be used together with --attach.") return 2 if host is None: host = LOCALHOST fSpawn = (len(_rpdb2_args) != 0) and (not fWrap) and (not fAttach) fStart = (len(_rpdb2_args) == 0) if fchdir and not (fWrap or fSpawn): _print("-c can only be used when launching or starting a script from command line.") return 2 assert (fWrap + fAttach + fSpawn + fStart) == 1 if fAttach and (os.name == POSIX): try: int(_rpdb2_args[0]) _rpdb2_pwd = read_pwd_file(_rpdb2_args[0]) delete_pwd_file(_rpdb2_args[0]) except (ValueError, IOError): pass if (secret is not None) and (os.name == POSIX): _rpdb2_pwd = read_pwd_file(secret) if (fWrap or fAttach) and not is_valid_pwd(_rpdb2_pwd): _print(STR_PASSWORD_MUST_BE_SET) while True: _rpdb2_pwd = _raw_input(STR_PASSWORD_INPUT) if is_valid_pwd(_rpdb2_pwd): break _print(STR_PASSWORD_BAD) _print(STR_PASSWORD_CONFIRM) if fWrap or fSpawn: try: if encoded_path != None: _b = as_bytes(encoded_path).translate(g_safe_base64_from) _u = base64.decodestring(_b) _path = as_unicode(_u) _rpdb2_args[0] = _path FindFile(_rpdb2_args[0]) except IOError: _print(STR_FILE_NOT_FOUND % _rpdb2_args[0]) return 2 if fWrap: if (not fAllowUnencrypted) and not is_encryption_supported(): _print(STR_ENCRYPTION_SUPPORT_ERROR) return 2 StartServer(_rpdb2_args, fchdir, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, secret) elif fAttach: StartClient_func(_rpdb2_args[0], fAttach, fchdir, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host) elif fStart: StartClient_func(as_unicode(''), fAttach, fchdir, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host) else: if len(_rpdb2_args) == 0: _rpdb2_args = '' else: _rpdb2_args = '"' + '" "'.join(_rpdb2_args) + '"' StartClient_func(_rpdb2_args, fAttach, fchdir, _rpdb2_pwd, fAllowUnencrypted, fAllowRemote, host) return 0 if __name__ == '__main__': import rpdb2 # # Debuggee breaks (pauses) here # on unhandled exceptions. # Use analyze mode for post mortem. # type 'help analyze' for more information. # ret = rpdb2.main() # # Debuggee breaks (pauses) here # before program termination. # # You can step to debug any exit handlers. # rpdb2.setbreak() spe-0.8.4.h/_spe/plugins/winpdb/__init__.py0000644000175000017500000000000010743417310017547 0ustar stanistanispe-0.8.4.h/_spe/plugins/winpdb/winpdb0000755000175000017500000000406710743417221016671 0ustar stanistani#! /usr/bin/env python """ winpdb A wrapper for winpdb.py Copyright (C) 2005-2008 Nir Aides This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import sys import os STR_VERSIONS_ERROR_TITLE = 'Warning' STR_VERSIONS_ERROR_MSG = """Winpdb is being run with the wrong version of Python. Winpdb path: %s Python path: %s""" % (os.path.abspath(__file__), os.path.abspath(sys.executable)) def expandPath(p): if not '~' in p: return p d, b = os.path.split(p) if '~' in d: d = expandPath(d) if not '~' in b: return os.path.join(d, b) _prefix, _index = b.split('~', 1) prefix = _prefix.lower() index = int(_index) for f in os.listdir(d): if not f.replace(' ', '').lower().startswith(prefix): continue index -= 1 if index == 0: return os.path.join(d, f) if os.name == 'nt': path1 = expandPath(os.path.abspath(os.path.dirname(sys.executable))).lower() path2 = expandPath(os.path.abspath(os.path.dirname(__file__))).lower() if not path2.startswith(path1): sys.__stderr__.write(STR_VERSIONS_ERROR_MSG) try: import Tkinter import tkMessageBox Tkinter.Tk().wm_withdraw() tkMessageBox.showwarning(STR_VERSIONS_ERROR_TITLE, STR_VERSIONS_ERROR_MSG) except: pass import winpdb winpdb.main() spe-0.8.4.h/_spe/plugins/winpdb/README.txt0000644000175000017500000000452410743417221017154 0ustar stanistani Winpdb - A GPL Python Debugger Contact: Nir Aides Email: nir@winpdb.org Website: http://www.winpdb.org/ http://sourceforge.net/projects/winpdb/ Version: 1.3.4 Requirements CPython Winpdb is compatible with CPython 2.3 or later. Winpdb is NOT compatible with Jython or IronPython. (http://www.python.org/download/) wxPython To use the Winpdb GUI you need wxPython 2.6.x or later installed. You can still use rpdb2 which is the console version of the debugger without wxPython. Most Linux distributions include wxPython as a package called python-wxgtk. Use your distribution’s package manager (e.g. synaptic, aptitude or yum) to find and install it. On Windows you need to install the wxPython runtime from http://www.wxpython.org/ (The unicode version is preferred). Installation In a console with admin privileges type: python setup.py install -f On Ubuntu you can type in a normal console: sudo python setup.py install -f Where do the files go? The setup script copies rpdb2.py and winpdb.py modules to the Python site-packages folder. The scripts rpdb2, winpdb are copied to the Python binaries (scripts) folder: On Linux this folder is usually /usr/bin and is in the path by default. On Windows this folder is %PYTHONHOME%\Scripts and is not in the path by default. Insufficient permissions? In the event of insufficient permissions, installation can be avoided completely. To use Winpdb simply launch it from the folder in which it is placed. Launch Time On Linux systems start the debugger from a console with: winpdb On Windows systems start the debugger with: %PYTHONHOME%\Scripts\winpdb Note that the Python interpreter must be in the PATH for this to work. Documentation Use the -h command-line flag for command-line help. Use the RPDB2 console 'help' command for detailed description of debugger commands. Online documentation is available at: http://www.winpdb.org Further Development Winpdb is open source. If you would like it to develop further you are welcome to contribute to development, send feedback or make a donation. spe-0.8.4.h/_spe/plugins/winpdb/winpdb.py0000644000175000017500000051355410743417221017323 0ustar stanistani#! /usr/bin/env python """ winpdb.py A GUI for rpdb2.py Copyright (C) 2005-2008 Nir Aides This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA """ ABOUT_NOTICE = """Winpdb is a platform independent GPL Python debugger with support for multiple threads, namespace modification, embedded debugging, encrypted communication and is up to 20 times faster than pdb. Copyright (C) 2005-2008 Nir Aides This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Credits: Jurjen N.E. Bos - Compatibility with OS X.""" LICENSE_NOTICE = """ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GPL with the precise terms and conditions for copying, distribution and modification follow: """ COPY_OF_THE_GPL_LICENSE = """ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS """ import sys WXVER = "2.6" STR_WXPYTHON_ERROR_TITLE = 'Winpdb Error' STR_WXPYTHON_ERROR_MSG = """wxPython was not found. wxPython 2.6 or higher is required to run the winpdb GUI. wxPython is the graphical user interface toolkit used by Winpdb. You can find more information on wxPython at http://www.wxpython.org/ The Unicode version of wxPython is recommended for Winpdb. To use the debugger without a GUI, run rpdb2.""" STR_X_ERROR_MSG = """It was not possible to start Winpdb. A possible reason is that the X server (Windowing system) is not started. Start the X server or try to use rpdb2 instead of winpdb.""" import rpdb2 if 'wx' not in sys.modules and 'wxPython' not in sys.modules: try: import wxversion wxversion.ensureMinimal(WXVER) except ImportError: rpdb2._print(STR_WXPYTHON_ERROR_MSG, sys.__stderr__) try: import Tkinter import tkMessageBox Tkinter.Tk().wm_withdraw() tkMessageBox.showerror(STR_WXPYTHON_ERROR_TITLE, STR_WXPYTHON_ERROR_MSG) except: pass sys.exit(1) import wx assert wx.VERSION_STRING >= WXVER import wx.lib.wxpTag import wx.gizmos import wx.html import wx.lib.mixins.listctrl as listmix import wx.stc as stc import webbrowser import traceback import cStringIO import threading import xmlrpclib import tempfile import textwrap import keyword import weakref import base64 import socket import string import codecs import pickle import Queue import time import os import re MARKER_BREAKPOINT_ENABLED = 5 MARKER_BREAKPOINT_DISABLED = 6 MARKER_CURRENT_LINE = 7 MARKER_CURRENT_LINE_HIT = 8 MARKER_CALL = 0 MARKER_LINE = 1 MARKER_RETURN = 2 MARKER_EXCEPTION = 3 MARKER_RUNNING = 4 MARKER_LIST = [MARKER_BREAKPOINT_ENABLED, MARKER_BREAKPOINT_DISABLED, MARKER_CURRENT_LINE, MARKER_CURRENT_LINE_HIT, MARKER_CALL, MARKER_LINE, MARKER_RETURN, MARKER_EXCEPTION, MARKER_RUNNING] CAPTION_SOURCE = "Source" CAPTION_CONSOLE = "Console" CAPTION_THREADS = "Threads" CAPTION_STACK = "Stack" CAPTION_NAMESPACE = "Namespace" CONSOLE_PROMPT = "\n> " CONSOLE_COMPLETIONS = '\nAvailable completions:\n%s' COMPLETIONS_NOTICE = 'NEW: Use CTRL-N for auto completion in the following commands: launch, eval and exec.' COMPLETIONS_WARNING = '\nDisplay all %d possibilities? (y or n)' COMPLETIONS_WARNING_CONFIRM_CHARS = ['y', 'Y'] COMPLETIONS_WARNING_THRESHOLD = 32 ENABLED = True DISABLED = False WINPDB_WILDCARD = "Python source (*.py;*.pyw)|*.py;*.pyw|All files (*)|*" PYTHON_WARNING_TITLE = "Python Interpreter Warning" PYTHON_WARNING_MSG = """Winpdb was started with the wrong Python interpreter version. Winpdb path is: %s Python interpreter path is: %s""" MSG_WARNING_TRAP = "Are you sure that you want to disable the trapping of unhandled exceptions? If you click Yes unhandled exceptions will not be caught." MSG_WARNING_UNHANDLED_EXCEPTION = "An unhandled exception was caught. Would you like to analyze it?" MSG_WARNING_TITLE = "Warning" MSG_WARNING_TEMPLATE = "%s\n\nClick 'Cancel' to ignore this warning in this session." MSG_ERROR_TITLE = "Error" MSG_ERROR_FILE_NOT_FOUND = "File not found." MSG_ERROR_FILE_NOT_PYTHON = "'%s' does not seem to be a Python source file. Only Python files are accepted." STR_FILE_LOAD_ERROR = "Failed to load source file '%s' from debuggee." STR_FILE_LOAD_ERROR2 = """Failed to load source file '%s' from debuggee. You may continue to debug, but you will not see source lines from this file.""" STR_BLENDER_SOURCE_WARNING = "You attached to a Blender Python script. To be able to see the script's source you need to load it into the Blender text window and launch the script from there." STR_EMBEDDED_WARNING = "You attached to an embedded debugger. Winpdb may become unresponsive during periods in which the Python interpreter is inactive." STR_EXIT_WARNING = """The debugger is attached to a script. Would you like to stop the script? If you click 'No' the debugger will attempt to detach before exiting.""" STR_WXPYTHON_ANSI_WARNING_TITLE = 'wxPython ANSI Warning' STR_WXPYTHON_ANSI_WARNING_MSG = """The version of wxPython that was found does not support Unicode. wxPython is the graphical user interface toolkit used by Winpdb. You may experience some functionality limitations when debugging Unicode programs with this version of wxPython. If you need to debug Unicode programs it is recommended that you install the Unicode version of wxPython. You can find more information on wxPython at http://www.wxpython.org/""" STR_MORE_ABOUT_BREAKPOINTS = """You can set conditional breakpoints with the 'bp' console command, disable or enable specific breakpoints with the 'bd' and 'be' commands and even load and save different sets of breakpoints with the 'load' and 'save' console commands. To learn more about these commands type 'help ' at the console prompt.""" STR_HOW_TO_JUMP = """You can jump to a different line in the current scope with the 'jump' console command. Type 'help jump' at the console prompt for more information.""" DLG_EXPR_TITLE = "Enter Expression" DLG_ENCODING_TITLE = "Encoding" DLG_SYNCHRONICITY_TITLE = "Synchronicity" DLG_PWD_TITLE = "Password" DLG_OPEN_TITLE = "Open Source" DLG_LAUNCH_TITLE = "Launch" DLG_ATTACH_TITLE = "Attach" STATIC_EXPR = """The new expression will be evaluated at the debuggee and its value will be set to the item.""" CHECKBOX_ENCODING = "Output non ASCII characters as an escape sequence." STATIC_ENCODING = """The specified encoding is used as source encoding for the name-space viewer and for the exec and eval console commands. Valid values are either 'auto' or an encoding known by the codecs module. If 'auto' is specified, the source encoding of the active scope will be used, which is utf-8 by default.""" STATIC_ENCODING_SPLIT = """The specified encoding is used as source encoding for the name-space viewer and for the exec and eval console commands. Valid values are either 'auto' or an encoding known by the codecs module. If 'auto' is specified, the source encoding of the active scope will be used, which is utf-8 by default.""" CHECKBOX_SYNCHRONICITY = "Use synchronicity." STATIC_SYNCHRONICITY = """Traditional Python debuggers that use the inspected thread (usually the main thread) to query or modify the script name-space have to wait until the script hits a break-point. Synchronicity allows the debugger to query and modify the script name-space even if its threads are still running or blocked in C library code by using special worker threads. In some rare cases querying or modifying data in synchronicity can crash the script. For example in some Linux builds of wxPython querying the state of wx objects from a thread other than the GUI thread can crash the script. If this happens or if you want to restrict these operations to the inspected thread, turn synchronicity off.""" STATIC_SYNCHRONICITY_SPLIT = """Traditional Python debuggers that use the inspected thread (usually the main thread) to query or modify the script name-space have to wait until the script hits a break-point. Synchronicity allows the debugger to query and modify the script name-space even if its threads are still running or blocked in C library code by using special worker threads. In some rare cases querying or modifying data in synchronicity can crash the script. For example in some Linux builds of wxPython querying the state of wx objects from a thread other than the GUI thread can crash the script. If this happens or if you want to restrict these operations to the inspected thread, turn synchronicity off.""" STATIC_PWD = """The password is used to secure communication between the debugger console and the debuggee. Debuggees with un-matching passwords will not appear in the attach query list.""" STATIC_PWD_SPLIT = """The password is used to secure communication between the debugger console and the debuggee. Debuggees with un-matching passwords will not appear in the attach query list.""" STATIC_LAUNCH_ENV = """To set environment variables for the new script use the 'env' console command.""" STATIC_LAUNCH_ENV_SPLIT = """To set environment variables for the new script use the 'env' console command.""" STATIC_OPEN = """The source file entered will be fetched from the debugee.""" LABEL_EXPR = "New Expression:" LABEL_ENCODING = "Set encoding:" LABEL_PWD = "Set password:" LABEL_OPEN = "File name:" LABEL_LAUNCH_COMMAND_LINE = "Command line:" LABEL_ATTACH_HOST = "Host:" LABEL_CONSOLE = "Command:" BUTTON_LAUNCH_BROWSE = "Browse" BUTTON_ATTACH_REFRESH = "Refresh" CHECKBOX_LAUNCH = "Set working directory to the script folder." HLIST_HEADER_PID = "PID" HLIST_HEADER_FILENAME = "Filename" HLIST_HEADER_TID = "TID" HLIST_HEADER_NAME = "Name" HLIST_HEADER_STATE = "State" HLIST_HEADER_FRAME = "Frame" HLIST_HEADER_LINENO = "Line" HLIST_HEADER_FUNCTION = "Function" HLIST_HEADER_PATH = "Path" TLC_HEADER_NAME = "Name" TLC_HEADER_REPR = "Repr" TLC_HEADER_TYPE = "Type" WINPDB_TITLE = "Winpdb 1.3.4" WINPDB_VERSION = "WINPDB_1_3_4" VERSION = (1, 3, 4, 0, '') WINPDB_SIZE = "winpdb_size" WINPDB_MAXIMIZE = "winpdb_maximize" SPLITTER_1_POS = "splitter_1_pos" SPLITTER_2_POS = "splitter_2_pos" SPLITTER_3_POS = "splitter_3_pos" SPLITTER_4_POS = "splitter_4_pos" WINPDB_SIZE_MIN = (640, 480) WINPDB_SETTINGS_FILENAME = "winpdb_settings.cfg" WINPDB_SETTINGS_DEFAULT = { WINPDB_SIZE: (800, 600), WINPDB_MAXIMIZE: False, SPLITTER_1_POS: 190, SPLITTER_2_POS: 294, SPLITTER_3_POS: 382, SPLITTER_4_POS: 305 } AC_CHAR = "\t" AC_EXIT = "Alt-X" AC_ANALYZE = "F3" AC_BREAK = "F4" AC_GO = "F5" AC_NEXT = "F6" AC_STEP = "F7" AC_GOTO = "F8" AC_TOOGLE = "F9" AC_RETURN = "F12" ML_EMPTY = "" ML_SEPARATOR = "" ML_ROOT = "" ML_FILE = "&File" ML_PWD = "&Password" ML_LAUNCH = "&Launch" ML_ATTACH = "&Attach" ML_DETACH = "&Detach" ML_STOP = "&Stop" ML_RESTART = "&Restart" ML_OPEN = "&Open Source" ML_EXIT = "E&xit" + AC_CHAR + AC_EXIT ML_BREAKPOINTS = "&Breakpoints" ML_TOGGLE = "&Toggle" + AC_CHAR + AC_TOOGLE ML_DISABLE = "&Disable All" ML_ENABLE = "&Enable All" ML_CLEAR = "&Clear All" ML_LOAD = "&Load" ML_SAVE = "&Save" ML_MORE = "&More..." ML_CONTROL = "&Control" ML_ANALYZE = "&Toggle Analyze" + AC_CHAR + AC_ANALYZE ML_GO = "&Go" + AC_CHAR + AC_GO ML_BREAK = "&Break" + AC_CHAR + AC_BREAK ML_STEP = "&Step Into" + AC_CHAR + AC_STEP ML_NEXT = "&Next" + AC_CHAR + AC_NEXT ML_RETURN = "&Return" + AC_CHAR + AC_RETURN ML_GOTO = "Run to &Line" + AC_CHAR + AC_GOTO ML_JUMP = "&Jump" ML_WINDOW = "&Window" ML_HELP = "&Help" ML_WEBSITE = "&Website" ML_SUPPORT = "&Support" ML_DOCS = "&Online Docs" ML_EXT_DOCS = "&External Docs" ML_UPDATES = "&Check for Updates" ML_LICENSE = "&License" ML_ABOUT = "&About" TB_GO = "Go" TB_BREAK = "Break" TB_STEP = "Step into" TB_NEXT = "Next" TB_RETURN = "Return" TB_GOTO = "Run to line" TB_FILTER = "Filter out methods and functions from classes and objects in the namespace viewer" TB_EXCEPTION = "Toggle 'analyze exception' mode" TB_ENCODING = "Set the source encoding for the name-space viewer and the exec/eval console commands" TB_SYNCHRONICITY = "Set the synchronicity mode" TB_TRAP = "Toggle 'trap unhandled exceptions' mode" TB_FILTER_TEXT = " Filter: %s " TB_ENCODING_TEXT = " Encoding: %s " TB_SYNCHRONICITY_TEXT = " Synchronicity: %s " COMMAND = "command" TOOLTIP = "tooltip" TEXT = "text" DATA = "data" DATA2 = "data2" ID = "id" LABEL = "label" FORMAT = "format" KEYS = "keys" WIDTH = "width" PWD_TIP = "Set connection password." LAUNCH_TIP = "Launch a new debugged script." ATTACH_TIP = "Attach to a debugged script." DETACH_TIP = "Detach from debugged script." STOP_TIP = "Shutdown the debugged script." RESTART_TIP = "Restart the debugged script." OPEN_TIP = "Open source file in the source viewer." ANALYZE_TIP = "Toggle analyze exception mode." BREAK_TIP = "Pause script for inspection." GO_TIP = "Let script continue its run." STEP_TIP = "Continue to the next code line, possibly in an inner scope." NEXT_TIP = "Continue to the next code line in the current scope." GOTO_TIP = "Continue to the line under the cursor." RETURN_TIP = "Continue to the end of the current scope." JUMP_TIP = "Jump to another line in the current scope." WEBSITE_TIP = "Open the Winpdb homepage." SUPPORT_TIP = "Open the Winpdb support web page." DOCS_TIP = "Open the Winpdb online documentation web page." EXT_DOCS_TIP = "Open the Winpdb external documentation web page." UPDATES_TIP = "Check for updates in the Winpdb website." TOGGLE_TIP = "Toggle breakpoint at cursor location." DISABLE_TIP = "Disable all breakpoints." ENABLE_TIP = "Enable all breakpoints." CLEAR_TIP = "Clear all breakpoints." LOAD_TIP = "Load breakpoints from file." SAVE_TIP = "Save breakpoints to file." MORE_TIP = "Learn more about Winpdb..." TOOLTIP_UNLOCKED = "Communication channel is authenticated but NOT encrypted." TOOLTIP_LOCKED = "Communication channel is authenticated AND encrypted." TOOLBAR_BITMAP_SIZE = (23, 21) BASE64_BREAK = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nUUlEQVQ4y2NgGAXDCjDik1QJnPKJgYGBl4GB4cOd9TmCULH3DAwMAshiuAATAct5obQAkpgAFjGy\nDKcIjBo+avgQMfwTlP6GJPYZTW4UjBQAAICvDiDQ+lb5AAAAAElFTkSuQmCC\n' BASE64_GO = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nZElEQVQ4y2NgGAWkApXAKR8p0c9EQJ5PJXDKf1oZDvPBf5oZTq4FTCTGwX+aGU6qBUxkpqL/NDOc\nWAvINvzO+hxGmhhOjMFkGU6swSQbTorBJBlOqsFEG06OwcQkt0+jdQPVAQDJqB4mOx09ZwAAAABJ\nRU5ErkJggg==\n' BASE64_STEP = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB\ni0lEQVQ4y92UO0sDURCFv9lNCNlK1KSxCIFIUgta+CittIlgp21Q2Ma/IdqIoPZWFq6FEOy10dIm\nkSURS0OsxDTJjoWbGJZssj4anerOcM65c2fmDvxVk2AgVzzUQOgeOAP2Xcdu/Ujcv8ACZoASsOHj\nHoBl17GffiQeuGgVuABM4BaYdx27E0XcGAVwHfsS2PPdOWAnauZGRNxJ33nlV8Vdx673uQvfFk+M\nZRJWKr9rpQu1EE6837HShZqVyu8mxjKJIDAWDJjx5Cki86qd2SjZqXqLIuadGU9mgfXQaUmm8kUR\n4xzV7bdG5Thk7rv26Dp2FsBKFbYQOVL11lqNqjOwLCJSAlCvfdVXbwnpQ7aXvY/v8kNqLjMAraZb\nDwjJMP8T/8EPa2h6yMTIsJcM4gfFX0eM5Kgf/RourloGSE5OT31lQfXwPn+guKIHH40xlr60/Xx8\nlx+6uKx0wQHy2mkvtpruy8isJ3LjYsaugerbc6U49Ieq522i3IgRK0fK2oiVUW7U8zb5N/YOEKSA\nXhG59Y4AAAAASUVORK5CYII=\n' BASE64_NEXT = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB\nUUlEQVQ4y9WUMUvDQBTHf6m6hI4lOLgIWQIuFRHULoJOujh0c+jkYhY/hqBbFr+CDmdB6OhSKIiD\n4BCRQEEcSj5AskR0eYXjSNqkcelb7t4///vdy93jYFnDKmt0z4JfQ3oH7oHbSPlpLbhsYAPbwAVw\nLus/geNI+V+14MZGp8AjsAK8APuR8n90T2NReKT8J+BG0l3gyvQ0at7ZnTY/+Vd4pPyxlh7MhNuO\n17Id78F2vFTTUtFac/ZaK4TbjrcKDIAjoK152qINxFM69Mp7wA4QJHH4MRVlHsi3nt73Zu+LNs6D\nX8rYzymib3iIlG8V3MNmHtyVSl/NBZrmGiBrVq7DmyWOsZlTqVX0Jzo8KwHPCo7CmnehQ+maLdOk\nacNFu+Vaxk6Or2N4qj250sPPwAawl8ThRPR1YAR8A4dJHGaVK5dFXeBNYNMYidatAl7u+AMmh2gx\n02GtwwAAAABJRU5ErkJggg==\n' BASE64_RETURN = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB\ne0lEQVQ4y92TPUsDQRCGn8klhLsqqLlGMAjRS36AFn78AhsPol1aqzTiT0gnVpJGS7GzSCMEe1MJ\nYqkStBM0aCVJk9xY6Ek8Em8jCOJUO+w7z747swt/OfJ+TUftJX7zABkDYAHbwBqwDKSimla9ImPD\n835tBjgBFuO0gweIAdgGroD5ccAASQPjOx/gPrAHHLTqlftov6NgU/gmoMB6q145NXE8NNKZXNrJ\neruOW7gbdJb3a0dh7riFOyfr7aYzuXQc74tzK2UfI7Kk2l+I6A7DhWqwImJdWCl7Ftj4Dv75zu2s\n5yNSQrXabd8+RHSX4aLbvn1AtYpIyc56vhFcRLYANOidDelpZzAPNWFNbDhu8dFxi2r6qRy3qI5b\nfDRyDrg/+PmuKfz1B/BXM7hqA8CempuOI35qPmpi4Yruvw8psRoHDzVhzUjd1yEV6oCn/d5K97n1\nMtT1ZH5CrOQ5cNN5uvZNe44GQRmlKYnkyOtKItlAaWoQlPm38QY7vXb+uQlzowAAAABJRU5ErkJg\ngg==\n' BASE64_GOTO = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nwElEQVQ4y+2SsQ4BURBFz65o9gP0Eo1WoaBW0ejVqmn8B53GL2hG4Su0ColMQpQ+gEpWs8Vms8uT\ntyTErd7Mm5x7Mxn4VgXZRmM4jzOtLbAEZqZy9YInBhHQAsbAKJnbAz1TOXnBM0YDYAVUgA3QMZWb\nCzx8NmAqa2CalG1g4po8dJxbpN79UuGmckiV3bKTp1V9J5wyryUu+DqaSt0LXmRgKoF38jwDF/DL\nerCiH1Ph7qJa03kFl/Mu+Pid/5WrO8B7LfQd3oiRAAAAAElFTkSuQmCC\n' BASE64_LOCKED = "iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAhUlEQVR42u2UQRLAEAxFP+NguRm5WW6WbrRjOkqorurvmHiR5ANsVeQsQSlBb2u3JHtKUBFRAApAcyK1nPU9MJGAiM4qXd6HJYHvBRTg4Zb4LwcaZgZa7rcqcaPASpzZdRfYop5zwoJnMNdz5paLBADNw2NsmhQiv7s58/u/6YmgCxhbdR19GFJ+yzjAWQAAAABJRU5ErkJggg==" BASE64_UNLOCKED = "iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAjklEQVR42u1TQQ7DIAyzUR8WXkb4WX7mnSqtFetCxU6rb0jYJLYBHgzAOyR36HTmkmncoYgQSZGUO0RSo7tlVtgsUGuFJEoiALQmjB4os5PvwhlLyi8D3TKBLWtLVrh3HuxJBZbBVUO+2oJFtd3GK38mmAUAuy/e2hXFEPF3k/fOZZ/ooJSp146pjj94xwuYKl+HgD9iOwAAAABJRU5ErkJggg==" BASE64_EXCEPTION = 'iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC\nD0lEQVQ4y+2UTUsbURSGn9zcNJMQSVPH7CxMBF0EjIugmxaEbJq9UNv5DfoL3Ar+AH+BJf1aCm6E\nuHLXEJrFLCK0QoUS2kAYCpkxTu50kTjGfBHBpWd37znnPR/3vS882RgLTXNms2UJbAshTE3T8kKE\nU0p1W67rVpRSH4FPllXwHgyezZaXpZRfdD29lkwmEUIEPqUUtm3TbP6peZ731rIK9ZnBs9nysqbF\nzhcXXy5IKSdO5nkeV1e//rqu83pcgdC4VUgpK4axlLsFDodhdTWKrgsajS6W1UGpuwKXlz9rnneT\nH17RuLa2dT0dAM/NCfb2npPJRIKAev2G/f0WjuMjpUTXF3KNxu93wIdBIDGMLIQwk8lkcDbNBJlM\nhNNTh52dJicnbVZWImxtJYKY/pu8H8Eavuix4u56YyMKwNmZg1JQLjv4PqyvRwcbQtO0/DCWHO08\nnAqcMkQi0St0cPDiXtz8vJiYNxFcqW4L0AG6XR/H8YnFQuzuNmm3fYToFe10/HF509fS/yAA+D5U\nq9cAFItxlILNzRiHhzqmmbjHe9d1KzN0rkq2bb9JpXpTHh39wzAiFItxisU4AK2W4vi4HeTYto1S\nqjQrz78ZxtLaLR0jkRC53DPS6TC2rahWr3Ecf4DnP2qe543w/LF+6CvLKlw8VFu+6no6N0Vbvve1\n5eKxVbEEfJ6mik821v4D0B75yPNHQ9UAAAAASUVORK5CYII=\n' BASE64_TRAP = "iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA\nB3RJTUUH1wMWBzIMELT6ewAAAixJREFUeNrNlVtIkwEUx39z35zOteU252X6hbNpEeZW5oUyejC7\naEEIERhRPVTMhx6rh3rLqCB8iaSHejGiqF588QJFD3bZg4HQCsNLuE2deNk3v29urtV7N9RvQef1\nnPPjcPif/4F/GFrVBEdOFUm7jmRU+jmVoY7c1EIw7zCajNTvsuuGl3DVa8TalkNFEGUylBZ4B1fK\nPVRdg6mmbAqXTzi6P6Rl50fZ7HlPb1uuJWSOxMyCicon/dGDg3+q16wW3FBEvcHG5XoX04qE/vmA\neXmUyAXVanFS3crG0JmLl9Dt8GAaHWOLaIw/TQZNcj4Oayk1FnBbJT7NrwlewLH2JeabHZZpf2UV\nzlIRo82OYTzBAckQPzT3fWHviDSzTyZel0WDlODz+KrgG6g7KRNs0RCRY7JUkJTILRaxlXuw2woJ\nGc34ZQVhbjah6OKuzkUG3q568gSB4eraxsBU8OuLPamKNxOTS8VlrnjBVjeZgS8MPbxH5sQwvjJl\nZ9dHfP51n4uYxblGJw9edXCj5xYDrW5e70I83ld936lKLdnk7naIC+e9pwjPjlA2NsiiEsx53IPc\nr0otetyub0TPxldi7wJhtgfCzNgi3HmmrPhUOUdzzc1KHY67AoXXBUydwOm19P91LTo2eVMs12vQ\nhCD1Mkm4Ly1erCf/iBZrr0DRbT21rrSZvIC4X4u1W0dJuxrOL66YxTYRojVgfOQyN3el9TUJ5DXo\nMTv53+MHY3Sxa+ko45EAAAAASUVORK5CYII=\n" BASE64_FORK = "iVBORw0KGgoAAAANSUhEUgAAABcAAAAVBAMAAABfzGiYAAAAD1BMVEWZAACsqJn///8BAQEAAIBm\nb8BsAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElN\nRQfXBwQRJRb/bmGBAAAAT0lEQVQY02NgIA4wCoIAjKMEBIoMDlg4ysa4ZJSMjY0VWVyQZFhcXFyQ\nZViQ9UA4ysZGCA6KDEiPi4sDC5JpKMpYQGbDXe3igOQXFnweBQD3YA+4tU+1lQAAAABJRU5ErkJg\ngg==\n" BASE64_ICON_16 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wceCwAVoIFxgQAAAqdJREFUOMuFkltIFFEYx/9zdnN3\nci+E2Wq7uWp4rcBbSQaBRCClUg/lUz0URYTRi1FPgWBIBT1UZpAPERSRmERkN6UI8yExtdhYUTeV\ndbNdXW8zszPn7Mz04CXcNP8vh3O+8/+d7/vOx2FRN560WwRFPRdRWKWsRF2irIQEMdIeGhu49+Fh\n/TjWEAcAdY/eZzFVb5MUli4pDJJMsbzKNBz2D53ofXbzDQAtFmC4/rjdqkT1Tklh6X+NDJJCIckM\nERrlidlauZE3vwuPeQOxACIq6nlJYWlLZlFmEBUKUWaQKIOqagBHrFb3rqsA+H8AksIqRZlCVBhE\nmS6/POn3waBRCMFRmAwqUpOM+5/fyq96ebskYSVAps6VdTPMB0ZwuigJTWdLUXesGG65D/tSgnZX\nAqkuy6OeroacMgBkMQMaXmgWw9xMeCYiK+rO7hdIE8IYbG3FBq8H6b39KLAMQaeMGJnk2J3BNd+5\nmLoXAGcUxEiHHEW+qFBEhPkQH282lY94eb2lBQcIwReOQ6HPh2xhFgFzHIEOGAksh/eYr10Ayo3T\nAd9d3eY8I1PVruoghc5wNCfRCo/HgwCACQAHzQR8igGIclsAHQCwLZGUuBzx2w0/ez/N2VNyvUbe\nVgHo3NG075KtIM7G+oMwUx3gCZJqkmHP5GExw7rcPA6Gr8NaB7e0zyo9XmzZmnG5sbTNne+medBU\nTIeisG0ywmTiVp3CoupfR2Ij/ETLjksOu1aLdTQ+pf92VXkPkZjzSPegfl/VyNR6gKcfhTYAvlgA\nKq78CPYMq6dUjYusZX7bQ7tqGv0NAGYNq11oejU56HRYOjfbDJlWniQTbmFoAmE9+OC10HyyfrQW\nQB8AjftPlhwAS3aqLbMkl88Y8FP6+dv0KAAfgBks/ucfwdhZh0OZfFUAAAAASUVORK5CYII=\n' BASE64_ICON_32 = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wceCjYEQu+qMQAABhVJREFUWMOtlmtsFNcVx39n9uW1\n1/bau7Zx/AAbYsdNGl52oSUJIUlJa+VB0g+0JK1Ig9omRUoitaiNFFVqkVXSh5BaVVUbNVaSSiVF\napIPiJLQIAMSUJIWKMzaJsaGBbIGB693vO+Z2w+73thmbRbjK43uPZq59/8/Z8753yPMMpRSbmA9\ncB/QalqWVxNJikgQ+AjYIyL93MKQGYDLgG3D14znTnxyubI3eIVLV8cwYklMy8LjdtJY7WX5kjra\nW+sPOB22n4lIz7wQUErdHx6Pv7nv3331Jwc+JZU2SZlmZk5bk+zMurTYxVMPLVcPrljyZ+AFEYnP\nmYBSatPApc+6d/ecckSiievAk1k7PbFOm6TMDJF7vriIbRvXHnK7HJ0iErlpAkqpr569OLJn14cn\n7PFkKudhcpK3kwFzEckRNOlobeBXP+jc57DbOkXELISAlgX3fzYWfXN3zyl7PJkimfVwdnBzCrhp\nKY7o5/nDu0fWAz8qNAJadn5lz7HeGiOWIJnnP08Hm07GtFTuwL99eILTg6FXlFILCiKglKq4MDy6\nJXB+OG+S5bfzg2ejSffe4yXA84VG4PGP+y8VTwG47vn8XTJtEjXGpoAnxq6SHB/NHXr49BBXw+Ob\nTNMsKoTAuoz3N/Y2lbaIGWNcPHV4iudJYxQzEUOAIruJ3z1O77mBxVo6NKyUek0p1TojgUQq3Ra6\nZuT1Nt8ah5uSqgZqJUzn3TWsa6mg2IpS5q+m0h2nrtSgoTTC2GgQzu8s5cyWZwkfPaWU6lJKOaYT\nsBvRpG+2EkumTdITOmCaGPoRvt3ewMbNTyJaJoefvqeVHV2vYjUsoK7UjdcVRxJBcNTAyAE4vdVB\n9WM/pXnbaqXUBhEZy0VANMzp4BOCk8zZGfDxwDHuNProWN3BuUCAAV1nQNcZDgbZ+ORjnNv9NhWE\nqPeEKU4NZgik05BOwYVdcHLrOqz4u0opZ45AeUnRJUupSWAZMhN2Y7U3o36JOKlDu6lvasoB555A\ngE+DQWp81Zx5/zD1xaP46QVnLaSSGQKWBSOHIfCL+4Gu3C+wadp/an1la3svXMmjbhZbn/gKz+98\nh9oLOj+PjxMMhVik63hlkoqLMAx8ORpl8OgQ9Vtvo8oRB80N5jRBvPwPqHrwRaXUGyJyUgP2Lltc\nmxc8ld1sE0WLEaIM+LWuc0jXqdN1KrNzTNd5Vdf5VzDIl4wUJeZVyh0xQOVP/U922lDWywB24IP7\nljYP/XX/fxdOUTvTwsqWWqU7jqtMUQFUh0J8wTBAhF5gGVAO2NJpmuNxxjWoKTYRsYOagcD4WRg9\nvkEp5dVExPSVFW9/ZPUdUypgAlyAJu8o6Tv9OIBdShEzDMYiEUYiEYhEuBiJ8EIsRicQbXNT5BRQ\nFkTPzaxAIwddwNqJu+Av33pgWU/TgsoM+CTmTpvFwtIwty+2cXBlAwbwY+A3QBi4AjwDvA3EAMcm\nf1aT09DXNTOByBmApVomh8RyOe3f3P7sw+frq8qnfBdPQWNZhPqSMK4f3kH/klJ+BzwKJAAH8BPg\nJYH+Z6pYsspT2DWYGAao0T5PZLlcU+FZ98eXnuhb1daY+244HKXZp9FQfI3WKoOFv23Ct6Uaz0IX\nzgYnAbfG0vYSYjsaufsp/030QiqjQ3laMq9Saue+4/3f6f7nR/K1jha+7nmNosgxSuwJbGJNOULm\n2o1622HlG9vt17VIIqPAZqXU79e3t7w4Fo0/7hmq8djiscI62kKHpwXgjDZjryZyXNPk6fKSorts\n/jWK+R6+NRZwQLth0ygyhP/eHpz++QN31UDlmv0iclkrrHEr+iVN358/Ak3PgebcMbknvFEU9lK3\n8R287bcOXrEKbvvG30Vk/03lkVLKR2L4KB9vXkx0cG7gJc2worsPp3+1iFwrOALZKIzgql7Piu4B\nypfPoexWworXz+L0PzwBPqdKUkpVYaW6Cb7VyeCfIBWefYOjAhZ9Dxo2vYc4visiI7dcyipzV2wg\nbbzMlf0djBwEIwDJ7NlOH3jawH8v+B84it3TBbwnIvOrJVkybcBDwF1A1YSCA/8D3heR3tn2/x9k\nTxVPItzU3gAAAABJRU5ErkJggg==\n' BASE64_ICON_64 = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI\nWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wceCjUKjnrU9QAADqFJREFUeNrdm3t0XNV1xn/nzkuj\n0Yysh/WwLMvIlh2/HwgCBoyNTQOYUF4JBDuF8ohXIQWCm5AAaWJS0lBcL0obVkOeTUoIUCAxNKZg\nXIMhBWMsV8a2bEsYWZZk6y3NSBrN3Ht3/5g749F4ZvRAsrW61zrrnjl37tzzfWfvffbZ54xijERE\nXMBCoAKYCuQANsAEWoETwH7ggFIqxP8HEZGZIvItEXlXRIISJ2HdkIGQLmHdkAQJisgOEfkbESk/\n2xjUKEADrAHuA1YDqrGtm9rGdo61dHGi3U9HoJ/+gTCmKRimidNuw5vpYkq+j2kFk5g3vYiywklY\n2vEG8BSwVSk1sQkQkWXAE8Cy7t4gH9Y0UFXbRKe/PwJWBNM0MUyJgR90jbufk+XmkoXnsGrpTPJ8\nmQA7gW8qpT6YcASISCbw98DXe/oGtB1766g60oRumEnBJSUhBTkAK5fM4OaVi8j1ZZrAk8AjSqn+\nCUGAZad/EGH+h4caeGtPLcGQngbc8MBH66ZpYojgtNu47YpKrr5gDkrxv8CfK6XqzyoBlspv6R8I\n572882PqmtqTgIuqeRqQkrw9GUHnzirh4XWX4XW7WoE1SqkPzwoBInIRsLW9p8/7u+17ae/pS27b\nkh589DvDAR9tn5Lv44n1V1GSn90FXK6U2n1GCRCROcD/tPf0Zf/mzT309AbTgo+2pQI/Ur9gmCb5\n2R6evv9aSvKz24HPK6XqxoMALQn4HOAPgf5Q9rPbquLAm6d79ST1YYM3E/3GYGJPdga495+30N0b\nzAO2iIj3jBAAPGWYUvHi29V0BfoHddRIGL3kYIYD3ozzC6c/Fwk1oLGth4d+9jqmKXOBTeNOgIhc\nA6x7d99RGlq6TgOflIhhjbAk1Z5k96Pgo/LR4UaefasK4C4RWT1uBIiIA9jU0hlgZ/XRlOCH8vyn\n7qcPiJI5REnRyZ++touGli4FbBYR23hpwO1AxbY9tYStAGf04CW135DkPkTSdDKkGzy95X2ABcAt\nY06AiCjgG8dbuznU0JpaTWUIB5bk/lB+YyjwUdlRVUdtYxvAAyIy5hpwGTD7g4PHRgE+tU8YVP8M\n4AEEeGHHPoDFwLKxJuCmYEhn3ycnhuHAzOQgRdL7jSQEjXQc39h9mGBIB/jymBFgqf/VR463EdKN\nNFNa8tkgCj4+CEr8DV0P0350P4ZxisBk0vD+Fk7ueydlZ4MhnV01DQDXG4Yxfaw0YA5QHLV9Iw34\ndCDTmU7b0X1Uv/IUXU11KcEDBLtaGPC3ndZu10w8zjB57iD7az4GKNU07aiI7BaR+6zgbdQELAE4\nFpv3JUZEyvg9HqQMPbdnT5vHlCWrycwvTduZyXMupGjBithnmxLcDh2vK4TPGcLnGuBE2/HIzZ4P\noK/mXGv5XC8iPxKRvNEQsFA3TE50+JOGucMPcFL7DUFRtHAFnUerYy829RDhvh6MUGTZL6ZBf0cz\nTm8umhJcdoMsVwhfDHyk+HuaMU0D+mqh5i44cCt0vOlFjAeBGhG5wzLrYYkdmNLdGxyc3Ehi2+Yo\nY4Jom8Mzif6Wejz2IF+8fBmVS5ZSVFxMIBDgQM0RXn3tdbqcLuyEyHRCht0gw66TYdMT6jrdPZ3k\nOIvAFOithbrvQcYvoeyb+fiW/Ay4VkRuU0q1D4eAAn/fwGcAH5/cSA4+2N5I784XuXftddxy993Y\n7PbYUtSbmUlxQQGrll9E9a5dfO/hv2VgXiUFn6uIgLYbMeDRq9/fSk5uMYgJIpHSWwf710PhjTD9\n/qvRnHtE5Eql1IGhTMChG58dvJEQEEXb/Uc+ov+lTTyw/qtc/ZWv0NPZSWdr66nS1hYrpeXl/MPm\nJ9B3bqX+7a34nAOR4opeg/icQfoDLeAsBtOMK0akND4He2+FUOs0YKeIXDAUAaZSDAu8YZopwcf8\nRhz4QF0VxrZfsWLVZSy64IKkoBPJsDkc3LFhAx3vvsf+N7dZJESA+xyRut7XDI4cUK448CYY1rXn\nY9i9Fvrqc4E/isj8dCbQ43Y6hvTqQycxBhM40NVCePtvcCnF8jVr6GxrOz0TkyINXjxtGjPnzuXI\njg9pqMjh3MpSMmzhiAnYdKS/MfJFRxGEjkRMwDQjJmFK5Np/HKpuh8rf5uAqfF1EKpVSJ5IRcHyS\n1z0IfHyoOhrwAIH3XsIVDjGlvBwxTTpbWy3kKnkqKo4MBVTMn0/dgQO89+K7XFR5DT6HWCSEsYca\nIl90FoO/5hRoU6ygORpYNMPe9VD5XAk297+LyBeUUkYiAZ9kuhx43M7TEiDDSV/dfuV5bK+qpaah\nNQY+2N6IvX4/ANm5uaeN/inMKlkjAG6PBwC9q4/qXYe5avVUMjSdDFuYbNPKjrmKwDBPOcNkEjgM\nh/4O5j62ytrM2ZxIwG6AssJJtPf0jTB3J6y7fAnBcJgD9S2xHy088hFrrXpeOMzk6OinUfvE9oFA\ngJlW/dj79WRfmU+GFtEAnwpYz7gi9j+UNL8CBashf+X3ReQFpdTxeAL2AKHZpZOduw8dT67eklrt\nTVPQEjp/cXMdf2HV3+7o4IO2NhYCl6YBHJVjStEILG5u5hKr7T+PdJKp9ZPliGhAhmaNtpjDD/kO\n/RByL/SiZWwE7ogRoJTqE5Ht584queLXb+wZEfiof9A0LWa7dpvJtJ7IiB8GHmhpYX5rKx8BM5Wi\nJM3IHwD+0bJio76efwXcQGnIpLe7mynFGi4tjE254hbJw5RgIzT+B5Su+6qIbFRKHYtqAMDLhTne\nK8qLczlk2XKqlZ6ZsA4wRbBF7dah47bruMMDAHwADAwM0Hj0KB6vl5NwigClOGLtpUdlp1K0A2Ka\nfNrczD7gfCALCOh9ZNodDHKhI02MHPsFTL3ZgbLfAzwYT8DvgE1/dt4s38H6ljTg43d7Ii83TUHT\nFDZNyHYNkGHXCbpcEBoguvRpbWrCkZPDLG1wEnovUBGnAQVAJ9AXCKB0nWlWew+Q54mbOWLPjJCA\n4AloewcmX7ZWRB5SShl2yxv7ReTfLp4//a+f3VZFU1tPkt2c08FDJICyaRo+Z8giwKA1Pwf8PVwK\n/BVw0DC4s72drHgClOJkQv+uAZpEqDYMbgaKrPbjGRoL8x1J9nNGkRo78SpMvqzEyirtjB+SH9lt\nWt/aVUsGhbbpwAOYEtGAPHe/tXIboH5mSayb9wD/AiwWiURq0aLrdOg6xBWbrnOPYfATYGXcO/T5\nbgYrjzZyJxiVjj+BGACrBmWFlVJNwOZLF5WzaGZx0jWAmcTmBkI6HpeNQk9vLG53n19OdZxqC/BD\ny/XGb/53xdWPAOuB6616VPoB56rswS/VA5GR7Ppo5ATofvAfBFiebGfoMaU4+I0bL8HtcgwJHqCl\nK8A5BS6yowsWZ5AZU91sPfdUxuoT4LcW+LuBZqu907r6gTuB96yZIz4ptrXYweqVvoS3mrD/QfAf\nGF0aKFADMPc0ApRSQeC2wpys0HfXrYo5OTONtz3ZGaAwJ+u0BUv+LQv5L48TLFvOimoMEB23XiAM\nfAi0xwUmy616nYKi+4px2sf46EzvUYBCEcnWkoSnu4C7z59Tyv03XMxQuduTnQF83kkJq7Yg5xRq\nHL9/CVV2DY91rqYIKAXOi254WCQsAGZZ5Z+sqbEF2HvbZJZVesZ+QzAUi0wn21PE6D8XkRnXXTL/\nO6YIm17YSarNiJZOPw5HBvkeDc0IWiu2yMrt80u9HH54Hl2bDrKyV2dbwrNhi4AS4OW49hoNau4o\n4Iab8hgXMfqiNZ+W5msPAY/fsHwBj991JZkuR0oNAJg8KSs2+pHSj8/RzyXnuyl8ejbPLfNyOOHZ\nJXPc9MZ9bgdenJGBf3MZ144XeADRY5GwPeXJiYgX/7aINCxfdM6Tv3zwS/ZHf/0W+z89mZSAXJ+P\nYDBoxerh2NI1QwuTN0WY++hU9n0ywO+3daPt7UU1hHAXOXi9LkhNkQOZl0nOCh83LvUw7qflbDGz\n8tuHPEKi1I9FZH9ZYc6vntlwQ9lL7+zjF1t30xXot0wgQkC2NxtnZ9ACHyLDFsap6djUKdNZUO5i\nwdcKYp/XmCTM72dIHLFptWtYr1dK7QAW2jT19JdXLNRf2riOr1+7jCl5Ptp7+tANkyxPDj57RO29\n9iBuW3gQ+KT5uLMBHsBdFp2ETozmpOhsYCNwgyli31vbxNyyQmzt2+HjDdg1A8UEl8XPQN7FVUqp\npSMeA6XUIaXUzUCZptT3llaUVGc47TjyKnFo5sQHr2yQvRjg/VRnhIZLRJNS6lGl1CJgPc5cyJrN\nhBffArBnAfz3ZyIgQX4P6BReOfEJiPQxSOSQ9tgQoJRqAV6n+IsRFZuoojmhcA3AFqVU91hqAMAz\nuIqg8KqJS0DxteDMBfhJwsJ6TOQ1oJrp60HZJ+bol90ZdX7bx5wApZQAj+Aph9J1E4+AstvBPRXg\nu/H7EWMaiiilXgVepfwecJdOHPCeGTD9awDPK6UGrcnGfNoWkVJgL/79uexeC+ZZ/n+ULQPOex48\nFSeBxYn7g2MejCqlGoBb8c4T5jw2HhyPLOiZ9wR4KkxgXbLN0XGJxpVSrwHfpmgNzH747JCgNPjc\nRpi8CuDeRNUfNxNIMIfHgW9xYgsceCR+HT7+Hn/e41DwBYDvK6U2puRpnAkA+A7wGN17FR9viGxZ\nj+tKbyrM3wy++SawQSn1ZFpFORMDIiJfAn5KuDub2k3Q9DKj2tQYSuVLboIZ94Pd2wH8pVJqy5CP\nnSmTFJEZwM+BS+mphk9+DO07xwI55K+A8nvAOxfgTeCu4f7j7Ix6J+v83jrgB0AZgRpoegVO/hFC\n7SP7MdfkSFw/5XrwzASoAx625vqR0HfmxfpzxloiO2eVIOA/BF27IFALfZ9CuAN0K3trzwRHLnjO\nAc8syDkPsiqi3X+fyO7b80opfRT6c3bF+ofadUSO7F8IZA7xSC/wJyuef1kpdfgzGtDEERHRgGlE\n9kZyAa/lLf1AB5FtwwallDlW7/w/D+GUlNdUS4wAAAAASUVORK5CYII=\n' SB_LINE = "Line" SB_COL = "Col" SB_STATE = "State" SB_ENCRYPTION = "Encryption" SHOW = "Show" VALUE = "Value" BITMAP = "Bitmap" STATE_SPAWNING_MENU = {ENABLED: [ML_STOP, ML_DETACH], DISABLED: [ML_ANALYZE, ML_GO, ML_BREAK, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_PWD, ML_LAUNCH, ML_ATTACH, ML_RESTART]} STATE_ATTACHING_MENU = {ENABLED: [ML_STOP, ML_DETACH], DISABLED: [ML_ANALYZE, ML_GO, ML_BREAK, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_PWD, ML_LAUNCH, ML_ATTACH, ML_RESTART]} STATE_BROKEN_MENU = {ENABLED: [ML_ANALYZE, ML_GO, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_STOP, ML_DETACH, ML_RESTART], DISABLED: [ML_PWD, ML_LAUNCH, ML_ATTACH, ML_BREAK]} STATE_ANALYZE_MENU = {ENABLED: [ML_ANALYZE, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_STOP, ML_DETACH, ML_RESTART], DISABLED: [ML_PWD, ML_LAUNCH, ML_ATTACH, ML_BREAK, ML_GO, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO]} STATE_RUNNING_MENU = {ENABLED: [ML_BREAK, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_STOP, ML_DETACH, ML_RESTART], DISABLED: [ML_ANALYZE, ML_PWD, ML_LAUNCH, ML_ATTACH, ML_GO, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO]} STATE_DETACHED_MENU = {ENABLED: [ML_PWD, ML_LAUNCH, ML_ATTACH], DISABLED: [ML_ANALYZE, ML_GO, ML_BREAK, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_STOP, ML_DETACH, ML_RESTART]} STATE_DETACHING_MENU = {ENABLED: [ML_STOP, ML_DETACH], DISABLED: [ML_ANALYZE, ML_GO, ML_BREAK, ML_STEP, ML_NEXT, ML_RETURN, ML_JUMP, ML_GOTO, ML_TOGGLE, ML_DISABLE, ML_ENABLE, ML_CLEAR, ML_LOAD, ML_MORE, ML_SAVE, ML_OPEN, ML_PWD, ML_LAUNCH, ML_ATTACH, ML_RESTART]} STATE_BROKEN_TOOLBAR = {ENABLED: [TB_EXCEPTION, TB_FILTER, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO], DISABLED: [TB_BREAK]} STATE_ANALYZE_TOOLBAR = {ENABLED: [TB_EXCEPTION, TB_FILTER], DISABLED: [TB_BREAK, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_RUNNING_TOOLBAR = {ENABLED: [TB_BREAK], DISABLED: [TB_EXCEPTION, TB_FILTER, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_SPAWNING_TOOLBAR = {ENABLED: [], DISABLED: [TB_EXCEPTION, TB_FILTER, TB_BREAK, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_ATTACHING_TOOLBAR = {ENABLED: [], DISABLED: [TB_EXCEPTION, TB_FILTER, TB_BREAK, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_DETACHED_TOOLBAR = {ENABLED: [], DISABLED: [TB_EXCEPTION, TB_FILTER, TB_BREAK, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_DETACHING_TOOLBAR = {ENABLED: [], DISABLED: [TB_EXCEPTION, TB_FILTER, TB_BREAK, TB_GO, TB_STEP, TB_NEXT, TB_RETURN, TB_GOTO]} STATE_MAP = { rpdb2.STATE_SPAWNING: (STATE_SPAWNING_MENU, STATE_SPAWNING_TOOLBAR), rpdb2.STATE_ATTACHING: (STATE_ATTACHING_MENU, STATE_ATTACHING_TOOLBAR), rpdb2.STATE_BROKEN: (STATE_BROKEN_MENU, STATE_BROKEN_TOOLBAR), rpdb2.STATE_ANALYZE: (STATE_ANALYZE_MENU, STATE_ANALYZE_TOOLBAR), rpdb2.STATE_RUNNING: (STATE_RUNNING_MENU, STATE_RUNNING_TOOLBAR), rpdb2.STATE_DETACHED: (STATE_DETACHED_MENU, STATE_DETACHED_TOOLBAR), rpdb2.STATE_DETACHING: (STATE_DETACHING_MENU, STATE_DETACHING_TOOLBAR) } LICENSE_TITLE = 'License.' ABOUT_TITLE = 'About ' + WINPDB_TITLE ABOUT_HTML_PREFIX = """

""" ABOUT_HTML_SUFFIX = """

""" WEBSITE_URL = "http://www.winpdb.org/" SUPPORT_URL = "http://www.winpdb.org/?page_id=4" DOCS_URL = "http://www.winpdb.org/?page_id=5" EXT_DOCS_URL = "http://www.winpdb.org/?page_id=17" UPDATES_URL = "http://www.winpdb.org/?page_id=3" STR_ERROR_INTERFACE_COMPATIBILITY = "The rpdb2 module which was found by Winpdb is of unexpected version (version expected: %s, version found: %s). Please upgrade to the latest versions of winpdb.py and rpdb2.py." STR_NAMESPACE_DEADLOCK = 'Data Retrieval Timeout' STR_NAMESPACE_LOADING = 'Loading...' BAD_FILE_WARNING_TIMEOUT_SEC = 10.0 DIRTY_CACHE = 1 POSITION_TIMEOUT = 2.0 FILTER_LEVELS = ['Off', 'Medium', 'Maximum'] g_ignored_warnings = {'': True} g_fUnicode = 'unicode' in wx.PlatformInfo assert(g_fUnicode or not rpdb2.is_py3k()) def calc_title(path): (dn, bn) = os.path.split(path) if dn == '': return '%s - %s' % (bn, WINPDB_TITLE) if os.name != rpdb2.POSIX: return '%s (%s) - %s' % (bn, rpdb2.calc_suffix(dn, 64), WINPDB_TITLE) home = os.path.expanduser('~') if dn.startswith(home): dn = '~' + dn[len(home):] return '%s (%s) - %s' % (bn, rpdb2.calc_suffix(dn, 64), WINPDB_TITLE) def calc_denominator(string_list): if string_list in [[], None]: return '' d = string_list[0] for s in string_list[1:]: i = 0 while i < min(len(d), len(s)): if d[i] != s[i]: break i += 1 if i == 0: return '' d = d[:i] return d def open_new(url): if sys.version.startswith('2.5.') and 'ubuntu' in sys.version: w = webbrowser.get() if 'firefox' in w.name: cmd = '%s -new-window "%s"' % (w.name, url) os.popen(cmd) return webbrowser.open_new(url) def image_from_base64(str_b64): b = rpdb2.as_bytes(str_b64) s = base64.decodestring(b) stream = cStringIO.StringIO(s) image = wx.ImageFromStream(stream) return image class CSettings: def __init__(self, default_settings): self.m_dict = default_settings def calc_path(self): if os.name == rpdb2.POSIX: home = os.path.expanduser('~') path = os.path.join(home, '.' + WINPDB_SETTINGS_FILENAME) return path # # gettempdir() is used since it works with unicode user names on # Windows. # tmpdir = tempfile.gettempdir() path = os.path.join(tmpdir, WINPDB_SETTINGS_FILENAME) return path def load_settings(self): try: path = self.calc_path() f = open(path, 'rb') except IOError: return try: d = pickle.load(f) self.m_dict.update(d) except: rpdb2.print_debug_exception() f.close() def save_settings(self): try: path = self.calc_path() f = open(path, 'wb') except IOError: return try: pickle.dump(self.m_dict, f) finally: f.close() def __getitem__(self, key): return self.m_dict[key] def __setitem__(self, key, value): self.m_dict[key] = value class CMenuBar: def __init__(self): self.m_menubar = None self.m_encapsulating_menu_items = {} self.m_cascades = {} def init_menubar(self, resource): if 'wxMac' in wx.PlatformInfo: wx.MenuBar.SetAutoWindowMenu(False) self.m_menubar = wx.MenuBar() self.SetMenuBar(self.m_menubar) self.m_cascades = {ML_ROOT: self.m_menubar} k = resource.keys() k.sort() for c in k: s = (ML_ROOT + c).split('/') sc = [e for e in s if not e.isdigit()] for i, e in enumerate(sc[:-1]): if not e in self.m_cascades: parent_label = sc[i - 1] parent = self.m_cascades[parent_label] child = wx.Menu() if parent_label == ML_ROOT: parent.Append(child, e) else: parent.AppendMenu(wx.NewId(), e, child) self.m_encapsulating_menu_items[e] = parent self.m_cascades[e] = child parent_label = sc[-2] parent = self.m_cascades[parent_label] item_label = sc[-1] if item_label == ML_EMPTY: continue if item_label == ML_SEPARATOR: parent.AppendSeparator() continue command = resource[c][COMMAND] tip = resource[c].get(TOOLTIP, wx.EmptyString) item = parent.Append(-1, item_label, tip) self.Bind(wx.EVT_MENU, command, item) self.m_encapsulating_menu_items[item_label] = parent def set_menu_items_state(self, state_label_dict): for state, label_list in state_label_dict.items(): for item_label in label_list: parent = self.m_encapsulating_menu_items[item_label] id = parent.FindItem(item_label) parent.Enable(id, [True, False][state == DISABLED]) def add_menu_item(self, menu_label, item_label, command): if not g_fUnicode: item_label = rpdb2.as_string(item_label, wx.GetDefaultPyEncoding()) parent = self.m_cascades[menu_label] item = parent.Append(-1, item_label) self.Bind(wx.EVT_MENU, command, item) def clear_menu_items(self, menu_label): parent = self.m_cascades[menu_label] while parent.GetMenuItemCount() > 0: i = parent.FindItemByPosition(0) parent.DeleteItem(i) class CToolBar: def __init__(self): self.m_toolbar = None self.m_items = {} def init_toolbar(self, resource): self.m_toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT) self.m_toolbar.SetToolBitmapSize(TOOLBAR_BITMAP_SIZE) for e in resource: item_label = e[LABEL] if item_label == ML_SEPARATOR: self.m_toolbar.AddSeparator() continue command = e[COMMAND] id = wx.NewId() if TEXT in e: button = wx.Button(self.m_toolbar, id, e[TEXT], style = wx.NO_BORDER) button.SetToolTipString(item_label) self.m_toolbar.AddControl(button) self.m_items[item_label] = {ID: id} wx.EVT_BUTTON(self.m_toolbar, id, command) continue if DATA in e: image = image_from_base64(e[DATA]) bitmap = wx.BitmapFromImage(image) if DATA2 in e: image2 = image_from_base64(e[DATA2]) bitmap2 = wx.BitmapFromImage(image2) self.m_toolbar.AddSimpleTool(id, bitmap, item_label, isToggle = True) self.m_items[item_label] = {ID: id, DATA: bitmap, DATA2: bitmap2} self.Bind(wx.EVT_TOOL, command, id = id) self.Bind(wx.EVT_TOOL, self.OnToggleTool, id = id) else: self.m_toolbar.AddSimpleTool(id, bitmap, item_label) self.m_items[item_label] = {ID: id} self.Bind(wx.EVT_TOOL, command, id = id) self.m_toolbar.Realize() def set_toolbar_item_text(self, label, text): item = self.m_items[label] id = item[ID] tool = self.m_toolbar.FindControl(id) tool.SetLabel(text) size = tool.GetBestSize() tool.SetSize(size) def set_toolbar_items_state(self, state_label_dict): for state, label_list in state_label_dict.items(): for label in label_list: id = self.m_items[label][ID] if (wx.Platform == '__WXGTK__') and (state == ENABLED): self.__gtk_enable_tool(id) else: self.m_toolbar.EnableTool(id, [True, False][state == DISABLED]) def __gtk_enable_tool(self, id): p = self.m_toolbar.ScreenToClient(wx.GetMousePosition()) (x, y) = self.m_toolbar.GetSize() r = wx.RectS((x, y)) if r.Inside(p): self.m_toolbar.WarpPointer(p.x, p.y + 2 * y) self.m_toolbar.EnableTool(id, True) if r.Inside(p): self.m_toolbar.WarpPointer(p.x, p.y) def set_toggle(self, label, fToggle): item = self.m_items[label] id = item[ID] bitmap = [item[DATA], item[DATA2]][fToggle] tool = self.m_toolbar.FindById(id) tool.SetNormalBitmap(bitmap) self.m_toolbar.ToggleTool(id, fToggle) if wx.Platform == '__WXMSW__': self.m_toolbar.Realize() else: self.m_toolbar.ToggleTool(id, not fToggle); self.m_toolbar.ToggleTool(id, fToggle); def OnToggleTool(self, event): tool = self.m_toolbar.FindById(event.GetId()) if tool is None: event.Skip() return label = tool.GetShortHelp() f = event.IsChecked() self.set_toggle(label, f) event.Skip() class CStatusBar: def __init__(self): self.m_statusbar = None self.m_widths = [] self.m_formats = [] self.m_keys = [] self.m_data = {} self.m_bitmaps = {} self.sizeChanged = False def init_statusbar(self, resource): self.m_widths = [e[WIDTH] for e in resource] self.m_formats = [e.get(FORMAT, "") for e in resource] self.m_keys = [e.get(KEYS, []) for e in resource] self.m_statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP) self.m_statusbar.SetFieldsCount(len(self.m_widths)) self.m_statusbar.SetStatusWidths(self.m_widths) self.m_statusbar.Bind(wx.EVT_SIZE, self.OnSize) self.m_statusbar.Bind(wx.EVT_IDLE, self.OnIdle) def set_statusbar_data(self, data): self.m_data.update(data) for i, e in enumerate(self.m_keys): for k in e: if k in data: if self.m_formats[i] == BITMAP: self.set_bitmap(i, data[k][0], data[k][1]) else: self.m_statusbar.SetStatusText(self.m_formats[i] % self.m_data, i) break def set_bitmap(self, i, data, tooltip): if not i in self.m_bitmaps: if data is None: return image = image_from_base64(data) bitmap = wx.BitmapFromImage(image) p = wx.Panel(self.m_statusbar) sb = wx.StaticBitmap(p, -1, bitmap) self.m_bitmaps[i] = (p, sb, tooltip) else: if data is None: self.m_bitmaps[i][0].Hide() else: image = image_from_base64(data) bitmap = wx.BitmapFromImage(image) self.m_bitmaps[i][1].SetBitmap(bitmap) self.m_bitmaps[i][0].Show() self.reposition() def reposition(self): for i, (p, sb, tooltip) in self.m_bitmaps.items(): rect = self.m_statusbar.GetFieldRect(i) p.SetPosition((rect.x + 2, rect.y + 2)) s = sb.GetSize() sb.SetSize((s[0], rect.height - 4)) sb.SetToolTipString(tooltip) p.SetToolTipString(tooltip) p.SetClientSize(sb.GetSize()) self.sizeChanged = False def OnSize(self, event): self.reposition() self.sizeChanged = True def OnIdle(self, event): if self.sizeChanged: self.reposition() class CJobs: def __init__(self): self.__m_jobs_lock = threading.RLock() self.__m_n_expected_jobs = 0 self.__m_f_shutdown = False def init_jobs(self): pass def shutdown_jobs(self): self.__m_f_shutdown = True while 1: try: self.__m_jobs_lock.acquire() if self.__m_n_expected_jobs == 0: return finally: self.__m_jobs_lock.release() time.sleep(0.1) def job_post(self, job, args, kwargs = {}, callback = None): threading.Thread(target = self.job_do, args = (job, args, kwargs, callback)).start() def job_do(self, job, args, kwargs, callback): try: self.__m_jobs_lock.acquire() if self.__m_f_shutdown: return if self.__m_n_expected_jobs == 0: wx.CallAfter(self.set_cursor, wx.CURSOR_WAIT) self.__m_n_expected_jobs += 1 finally: self.__m_jobs_lock.release() r = None exc_info = (None, None, None) try: r = job(*args, **kwargs) except: exc_info = sys.exc_info() if callback == None: rpdb2.print_debug_exception() if callback is not None: wx.CallAfter(callback, r, exc_info) try: self.__m_jobs_lock.acquire() self.__m_n_expected_jobs -= 1 if self.__m_n_expected_jobs == 0: wx.CallAfter(self.set_cursor, wx.CURSOR_ARROW) finally: self.__m_jobs_lock.release() def set_cursor(self, id): cursor = wx.StockCursor(id) self.SetCursor(cursor) class CMainWindow(CMenuBar, CToolBar, CStatusBar, CJobs): def __init__(self): CMenuBar.__init__(self) CToolBar.__init__(self) CStatusBar.__init__(self) CJobs.__init__(self) class CAsyncSessionManagerCall: def __init__(self, session_manager, job_manager, f, callback, ftrace = False): self.m_session_manager = session_manager self.m_job_manager = job_manager self.m_f = f self.m_callback = callback self.m_ftrace = ftrace def __wrapper(self, *args, **kwargs): if self.m_callback != None: try: if self.m_ftrace: rpdb2.print_debug('Calling %s' % repr(self.m_f)) return self.m_f(*args, **kwargs) finally: if self.m_ftrace: rpdb2.print_debug('Returned from %s' % repr(self.m_f)) try: self.m_f(*args, **kwargs) except rpdb2.FirewallBlock: self.m_session_manager.report_exception(*sys.exc_info()) dlg = wx.MessageDialog(self.m_job_manager, rpdb2.STR_FIREWALL_BLOCK, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() except (socket.error, rpdb2.CConnectionException): self.m_session_manager.report_exception(*sys.exc_info()) except rpdb2.CException: self.m_session_manager.report_exception(*sys.exc_info()) except: self.m_session_manager.report_exception(*sys.exc_info()) rpdb2.print_debug_exception(True) def __call__(self, *args, **kwargs): if self.m_job_manager == None: return self.m_job_manager.job_post(self.__wrapper, args, kwargs, self.m_callback) class CAsyncSessionManager: def __init__(self, session_manager, job_manager, callback = None, ftrace = False): self.m_session_manager = session_manager self.m_callback = callback self.m_ftrace = ftrace self.m_weakref_job_manager = None if job_manager != None: self.m_weakref_job_manager = weakref.ref(job_manager) def with_callback(self, callback, ftrace = False): if self.m_weakref_job_manager != None: job_manager = self.m_weakref_job_manager() else: job_manager = None asm = CAsyncSessionManager(self.m_session_manager, job_manager, callback, ftrace) return asm def __getattr__(self, name): f = getattr(self.m_session_manager, name) if not hasattr(f, '__call__'): raise TypeError(repr(type(f)) + ' object is not callable') if self.m_weakref_job_manager != None: job_manager = self.m_weakref_job_manager() else: job_manager = None return CAsyncSessionManagerCall(self.m_session_manager, job_manager, f, self.m_callback, self.m_ftrace) class CWinpdbWindow(wx.Frame, CMainWindow): def __init__(self, session_manager, settings): CMainWindow.__init__(self) wx.Frame.__init__(self, None, -1, WINPDB_TITLE, size = settings[WINPDB_SIZE], style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE) # # Force 'Left to Right' as long as internationalization is not supported. # Not available on wxPython 2.6 # if hasattr(self, 'SetLayoutDirection'): self.SetLayoutDirection(1) image = image_from_base64(BASE64_ICON_16) bitmap = wx.BitmapFromImage(image) icon16 = wx.EmptyIcon() icon16.CopyFromBitmap(bitmap) image = image_from_base64(BASE64_ICON_32) bitmap = wx.BitmapFromImage(image) icon32 = wx.EmptyIcon() icon32.CopyFromBitmap(bitmap) image = image_from_base64(BASE64_ICON_64) bitmap = wx.BitmapFromImage(image) icon64 = wx.EmptyIcon() icon64.CopyFromBitmap(bitmap) ibundle = wx.IconBundle() ibundle.AddIcon(icon16) ibundle.AddIcon(icon32) ibundle.AddIcon(icon64) self.SetIcons(ibundle) self.Maximize(settings[WINPDB_MAXIMIZE]) self.m_session_manager = session_manager self.m_async_sm = CAsyncSessionManager(session_manager, self) self.m_source_manager = CSourceManager(self, session_manager) self.m_settings = settings self.m_stack = None self.m_state = rpdb2.STATE_DETACHED self.m_fembedded_warning = True self.m_filter_level = 1 self.SetMinSize(WINPDB_SIZE_MIN) self.SetSize(settings[WINPDB_SIZE]) self.Centre(wx.BOTH) self.init_jobs() menu_resource = { "/0/" + ML_FILE + "/0/" + ML_PWD: {COMMAND: self.do_password, TOOLTIP: PWD_TIP}, "/0/" + ML_FILE + "/1/" + ML_LAUNCH: {COMMAND: self.do_launch, TOOLTIP: LAUNCH_TIP}, "/0/" + ML_FILE + "/2/" + ML_ATTACH: {COMMAND: self.do_attach, TOOLTIP: ATTACH_TIP}, "/0/" + ML_FILE + "/3/" + ML_OPEN: {COMMAND: self.do_open, TOOLTIP: OPEN_TIP}, "/0/" + ML_FILE + "/4/" + ML_DETACH: {COMMAND: self.do_detach, TOOLTIP: DETACH_TIP}, "/0/" + ML_FILE + "/5/" + ML_STOP: {COMMAND: self.do_stop, TOOLTIP: STOP_TIP}, "/0/" + ML_FILE + "/6/" + ML_RESTART: {COMMAND: self.do_restart, TOOLTIP: RESTART_TIP}, "/0/" + ML_FILE + "/7/" + ML_SEPARATOR: None, "/0/" + ML_FILE + "/8/" + ML_EXIT: {COMMAND: self.do_exit}, "/1/" + ML_BREAKPOINTS + "/0/" + ML_TOGGLE: {COMMAND: self.toggle_breakpoint, TOOLTIP: TOGGLE_TIP}, "/1/" + ML_BREAKPOINTS + "/1/" + ML_DISABLE: {COMMAND: self.do_disable, TOOLTIP: DISABLE_TIP}, "/1/" + ML_BREAKPOINTS + "/2/" + ML_ENABLE: {COMMAND: self.do_enable, TOOLTIP: ENABLE_TIP}, "/1/" + ML_BREAKPOINTS + "/3/" + ML_CLEAR: {COMMAND: self.do_clear, TOOLTIP: CLEAR_TIP}, "/1/" + ML_BREAKPOINTS + "/4/" + ML_LOAD: {COMMAND: self.do_load, TOOLTIP: LOAD_TIP}, "/1/" + ML_BREAKPOINTS + "/5/" + ML_SAVE: {COMMAND: self.do_save, TOOLTIP: SAVE_TIP}, "/1/" + ML_BREAKPOINTS + "/6/" + ML_MORE: {COMMAND: self.do_more_bp, TOOLTIP: MORE_TIP}, "/2/" + ML_CONTROL + "/0/" + ML_ANALYZE: {COMMAND: self.do_analyze_menu, TOOLTIP: ANALYZE_TIP}, "/2/" + ML_CONTROL + "/1/" + ML_BREAK: {COMMAND: self.do_break, TOOLTIP: BREAK_TIP}, "/2/" + ML_CONTROL + "/2/" + ML_GO: {COMMAND: self.do_go, TOOLTIP: GO_TIP}, "/2/" + ML_CONTROL + "/3/" + ML_NEXT: {COMMAND: self.do_next, TOOLTIP: NEXT_TIP}, "/2/" + ML_CONTROL + "/4/" + ML_STEP: {COMMAND: self.do_step, TOOLTIP: STEP_TIP}, "/2/" + ML_CONTROL + "/5/" + ML_GOTO: {COMMAND: self.do_goto, TOOLTIP: GOTO_TIP}, "/2/" + ML_CONTROL + "/6/" + ML_RETURN: {COMMAND: self.do_return, TOOLTIP: RETURN_TIP}, "/2/" + ML_CONTROL + "/7/" + ML_JUMP: {COMMAND: self.do_jump, TOOLTIP: JUMP_TIP}, "/3/" + ML_WINDOW + "/0/" + ML_EMPTY: None, "/4/" + ML_HELP + "/0/" + ML_WEBSITE: {COMMAND: self.do_website, TOOLTIP: WEBSITE_TIP}, "/4/" + ML_HELP + "/1/" + ML_SUPPORT: {COMMAND: self.do_support, TOOLTIP: SUPPORT_TIP}, "/4/" + ML_HELP + "/2/" + ML_DOCS: {COMMAND: self.do_docs, TOOLTIP: DOCS_TIP}, "/4/" + ML_HELP + "/3/" + ML_EXT_DOCS: {COMMAND: self.do_ext_docs, TOOLTIP: EXT_DOCS_TIP}, "/4/" + ML_HELP + "/4/" + ML_UPDATES: {COMMAND: self.do_updates, TOOLTIP: UPDATES_TIP}, "/4/" + ML_HELP + "/5/" + ML_ABOUT: {COMMAND: self.do_about}, "/4/" + ML_HELP + "/6/" + ML_LICENSE: {COMMAND: self.do_license} } self.init_menubar(menu_resource) toolbar_resource = [ {LABEL: TB_BREAK, DATA: BASE64_BREAK, COMMAND: self.do_break}, {LABEL: TB_GO, DATA: BASE64_GO, COMMAND: self.do_go}, {LABEL: ML_SEPARATOR}, {LABEL: TB_NEXT, DATA: BASE64_NEXT, COMMAND: self.do_next}, {LABEL: TB_STEP, DATA: BASE64_STEP, COMMAND: self.do_step}, {LABEL: TB_GOTO, DATA: BASE64_GOTO, COMMAND: self.do_goto}, {LABEL: TB_RETURN, DATA: BASE64_RETURN, COMMAND: self.do_return}, {LABEL: ML_SEPARATOR}, {LABEL: TB_EXCEPTION, DATA: BASE64_EXCEPTION, DATA2: BASE64_EXCEPTION, COMMAND: self.do_analyze}, {LABEL: TB_TRAP, DATA: BASE64_TRAP, DATA2: BASE64_TRAP, COMMAND: self.do_trap}, {LABEL: ML_SEPARATOR}, {LABEL: TB_FILTER, TEXT: TB_FILTER_TEXT, COMMAND: self.do_filter}, {LABEL: ML_SEPARATOR}, {LABEL: TB_ENCODING, TEXT: TB_ENCODING_TEXT, COMMAND: self.do_encoding}, {LABEL: ML_SEPARATOR}, {LABEL: TB_SYNCHRONICITY, TEXT: TB_SYNCHRONICITY_TEXT, COMMAND: self.do_synchronicity} ] self.init_toolbar(toolbar_resource) self.set_toolbar_item_text(TB_FILTER, TB_FILTER_TEXT % FILTER_LEVELS[self.m_filter_level]) self.set_toolbar_item_text(TB_ENCODING, TB_ENCODING_TEXT % 'auto') self.set_toolbar_item_text(TB_SYNCHRONICITY, TB_SYNCHRONICITY_TEXT % 'True') ftrap = self.m_session_manager.get_trap_unhandled_exceptions() self.set_toggle(TB_TRAP, ftrap) statusbar_resource = [ {WIDTH: -2}, {WIDTH: -1, FORMAT: SB_STATE + ": %(" + SB_STATE + ")s", KEYS: [SB_STATE]}, {WIDTH: -1, FORMAT: SB_LINE + ": %(" + SB_LINE + ")d " + SB_COL + ": %(" + SB_COL + ")d", KEYS: [SB_LINE, SB_COL]}, {WIDTH: 50, FORMAT: BITMAP, KEYS: [SB_ENCRYPTION]} ] self.init_statusbar(statusbar_resource) self.m_splitterv = wx.SplitterWindow(self, -1, style = wx.SP_LIVE_UPDATE | wx.SP_NOBORDER) self.m_splitterv.SetMinimumPaneSize(100) self.m_splitterv.SetSashGravity(0.5) self.m_splitterh1 = wx.SplitterWindow(self.m_splitterv, -1, style = wx.SP_LIVE_UPDATE | wx.SP_NOBORDER) self.m_splitterh1.SetMinimumPaneSize(70) self.m_splitterh1.SetSashGravity(0.67) self.m_splitterh2 = wx.SplitterWindow(self.m_splitterh1, -1, style = wx.SP_LIVE_UPDATE | wx.SP_NOBORDER) self.m_splitterh2.SetMinimumPaneSize(70) self.m_splitterh2.SetSashGravity(0.5) self.m_namespace_viewer = CNamespaceViewer(self.m_splitterh2, style = wx.NO_BORDER, session_manager = self.m_session_manager) self.m_namespace_viewer.set_filter(self.m_filter_level) self.m_threads_viewer = CThreadsViewer(self.m_splitterh2, style = wx.NO_BORDER, select_command = self.OnThreadSelected) self.m_stack_viewer = CStackViewer(self.m_splitterh1, style = wx.NO_BORDER, select_command = self.OnFrameSelected) self.m_splitterh3 = wx.SplitterWindow(self.m_splitterv, -1, style = wx.SP_LIVE_UPDATE | wx.SP_NOBORDER) self.m_splitterh3.SetMinimumPaneSize(100) self.m_splitterh3.SetSashGravity(1.0) self.m_code_viewer = CCodeViewer(self.m_splitterh3, style = wx.NO_BORDER | wx.TAB_TRAVERSAL, session_manager = self.m_session_manager, source_manager = self.m_source_manager, notify_filename = self.do_notify_filename) self.m_console = CConsole(self.m_splitterh3, style = wx.NO_BORDER | wx.TAB_TRAVERSAL, session_manager = self.m_session_manager, exit_command = self.do_exit) self.m_splitterh2.SplitHorizontally(self.m_namespace_viewer, self.m_threads_viewer) self.m_splitterh1.SplitHorizontally(self.m_splitterh2, self.m_stack_viewer) self.m_splitterv.SplitVertically(self.m_splitterh1, self.m_splitterh3) self.m_splitterh3.SplitHorizontally(self.m_code_viewer, self.m_console) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.Bind(wx.EVT_SIZE, self.OnSizeWindow) state = self.m_session_manager.get_state() self.update_state(rpdb2.CEventState(state)) event_type_dict = {rpdb2.CEventState: {}} self.m_session_manager.register_callback(self.update_state, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventStackFrameChange: {}} self.m_session_manager.register_callback(self.update_frame, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventThreads: {}} self.m_session_manager.register_callback(self.update_threads, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventNoThreads: {}} self.m_session_manager.register_callback(self.update_no_threads, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventNamespace: {}} self.m_session_manager.register_callback(self.update_namespace, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventUnhandledException: {}} self.m_session_manager.register_callback(self.update_unhandled_exception, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventConflictingModules: {}} self.m_session_manager.register_callback(self.update_conflicting_modules, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventThreadBroken: {}} self.m_session_manager.register_callback(self.update_thread_broken, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventStack: {}} self.m_session_manager.register_callback(self.update_stack, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventBreakpoint: {}} self.m_session_manager.register_callback(self.update_bp, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventTrap: {}} self.m_session_manager.register_callback(self.update_trap, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventEncoding: {}} self.m_session_manager.register_callback(self.update_encoding, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventSynchronicity: {}} self.m_session_manager.register_callback(self.update_synchronicity, event_type_dict, fSingleUse = False) event_type_dict = {rpdb2.CEventClearSourceCache: {}} self.m_session_manager.register_callback(self.update_source_cache, event_type_dict, fSingleUse = False) wx.CallAfter(self.__init2) def start(self, fchdir, command_line, fAttach): self.m_console.start() if fAttach: self.m_async_sm.attach(command_line, encoding = rpdb2.detect_locale()) elif command_line != '': self.m_async_sm.launch(fchdir, command_line, encoding = rpdb2.detect_locale()) # #-------------------------------------------------- # def __init2(self): self.m_splitterh1.SetSashPosition(self.m_settings[SPLITTER_2_POS]) self.m_splitterh2.SetSashPosition(self.m_settings[SPLITTER_1_POS]) self.m_splitterv.SetSashPosition(self.m_settings[SPLITTER_3_POS]) self.m_splitterh3.SetSashPosition(self.m_settings[SPLITTER_4_POS]) self.CheckInterpreterConflict() def CheckInterpreterConflict(self): """ On Windows, Winpdb can be started with a double click. The Python interpreter is chosen according to extension binding. With multiple Python installations it is possible that a winpdb version installed on one Python installation will be launched with the wrong python interpreter. This can lead to confusion and is prevented with this code. """ if os.name != 'nt': return try: path_m = sys.modules['__main__'].__file__.lower() if not os.path.dirname(path_m)[1:] in [r':\python23\scripts', r':\python24\scripts', r':\python25\scripts']: return except: return path_e = sys.executable.lower() if path_m[: 12] != path_e[: 12]: dlg = wx.MessageDialog(self, PYTHON_WARNING_MSG % (path_m, path_e), PYTHON_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() # #----------------- Thread list logic -------------- # def OnThreadSelected(self, tid): self.m_async_sm.set_thread(tid) def update_threads(self, event): wx.CallAfter(self.m_threads_viewer.update_threads_list, event.m_current_thread, event.m_thread_list) def update_no_threads(self, event): wx.CallAfter(self.clear_all) def clear_all(self): self.m_code_viewer._clear() self.m_namespace_viewer._clear() self.m_stack_viewer._clear() self.m_threads_viewer._clear() def update_thread_broken(self, event): wx.CallAfter(self.m_threads_viewer.update_thread, event.m_tid, event.m_name, True) # #---------------------------------------------------- # def update_bp(self, event): wx.CallAfter(self.m_code_viewer.update_bp, event) def toggle_breakpoint(self, event): self.m_code_viewer.toggle_breakpoint() # #------------------- Frame Select Logic ------------- # def OnFrameSelected(self, event): self.m_async_sm.set_frame_index(event.m_itemIndex) def update_frame(self, event): wx.CallAfter(self.do_update_frame, event.m_frame_index) def do_update_frame(self, index): self.do_set_position(index) self.m_stack_viewer.select_frame(index) # #---------------------------------------------------------- # def update_stack(self, event): self.m_stack = event.m_stack wx.CallAfter(self.do_update_stack, event.m_stack) def do_update_stack(self, _stack): self.m_stack = _stack self.m_stack_viewer.update_stack_list(self.m_stack) index = self.m_session_manager.get_frame_index() self.do_update_frame(index) def do_set_position(self, index): s = self.m_stack[rpdb2.DICT_KEY_STACK] e = s[-(1 + index)] filename = e[0] lineno = e[1] fBroken = self.m_stack[rpdb2.DICT_KEY_BROKEN] _event = self.m_stack[rpdb2.DICT_KEY_EVENT] __event = ['running', ['call', _event][index == 0]][fBroken] self.m_code_viewer.set_position(filename, lineno, __event) # #---------------------------------------------------- # def do_encoding(self, event): encoding, fraw = self.m_session_manager.get_encoding() dlg = CEncodingDialog(self, encoding, fraw) r = dlg.ShowModal() if r == wx.ID_OK: encoding, fraw = dlg.get_encoding() self.m_session_manager.set_encoding(encoding, fraw) dlg.Destroy() def do_synchronicity(self, event): fsynchronicity = self.m_session_manager.get_synchronicity() dlg = CSynchronicityDialog(self, fsynchronicity) r = dlg.ShowModal() if r == wx.ID_OK: fsynchronicity = dlg.get_synchronicity() self.m_session_manager.set_synchronicity(fsynchronicity) dlg.Destroy() def do_analyze_menu(self, event): state = self.m_session_manager.get_state() f = (state != rpdb2.STATE_ANALYZE) self.m_async_sm.set_analyze(f) def do_analyze(self, event): f = event.IsChecked() self.m_async_sm.set_analyze(f) def update_trap(self, event): wx.CallAfter(self.set_toggle, TB_TRAP, event.m_ftrap) def do_trap(self, event): f = event.IsChecked() if not f: dlg = wx.MessageDialog(self, MSG_WARNING_TRAP, MSG_WARNING_TITLE, wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) res = dlg.ShowModal() dlg.Destroy() if res == wx.ID_NO: self.set_toggle(TB_TRAP, True) return self.m_async_sm.set_trap_unhandled_exceptions(f) def update_namespace(self, event): wx.CallAfter(self.m_namespace_viewer.update_namespace, self.m_stack) def update_unhandled_exception(self, event): wx.CallAfter(self.notify_unhandled_exception) def notify_unhandled_exception(self): dlg = wx.MessageDialog(self, MSG_WARNING_UNHANDLED_EXCEPTION, MSG_WARNING_TITLE, wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) res = dlg.ShowModal() dlg.Destroy() if res != wx.ID_YES: return self.m_async_sm.set_analyze(True) def update_conflicting_modules(self, event): wx.CallAfter(self.notify_conflicting_modules, event) def notify_conflicting_modules(self, event): s = ', '.join(event.m_modules_list) if not g_fUnicode: s = rpdb2.as_string(s, wx.GetDefaultPyEncoding()) dlg = wx.MessageDialog(self, rpdb2.STR_CONFLICTING_MODULES % s, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() def do_filter(self, event): self.m_filter_level = (self.m_filter_level + 1) % 3 self.set_toolbar_item_text(TB_FILTER, TB_FILTER_TEXT % FILTER_LEVELS[self.m_filter_level]) self.m_namespace_viewer.set_filter(self.m_filter_level) self.m_namespace_viewer.update_namespace(self.m_stack) def do_notify_filename(self, filename, command): if command is not None: self.add_menu_item(ML_WINDOW, filename, command) self.m_console.set_filename(filename) def OnSizeWindow(self, event): if not self.IsMaximized(): # # On a Mac, the size is magically increased by 47; decrease it back. # (w, h) = self.GetSize() if sys.platform == 'darwin': h -= 47 self.m_settings[WINPDB_SIZE] = (w, h) event.Skip() def OnCloseWindow(self, event): if event.CanVeto() and self.m_session_manager.get_state() != rpdb2.STATE_DETACHED: dlg = wx.MessageDialog(self, STR_EXIT_WARNING, MSG_WARNING_TITLE, wx.YES_NO | wx.CANCEL | wx.YES_DEFAULT | wx.ICON_WARNING) res = dlg.ShowModal() dlg.Destroy() if res == wx.ID_CANCEL: event.Veto() return if res == wx.ID_NO: f = lambda r, exc_info: self.Close() self.m_async_sm.with_callback(f).detach() event.Veto() return try: self.m_session_manager.stop_debuggee() except: pass self.m_settings[WINPDB_MAXIMIZE] = self.IsMaximized() self.m_settings[SPLITTER_1_POS] = self.m_splitterh2.GetSashPosition() self.m_settings[SPLITTER_2_POS] = self.m_splitterh1.GetSashPosition() self.m_settings[SPLITTER_3_POS] = self.m_splitterv.GetSashPosition() self.m_settings[SPLITTER_4_POS] = self.m_splitterh3.GetSashPosition() self.m_console.stop() self.shutdown_jobs() self.Destroy() event.Skip() def set_cursor(self, id): cursor = wx.StockCursor(id) self.SetCursor(cursor) self.m_code_viewer.set_cursor(id) self.m_threads_viewer.set_cursor(id) self.m_stack_viewer.set_cursor(id) def do_none(self, event): pass def update_source_cache(self, event): wx.CallAfter(self.callback_source_cache, event) def callback_source_cache(self, event): self.m_source_manager.mark_files_dirty() self.m_code_viewer.refresh() def update_encoding(self, event): wx.CallAfter(self.callback_encoding, event) def callback_encoding(self, event): encoding, fraw = self.m_session_manager.get_encoding() if encoding != rpdb2.ENCODING_AUTO: try: codecs.lookup(encoding) except: encoding += ' (?)' if fraw: encoding += ', ' + rpdb2.ENCODING_RAW self.set_toolbar_item_text(TB_ENCODING, TB_ENCODING_TEXT % encoding) def update_synchronicity(self, event): wx.CallAfter(self.callback_synchronicity, event) def callback_synchronicity(self, event): fsynchronicity = self.m_session_manager.get_synchronicity() self.set_toolbar_item_text(TB_SYNCHRONICITY, TB_SYNCHRONICITY_TEXT % str(fsynchronicity)) def update_state(self, event): wx.CallAfter(self.callback_state, event) def callback_state(self, event): old_state = self.m_state self.m_state = event.m_state (menu_update_dict, toolbar_update_dict) = STATE_MAP[self.m_state] self.set_menu_items_state(menu_update_dict) self.set_toolbar_items_state(toolbar_update_dict) try: index = STATE_DETACHED_MENU[DISABLED].index(ML_RESTART) del STATE_DETACHED_MENU[DISABLED][index] STATE_DETACHED_MENU[ENABLED].append(ML_RESTART) except ValueError: pass state_text = self.m_state if state_text == rpdb2.STATE_BROKEN: state_text = rpdb2.STR_STATE_BROKEN self.set_statusbar_data({SB_STATE: state_text.upper()}) if self.m_state == rpdb2.STATE_DETACHED: self.m_fembedded_warning = True self.set_statusbar_data({SB_ENCRYPTION: (None, None)}) self.clear_menu_items(ML_WINDOW) self.m_source_manager._clear() self.m_code_viewer._clear() self.m_namespace_viewer._clear() self.m_stack_viewer._clear() self.m_threads_viewer._clear() self.m_console.set_focus() self.SetTitle(WINPDB_TITLE) elif (old_state in [rpdb2.STATE_DETACHED, rpdb2.STATE_DETACHING, rpdb2.STATE_SPAWNING, rpdb2.STATE_ATTACHING]) and (self.m_state not in [rpdb2.STATE_DETACHED, rpdb2.STATE_DETACHING, rpdb2.STATE_SPAWNING, rpdb2.STATE_ATTACHING]): try: serverinfo = self.m_session_manager.get_server_info() title = calc_title(serverinfo.m_filename) self.SetTitle(title) f = self.m_session_manager.get_encryption() except rpdb2.NotAttached: f = False data = [BASE64_UNLOCKED, BASE64_LOCKED][f] tooltip = [TOOLTIP_UNLOCKED, TOOLTIP_LOCKED][f] self.set_statusbar_data({SB_ENCRYPTION: (data, tooltip)}) if self.m_state == rpdb2.STATE_BROKEN: self.set_toggle(TB_EXCEPTION, False) #self.m_code_viewer._enable() self.m_namespace_viewer._enable() self.m_stack_viewer._enable() self.m_threads_viewer._enable() self.Raise() if self.m_fembedded_warning and self.m_session_manager.get_server_info().m_fembedded: self.m_fembedded_warning = False warning = STR_EMBEDDED_WARNING if not warning in g_ignored_warnings: dlg = wx.MessageDialog(self, MSG_WARNING_TEMPLATE % (warning, ), MSG_WARNING_TITLE, wx.OK | wx.CANCEL | wx.YES_DEFAULT | wx.ICON_WARNING) res = dlg.ShowModal() dlg.Destroy() if res == wx.ID_CANCEL: g_ignored_warnings[warning] = True elif self.m_state == rpdb2.STATE_ANALYZE: self.set_toggle(TB_EXCEPTION, True) #self.m_code_viewer._enable() self.m_namespace_viewer._enable() self.m_stack_viewer._enable() self.m_threads_viewer._disable() self.m_console.set_focus() else: #self.m_code_viewer._disable() self.m_namespace_viewer._disable() self.m_stack_viewer._disable() self.m_threads_viewer._disable() self.m_console.set_focus() def do_website(self, event): self.job_post(open_new, (WEBSITE_URL, )) def do_support(self, event): self.job_post(open_new, (SUPPORT_URL, )) def do_docs(self, event): self.job_post(open_new, (DOCS_URL, )) def do_ext_docs(self, event): self.job_post(open_new, (EXT_DOCS_URL, )) def do_updates(self, event): self.job_post(open_new, (UPDATES_URL, )) def do_license(self, event): about = CHTMLDialog(self, LICENSE_TITLE, LICENSE_NOTICE + COPY_OF_THE_GPL_LICENSE) about.ShowModal() about.Destroy() def do_about(self, event): about = CHTMLDialog(self, ABOUT_TITLE, ABOUT_NOTICE) about.ShowModal() about.Destroy() def do_password(self, event): pwd = self.m_session_manager.get_password() pwd_dialog = CPwdDialog(self, pwd) r = pwd_dialog.ShowModal() if r == wx.ID_OK: pwd = pwd_dialog.get_password() try: self.m_session_manager.set_password(pwd) except rpdb2.AlreadyAttached: assert(0) pwd_dialog.Destroy() def do_launch(self, event): (fchdir, command_line) = self.m_session_manager.get_launch_args() if None in (fchdir, command_line): (fchdir, command_line) = (True, '') launch_dialog = CLaunchDialog(self, fchdir, command_line) r = launch_dialog.ShowModal() if r == wx.ID_OK: (command_line, fchdir) = launch_dialog.get_command_line() self.m_async_sm.launch(fchdir, command_line) launch_dialog.Destroy() def do_open(self, event): host = self.m_session_manager.get_host().lower() flocal = (host in [rpdb2.LOCALHOST, rpdb2.LOOPBACK]) open_dialog = COpenDialog(self, flocal) r = open_dialog.ShowModal() if r == wx.ID_OK: file_name = open_dialog.get_file_name() self.m_code_viewer.set_file(file_name, fComplain = True) open_dialog.Destroy() def do_attach(self, event): attach_dialog = CAttachDialog(self, self.m_session_manager) r = attach_dialog.ShowModal() if r == wx.ID_OK: server = attach_dialog.get_server() self.m_async_sm.attach(server.m_rid, server.m_filename) attach_dialog.Destroy() def do_detach(self, event): self.m_async_sm.detach() def do_stop(self, event): self.m_async_sm.stop_debuggee() def do_restart(self, event): self.m_async_sm.restart() def do_disable(self, event): self.m_async_sm.disable_breakpoint([], True) def do_enable(self, event): self.m_async_sm.enable_breakpoint([], True) def do_clear(self, event): self.m_async_sm.delete_breakpoint([], True) def do_load(self, event): self.m_async_sm.with_callback(self.callback_load).load_breakpoints() def callback_load(self, r, exc_info): (t, v, tb) = exc_info if t == socket.error or isinstance(v, rpdb2.CException): error = rpdb2.STR_BREAKPOINTS_LOAD_PROBLEM elif t == IOError: error = rpdb2.STR_BREAKPOINTS_NOT_FOUND else: return dlg = wx.MessageDialog(self, error, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() def do_save(self, event): self.m_async_sm.with_callback(self.callback_save).save_breakpoints() def do_more_bp(self, event): dlg = wx.MessageDialog(self, STR_MORE_ABOUT_BREAKPOINTS, MORE_TIP, wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def do_jump(self, event): dlg = wx.MessageDialog(self, STR_HOW_TO_JUMP, MORE_TIP, wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def callback_save(self, r, exc_info): (t, v, tb) = exc_info if t in (socket.error, IOError) or isinstance(v, rpdb2.CException): error = rpdb2.STR_BREAKPOINTS_SAVE_PROBLEM else: return dlg = wx.MessageDialog(self, error, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() def do_go(self, event): self.m_async_sm.request_go() def do_break(self, event): self.m_async_sm.request_break() def do_step(self, event): self.m_async_sm.request_step() def do_next(self, event): self.m_async_sm.request_next() def do_return(self, event): self.m_async_sm.request_return() def do_goto(self, event): (filename, lineno) = self.m_code_viewer.get_file_lineno() self.m_async_sm.request_go_breakpoint(filename, '', lineno) def do_exit(self, event = None): self.Close() class CWinpdbApp(wx.App): def __init__(self, session_manager, fchdir, command_line, fAttach, fAllowUnencrypted): self.m_frame = None self.m_session_manager = session_manager self.m_fchdir = fchdir self.m_command_line = command_line self.m_fAttach = fAttach self.m_fAllowUnencrypted = fAllowUnencrypted self.m_settings = CSettings(WINPDB_SETTINGS_DEFAULT) wx.App.__init__(self, redirect = False) def OnInit(self): wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1) self.m_settings.load_settings() if (not self.m_fAllowUnencrypted) and not rpdb2.is_encryption_supported(): dlg = wx.MessageDialog(None, rpdb2.STR_ENCRYPTION_SUPPORT_ERROR, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return True self.m_frame = CWinpdbWindow(self.m_session_manager, self.m_settings) self.m_frame.Show() self.m_frame.start(self.m_fchdir, self.m_command_line, self.m_fAttach) self.SetTopWindow(self.m_frame) return True def OnExit(self): self.m_settings.save_settings() class CCaption(wx.Panel): def __init__(self, *args, **kwargs): label = kwargs.pop("label", "") wx.Panel.__init__(self, *args, **kwargs) self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) self.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_CAPTIONTEXT)) sizerv = wx.BoxSizer(wx.VERTICAL) self.m_static_text = wx.StaticText(self, -1, label) sizerv.Add(self.m_static_text, 0, wx.EXPAND | wx.ALL, 2) font = self.m_static_text.GetFont() new_font = wx.Font(pointSize = font.GetPointSize(), family = font.GetFamily(), style = font.GetStyle(), weight = wx.BOLD, face = font.GetFaceName()) self.m_static_text.SetFont(new_font) self.SetSizer(sizerv) sizerv.Fit(self) class CCaptionManager: def bind_caption(self, widget): widget.Bind(wx.EVT_SET_FOCUS, self.OnGainFocus) widget.Bind(wx.EVT_KILL_FOCUS, self.OnLoseFocus) self.m_n_focus = 0 def OnGainFocus(self, event): self.m_n_focus += 1 self.m_caption.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)) self.m_caption.Refresh() event.Skip() def OnLoseFocus(self, event): self.m_n_focus -= 1 if self.m_n_focus > 0: return self.m_caption.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) self.m_caption.Refresh() event.Skip() class CStyledViewer(stc.StyledTextCtrl): def __init__(self, *args, **kwargs): self.m_margin_command = kwargs.pop('margin_command', None) stc.StyledTextCtrl.__init__(self, *args, **kwargs) # # Force Left to Right since CStyledViewer is broken for Right to Left. # Not available on wxPython 2.6 # if hasattr(self, 'SetLayoutDirection'): self.SetLayoutDirection(1) self.SetLexer(stc.STC_LEX_PYTHON) self.SetKeyWords(0, " ".join(keyword.kwlist)) self.SetReadOnly(True) self.SetVisiblePolicy(wx.stc.STC_VISIBLE_SLOP, 7) self.SetViewWhiteSpace(False) self.SetIndentationGuides(True) self.SetEOLMode(stc.STC_EOL_LF) self.SetViewEOL(False) self.SetProperty("fold", "0") self.SetMarginType(0, stc.STC_MARGIN_NUMBER) self.SetMarginMask(0, 0x0) self.SetMarginWidth(0, 40) self.SetMarginType(1, stc.STC_MARGIN_SYMBOL) self.SetMarginMask(1, 0x1F) self.SetMarginWidth(1, 16) self.SetMarginSensitive(1, True) if self.m_margin_command is not None: self.Bind(stc.EVT_STC_MARGINCLICK, self.m_margin_command) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) self.Bind(wx.EVT_KEY_UP, self.OnKeyReleased) if wx.Platform == '__WXMSW__': self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New,size:9') else: self.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier') self.StyleClearAll() self.SetTabWidth(rpdb2.PYTHON_TAB_WIDTH) self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, 'fore:#000000,back:#99A9C2') self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, 'fore:#00009D,back:#FFFF00') self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, 'fore:#00009D,back:#FF0000') self.StyleSetSpec(stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") self.StyleSetSpec(stc.STC_P_DEFAULT, 'fore:#000000') self.StyleSetSpec(stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') self.StyleSetSpec(stc.STC_P_NUMBER, 'fore:#008050') self.StyleSetSpec(stc.STC_P_STRING, 'fore:#800080') self.StyleSetSpec(stc.STC_P_CHARACTER, 'fore:#800080') self.StyleSetSpec(stc.STC_P_WORD, 'fore:#000080,bold') self.StyleSetSpec(stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') self.StyleSetSpec(stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') self.StyleSetSpec(stc.STC_P_DEFNAME, 'fore:#008050,bold') self.StyleSetSpec(stc.STC_P_OPERATOR, 'fore:#800000,bold') self.StyleSetSpec(stc.STC_P_IDENTIFIER, 'fore:#000000') self.SetSelBackground(True, '#316ac5') self.SetSelForeground(True, wx.WHITE) self.MarkerDefine(MARKER_BREAKPOINT_ENABLED, stc.STC_MARKER_MAX, wx.BLACK, (255, 0, 0)) self.MarkerDefine(MARKER_BREAKPOINT_DISABLED, stc.STC_MARKER_MAX, wx.BLACK, (255, 255, 128)) self.MarkerDefine(MARKER_CURRENT_LINE, stc.STC_MARKER_MAX, wx.WHITE, (150, 150, 255)) self.MarkerDefine(MARKER_CURRENT_LINE_HIT, stc.STC_MARKER_MAX, wx.BLACK, (215, 215, 255)) self.MarkerDefine(MARKER_CALL, stc.STC_MARK_CHARACTER + ord('C'), wx.WHITE, "#99A9C2") self.MarkerDefine(MARKER_LINE, stc.STC_MARK_CHARACTER + ord('L'), wx.WHITE, "#99A9C2") self.MarkerDefine(MARKER_RETURN, stc.STC_MARK_CHARACTER + ord('R'), wx.WHITE, "#99A9C2") self.MarkerDefine(MARKER_EXCEPTION, stc.STC_MARK_CHARACTER + ord('E'), wx.WHITE, "#99A9C2") self.MarkerDefine(MARKER_RUNNING, stc.STC_MARK_CHARACTER + ord('*'), wx.WHITE, "#99A9C2") def _clear(self): self.SetReadOnly(False) self.ClearAll() self.SetReadOnly(True) def load_source(self, value): self.SetReadOnly(False) self.ClearAll() self.SetText(value) self.SetReadOnly(True) self.GotoLine(0) self.EmptyUndoBuffer() self.SetSavePoint() def OnKeyReleased(self, event): key_code = event.GetKeyCode() if key_code == wx.WXK_CONTROL: self.GetParent().GetEventHandler().ProcessEvent(event) event.Skip() def OnKeyPressed(self, event): key_code = event.GetKeyCode() if key_code == wx.WXK_TAB: forward = not event.ShiftDown() switch = event.ControlDown() if switch: self.GetParent().GetEventHandler().ProcessEvent(event) return ne = wx.NavigationKeyEvent() ne.SetDirection(forward) ne.SetCurrentFocus(self) ne.SetEventObject(self) self.GetParent().GetEventHandler().ProcessEvent(ne) event.Skip() return event.Skip() class CSourceManager: def __init__(self, job_manager, session_manager): self.m_job_manager = job_manager self.m_session_manager = session_manager self.m_async_sm = CAsyncSessionManager(session_manager, self.m_job_manager) self.m_files = {} self.m_lock = threading.RLock() def _clear(self): self.m_files = {} def mark_files_dirty(self): for k, v in list(self.m_files.items()): self.m_files[k] = (DIRTY_CACHE, rpdb2.as_string('')) def is_in_files(self, filename): for k in list(self.m_files.keys()): if filename in k: return True return False def get_source(self, filename): for k, v in list(self.m_files.items()): if not filename in k: continue (_time, source) = v if _time == 0: return (k, source) t = time.time() if t - _time < BAD_FILE_WARNING_TIMEOUT_SEC: return (k, source) #del self.m_files[k] raise KeyError raise KeyError def load_source(self, filename, callback, args, fComplain): f = lambda r, exc_info: self.callback_load_source(r, exc_info, filename, callback, args, fComplain) self.m_async_sm.with_callback(f, ftrace = True).get_source_file(filename, -1, -1) def callback_load_source(self, r, exc_info, filename, callback, args, fComplain): (t, v, tb) = exc_info if self.m_session_manager.get_state() == rpdb2.STATE_DETACHED: return if t == None: _time = 0 _filename = r[rpdb2.DICT_KEY_FILENAME] source_lines = r[rpdb2.DICT_KEY_LINES] source = string.join(source_lines, '') if not g_fUnicode: source = rpdb2.as_string(source, wx.GetDefaultPyEncoding()) elif t == rpdb2.NotPythonSource and fComplain: dlg = wx.MessageDialog(None, MSG_ERROR_FILE_NOT_PYTHON % (filename, ), MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() return elif t in (IOError, socket.error, rpdb2.NotPythonSource) or isinstance(v, rpdb2.CConnectionException): if fComplain: dlg = wx.MessageDialog(None, STR_FILE_LOAD_ERROR % (filename, ), MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() return if t == IOError and rpdb2.BLENDER_SOURCE_NOT_AVAILABLE in v.args and not self.is_in_files(filename): dlg = wx.MessageDialog(None, STR_BLENDER_SOURCE_WARNING, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() _time = time.time() _filename = filename source = STR_FILE_LOAD_ERROR2 % (filename, ) if not g_fUnicode: source = rpdb2.as_string(source, wx.GetDefaultPyEncoding()) else: rpdb2.print_debug('get_source_file() returned the following error: %s' % repr(t)) _time = time.time() _filename = filename source = STR_FILE_LOAD_ERROR2 % (filename, ) if not g_fUnicode: source = rpdb2.as_string(source, wx.GetDefaultPyEncoding()) try: self.m_lock.acquire() fNotify = not self.is_in_files(_filename) self.m_files[_filename] = (_time, source) finally: self.m_lock.release() _args = (_filename, ) + args + (fNotify, ) callback(*_args) class CCodeViewer(wx.Panel, CJobs, CCaptionManager): def __init__(self, *args, **kwargs): self.m_session_manager = kwargs.pop('session_manager') self.m_notify_filename = kwargs.pop('notify_filename', None) self.m_source_manager = kwargs.pop('source_manager') wx.Panel.__init__(self, *args, **kwargs) CJobs.__init__(self) self.init_jobs() self.m_async_sm = CAsyncSessionManager(self.m_session_manager, self) self.m_history = [] self.m_history_index = 0 self.m_fSwitch = False self.m_swiched_original = None self.m_files = {} self.m_cur_filename = None self.m_pos_filename = None self.m_pos_lineno = None self.m_pos_event = None self.m_breakpoint_lines = {} self.m_request_number = 0 self.m_last_position_time = 0 self.m_event2Marker = {'running': MARKER_RUNNING, 'call': MARKER_CALL, 'line': MARKER_LINE, 'return': MARKER_RETURN, 'exception': MARKER_EXCEPTION} _sizerv = wx.BoxSizer(wx.VERTICAL) sizerv = wx.BoxSizer(wx.VERTICAL) _sizerv.Add(sizerv, 1, wx.EXPAND | wx.ALL, 3) self.m_caption = CCaption(self, label = CAPTION_SOURCE) sizerv.Add(self.m_caption, 0, wx.EXPAND | wx.ALL, 0) self.m_viewer = CStyledViewer(self, style = wx.TAB_TRAVERSAL, margin_command = self.on_margin_clicked) self.bind_caption(self.m_viewer) sizerv.Add(self.m_viewer, 1, wx.EXPAND | wx.ALL, 0) self.SetSizer(_sizerv) _sizerv.Fit(self) self.m_sizerv = sizerv self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) self.Bind(wx.EVT_KEY_UP, self.OnKeyReleased) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroyWindow) def OnDestroyWindow(self, event): self.shutdown_jobs() def set_cursor(self, id): self.m_viewer.SetSTCCursor([stc.STC_CURSORNORMAL, stc.STC_CURSORWAIT][id == wx.CURSOR_WAIT]) def on_margin_clicked(self, event): lineno = self.m_viewer.LineFromPosition(event.GetPosition()) + 1 self.__toggle_breakpoint(lineno) event.Skip() def get_file_lineno(self): lineno = self.m_viewer.GetCurrentLine() + 1 return (self.m_cur_filename, lineno) def toggle_breakpoint(self): lineno = self.m_viewer.GetCurrentLine() + 1 self.__toggle_breakpoint(lineno) def __toggle_breakpoint(self, lineno): try: bpl = self.m_session_manager.get_breakpoints() except rpdb2.NotAttached: return id = self.m_breakpoint_lines.get(lineno, None) if id is not None: bp = bpl.get(id, None) if (id is None) or (bp is None): self.m_async_sm.set_breakpoint(self.m_cur_filename, '', lineno, True, '') return self.m_async_sm.delete_breakpoint([id], False) def _disable(self): self.m_viewer.Disable() def _enable(self): self.m_viewer.Enable() def get_history(self, fBack): self.m_history_index = (self.m_history_index + [-1, 1][fBack]) % len(self.m_history) return self.m_history[self.m_history_index] def set_history(self, value): if value in self.m_history: self.m_history.remove(value) self.m_history.insert(0, value) self.m_history = self.m_history[:50] self.m_history_index = 0 def OnKeyPressed(self, event): if len(self.m_history) < 2: return if self.m_fSwitch == False: self.m_fSwitch = True self.m_swiched_original = self.m_cur_filename value = self.get_history(event.ShiftDown()) self.set_file(value, fNoHistory = True) def OnKeyReleased(self, event): if self.m_fSwitch == False: return if self.m_swiched_original == self.m_cur_filename: return self.set_history(self.m_cur_filename) def _clear(self): self.m_history = [] self.m_history_index = 0 self.m_fSwitch = False self.m_swiched_original = None self.m_files = {} self.m_cur_filename = None self.m_pos_filename = None self.m_pos_lineno = None self.m_pos_event = None self.m_viewer._clear() def __notify_filename(self, filename, fNew): if self.m_notify_filename is None: return if fNew: def command(event, filename = filename): self.set_file(filename) else: command = None self.m_notify_filename(filename, command) def refresh(self): if self.m_cur_filename == None: return filename = self.m_cur_filename self.m_files[self.m_cur_filename] = self.m_viewer.GetCurrentLine() + 1 self.m_cur_filename = None self.set_file(filename) def set_file(self, filename, fNoHistory = False, request_number = 0, fNotify = False, fComplain = False): if fNotify: self.__notify_filename(filename, fNew = True) if request_number == 0: self.m_request_number += 1 request_number = self.m_request_number elif request_number < self.m_request_number: return if self.m_cur_filename == filename: return try: (_filename, source) = self.m_source_manager.get_source(filename) except KeyError: self.m_source_manager.load_source(filename, self.set_file, (fNoHistory, request_number,), fComplain) return if self.m_cur_filename == _filename: return self.__notify_filename(filename, fNew = False) if self.m_cur_filename is not None: self.m_files[self.m_cur_filename] = self.m_viewer.GetCurrentLine() + 1 lineno = self.m_files.get(_filename, 1) self.m_viewer.load_source(source) self.m_viewer.EnsureVisibleEnforcePolicy(lineno - 1) self.m_viewer.GotoLine(lineno - 1) displayed_filename = _filename if not g_fUnicode: displayed_filename = rpdb2.as_string(displayed_filename, wx.GetDefaultPyEncoding()) label = CAPTION_SOURCE + ' ' + rpdb2.clip_filename(displayed_filename) self.m_caption.m_static_text.SetLabel(label) self.m_sizerv.Layout() self.m_cur_filename = _filename self.set_markers() if fNoHistory == False: self.set_history(self.m_cur_filename) def set_position(self, filename, lineno, event, request_number = 0, fNotify = False): if fNotify: self.__notify_filename(filename, fNew = True) if request_number == 0: self.m_request_number += 1 request_number = self.m_request_number elif request_number < self.m_request_number: return if self.m_cur_filename != filename: try: (_filename, source) = self.m_source_manager.get_source(filename) except KeyError: self.m_source_manager.load_source(filename, self.set_position, (lineno, event, request_number), fComplain = False) return self.__notify_filename(filename, fNew = False) if self.m_cur_filename is not None: self.m_files[self.m_cur_filename] = self.m_viewer.GetCurrentLine() + 1 self.m_viewer.load_source(source) self.m_viewer.EnsureVisibleEnforcePolicy(lineno - 1) self.m_viewer.GotoLine(lineno - 1) displayed_filename = filename if not g_fUnicode: displayed_filename = rpdb2.as_string(displayed_filename, wx.GetDefaultPyEncoding()) label = CAPTION_SOURCE + ' ' + rpdb2.clip_filename(displayed_filename) self.m_caption.m_static_text.SetLabel(label) self.m_sizerv.Layout() self.m_cur_filename = filename self.m_pos_filename = filename self.m_pos_lineno = lineno self.m_pos_event = event self.set_markers() self.set_history(self.m_cur_filename) self.m_last_position_time = time.time() def update_bp(self, event): if self.m_pos_filename is None: return fposition_timeout = time.time() - self.m_last_position_time > POSITION_TIMEOUT if event.m_action == rpdb2.CEventBreakpoint.SET and fposition_timeout: if self.m_cur_filename == event.m_bp.m_filename: lineno = event.m_bp.m_lineno self.m_viewer.EnsureVisibleEnforcePolicy(lineno - 1) self.m_viewer.GotoLine(lineno - 1) self.set_markers() def set_markers(self): for marker in MARKER_LIST: self.m_viewer.MarkerDeleteAll(marker) if self.m_pos_filename == self.m_cur_filename: self.m_viewer.MarkerAdd(self.m_pos_lineno - 1, self.m_event2Marker[self.m_pos_event]) f_current_line = False try: bpl = self.m_session_manager.get_breakpoints() except rpdb2.NotAttached: return self.m_breakpoint_lines = {} for bp in bpl.values(): if bp.m_filename != self.m_cur_filename: continue self.m_breakpoint_lines[bp.m_lineno] = bp.m_id if (self.m_pos_filename == self.m_cur_filename) and (bp.m_lineno == self.m_pos_lineno) and bp.m_fEnabled: self.m_viewer.MarkerAdd(self.m_pos_lineno - 1, MARKER_CURRENT_LINE_HIT) f_current_line = True else: marker = [MARKER_BREAKPOINT_DISABLED, MARKER_BREAKPOINT_ENABLED][bp.m_fEnabled] self.m_viewer.MarkerAdd(bp.m_lineno - 1, marker) if (self.m_pos_filename == self.m_cur_filename) and not f_current_line: self.m_viewer.MarkerAdd(self.m_pos_lineno - 1, MARKER_CURRENT_LINE) class CConsole(wx.Panel, CCaptionManager): def __init__(self, *args, **kwargs): self.m_session_manager = kwargs.pop('session_manager') self.m_exit_command = kwargs.pop('exit_command') wx.Panel.__init__(self, *args, **kwargs) # # CConsole acts as stdin and stdout so it exposes the encoding property. # if not g_fUnicode: self.encoding = wx.GetDefaultPyEncoding() else: self.encoding = 'utf-8' self.m_fcompletions_warning = False self.m_completions = None self.m_history = [''] self.m_history_index_up = 0 self.m_history_index_down = 0 self.m_history_index_errors = 0 self.m_console = rpdb2.CConsole(self.m_session_manager, stdin = self, stdout = self, fSplit = True) self.m_queue = Queue.Queue() _sizerv = wx.BoxSizer(wx.VERTICAL) sizerv = wx.BoxSizer(wx.VERTICAL) _sizerv.Add(sizerv, 1, wx.EXPAND | wx.ALL, 3) self.m_caption = CCaption(self, label = CAPTION_CONSOLE) sizerv.Add(self.m_caption, 0, wx.EXPAND | wx.ALL, 0) self.m_console_out = wx.TextCtrl(self, style = wx.TAB_TRAVERSAL | wx.TE_MULTILINE | wx.HSCROLL | wx.VSCROLL) self.m_console_out.Bind(wx.EVT_KEY_DOWN, self.OnConsoleOutKeyPressed) self.bind_caption(self.m_console_out) self.set_font(self.m_console_out) sizerv.Add(self.m_console_out, 1, wx.EXPAND | wx.ALL, 0) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.EXPAND | wx.ALL, 0) label = wx.StaticText(self, -1, LABEL_CONSOLE, style = wx.TAB_TRAVERSAL) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 0) self.m_console_in = wx.TextCtrl(self, style = wx.TE_PROCESS_ENTER) self.bind_caption(self.m_console_in) self.set_font(self.m_console_in) self.m_console_in.SetFocus() self.m_console_in.Bind(wx.EVT_CHAR, self.OnChar) self.m_console_in.Bind(wx.EVT_TEXT_ENTER, self.OnSendText) sizerh.Add(self.m_console_in, 1, wx.EXPAND | wx.ALL, 0) self.SetSizer(_sizerv) _sizerv.Fit(self) def OnConsoleOutKeyPressed(self, event): key_code = event.GetKeyCode() if key_code != wx.WXK_TAB: return forward = not event.ShiftDown() ne = wx.NavigationKeyEvent() ne.SetDirection(forward) ne.SetCurrentFocus(self.m_console_out) ne.SetEventObject(self.m_console_out) self.GetEventHandler().ProcessEvent(ne) event.Skip() def set_focus(self): self.m_console_in.SetFocus() def set_filename(self, filename): self.m_console.set_filename(filename) def set_font(self, ctrl): font = ctrl.GetFont() if wx.Platform == '__WXMSW__': face = "Courier New" point_size = 9 else: face = "Courier" point_size = font.GetPointSize() new_font = wx.Font(pointSize = point_size, family = font.GetFamily(), style = font.GetStyle(), weight = font.GetWeight(), face = face) ctrl.SetFont(new_font) def start(self): self.m_console.start() self.m_console.printer(COMPLETIONS_NOTICE) def stop(self): self.m_queue.put('exit\n') self.m_queue.put('exit\n') self.m_console.join() def write(self, _str): if not g_fUnicode: _str = rpdb2.as_string(_str, wx.GetDefaultPyEncoding()) else: _str = rpdb2.as_unicode(_str, self.encoding) sl = _str.split('\n') _str = '' for s in sl: while True: _str += '\n' + s[:81] s = s[81:] if len(s) == 0: break wx.CallAfter(self.m_console_out.write, _str[1:]) def flush(self): pass def readline(self): _str = self.m_queue.get() return _str def OnChar(self, event): key = event.GetKeyCode() if self.m_fcompletions_warning: self.m_fcompletions_warning = False if key in [ord(c) for c in COMPLETIONS_WARNING_CONFIRM_CHARS]: self.CompleteExpression(fForce = True) return if (key + ord('a') - 1) in [ord('n'), ord('N')] and event.ControlDown(): self.CompleteExpression() event.Skip() return if key in [wx.WXK_UP, wx.WXK_DOWN]: value = self.m_console_in.GetValue() _value = self.get_history(key == wx.WXK_UP, value) self.m_console_in.SetValue(_value) self.m_console_in.SetInsertionPointEnd() return event.Skip() def CompleteExpression(self, fForce = False): v = self.m_console_in.GetValue() ip = self.m_console_in.GetInsertionPoint() ce = v[:ip] completions = [] while True: c = self.m_console.complete(ce, len(completions)) if c == None: break completions.append(c) if completions == []: return d = calc_denominator(completions) nv = d + v[ip:] self.m_console_in.SetValue(nv) self.m_console_in.SetInsertionPoint(len(d)) if len(completions) == 1: return if len(completions) > COMPLETIONS_WARNING_THRESHOLD and not fForce: self.m_console_out.write(COMPLETIONS_WARNING % len(completions)) self.m_fcompletions_warning = True return if ce != '' and ce.split()[0] == 'launch': # # Go over launch completions and extract the basenames. # Add a trailing path seperator '/' to dir names completions. # _completions = [] for c in completions: p = c.split()[-1] dn, bn = os.path.split(p) if bn == '': bn = os.path.join(os.path.split(dn)[1], '') _completions.append(bn) completions = _completions if ce != '' and ce.split()[0] in ['v', 'eval', 'x', 'exec']: completions = [re.split('\W+', c)[-1] for c in completions] if completions == self.m_completions: return self.m_completions = completions out = ', '.join(completions) lines = textwrap.wrap(out, 60) text = '\n'.join(lines) + '\n' self.m_console_out.write(CONSOLE_COMPLETIONS % text) def OnSendText(self, event): self.m_completions = None value = self.m_console_in.GetValue() self.set_history(value) self.m_console_out.write(CONSOLE_PROMPT + value + '\n') self.m_console_in.Clear() if value in ['exit', 'EOF']: self.m_exit_command() return value = rpdb2.as_unicode(value, wx.GetDefaultPyEncoding()) self.m_queue.put(value + '\n') def get_history(self, fBack, value = None): if fBack: index = self.m_history_index_up else: index = self.m_history_index_down if (value is not None) and (value != self.m_history[index]): self.m_history[0] = value self.m_history_index_up = 0 self.m_history_index_errors = 0 try: if fBack: self.m_history_index_up = self.find_next_up() self.m_history_index_down = self.m_history_index_up else: self.m_history_index_down = self.find_next_down() self.m_history_index_up = self.m_history_index_down except KeyError: if self.m_history_index_errors == 3: self.m_history_index_errors += 1 return self.get_history(fBack, value) return self.m_history[self.m_history_index_up] def find_next_up(self): if self.m_history_index_up >= len(self.m_history) - 1: raise KeyError if self.m_history_index_errors >= 3: prefix = '' else: prefix = self.m_history[0] index = self.m_history_index_up current = self.m_history[index] while True: index += 1 if index >= len(self.m_history): self.m_history_index_errors += 1 raise KeyError next = self.m_history[index] if next != current and next.startswith(prefix): break if self.m_history_index_errors < 3: self.m_history_index_errors = 0 return index def find_next_down(self): if self.m_history_index_errors < 3: self.m_history_index_errors = 0 if self.m_history_index_errors >= 3: prefix = '' else: prefix = self.m_history[0] index = self.m_history_index_down current = self.m_history[index] while True: index -= 1 if index < 0: raise KeyError next = self.m_history[index] if next != current and next.startswith(prefix): return index def set_history(self, value): self.m_history[0] = '' self.m_history_index_up = 0 if value != '' and (len(self.m_history) <= 1 or value != self.m_history[1]): self.m_history.insert(1, value) self.m_history = self.m_history[:50] if self.m_history_index_down != 0: self.m_history_index_down = min(self.m_history_index_down + 1, len(self.m_history) - 1) class CThreadsViewer(wx.Panel, CCaptionManager): def __init__(self, *args, **kwargs): self.m_select_command = kwargs.pop('select_command', None) wx.Panel.__init__(self, *args, **kwargs) self.m_suppress_recursion = 0 _sizerv = wx.BoxSizer(wx.VERTICAL) sizerv = wx.BoxSizer(wx.VERTICAL) _sizerv.Add(sizerv, 1, wx.EXPAND | wx.ALL, 3) self.m_caption = CCaption(self, label = CAPTION_THREADS) sizerv.Add(self.m_caption, 0, wx.EXPAND | wx.ALL, 0) self.m_threads = CListCtrl(parent = self, style = wx.LC_REPORT | wx.LC_SINGLE_SEL) self.bind_caption(self.m_threads) self.m_threads.InsertColumn(0, HLIST_HEADER_TID + ' ') self.m_threads.InsertColumn(1, HLIST_HEADER_NAME) self.m_threads.InsertColumn(2, HLIST_HEADER_STATE) sizerv.Add(self.m_threads, 1, wx.EXPAND | wx.ALL, 0) if self.m_select_command: self.m_threads.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnThreadSelected) self.SetSizer(_sizerv) _sizerv.Fit(self) def set_cursor(self, id): cursor = wx.StockCursor(id) self.SetCursor(cursor) self.m_threads.SetCursor(cursor) def _clear(self): self.m_threads.DeleteAllItems() self.m_threads.Disable() def _disable(self): self.m_threads.Disable() def _enable(self): self.m_threads.Enable() def is_selected(self, index): return self.m_threads.IsSelected(index) def update_thread(self, thread_id, thread_name, fBroken): assert(rpdb2.is_unicode(thread_name)) index = self.m_threads.FindItemData(-1, thread_id) if index < 0: return -1 if not g_fUnicode: thread_name = rpdb2.as_string(thread_name, wx.GetDefaultPyEncoding()) self.m_threads.SetStringItem(index, 1, thread_name) self.m_threads.SetStringItem(index, 2, [rpdb2.STATE_RUNNING, rpdb2.STR_STATE_BROKEN][fBroken]) return index def update_threads_list(self, current_thread, threads_list): if self.m_suppress_recursion > 0: self.m_suppress_recursion -= 1 return self.m_threads.DeleteAllItems() j = None for i, s in enumerate(threads_list): tid = s[rpdb2.DICT_KEY_TID] name = s[rpdb2.DICT_KEY_NAME] if not g_fUnicode: name = rpdb2.as_string(name, wx.GetDefaultPyEncoding()) fBroken = s[rpdb2.DICT_KEY_BROKEN] index = self.m_threads.InsertStringItem(sys.maxint, repr(tid)) self.m_threads.SetStringItem(index, 1, name) self.m_threads.SetStringItem(index, 2, [rpdb2.STATE_RUNNING, rpdb2.STR_STATE_BROKEN][fBroken]) self.m_threads.SetItemData(index, tid) if tid == current_thread: j = i self.m_threads.set_columns_width() if j is not None: self.m_suppress_recursion += 1 self.m_threads.Select(j) def OnThreadSelected(self, event): if self.m_suppress_recursion == 0: self.m_suppress_recursion += 1 index = event.m_itemIndex tid = self.m_threads.GetItemData(index) self.m_select_command(tid) else: self.m_suppress_recursion -= 1 event.Skip() class CNamespacePanel(wx.Panel, CJobs): def __init__(self, *args, **kwargs): self.m_session_manager = kwargs.pop('session_manager') wx.Panel.__init__(self, *args, **kwargs) CJobs.__init__(self) self.init_jobs() self.m_async_sm = CAsyncSessionManager(self.m_session_manager, self) self.m_lock = threading.RLock() self.m_jobs = [] self.m_n_workers = 0 self.m_filter_level = 0 self.m_key = None sizerv = wx.BoxSizer(wx.VERTICAL) self.m_tree = wx.gizmos.TreeListCtrl(self, -1, style = wx.TR_HIDE_ROOT | wx.TR_DEFAULT_STYLE | wx.TR_FULL_ROW_HIGHLIGHT | wx.NO_BORDER) self.m_tree.AddColumn(TLC_HEADER_NAME) self.m_tree.AddColumn(TLC_HEADER_TYPE) self.m_tree.AddColumn(TLC_HEADER_REPR) self.m_tree.SetColumnWidth(2, 800) self.m_tree.SetMainColumn(0) self.m_tree.SetLineSpacing(0) self.m_tree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding) self.m_tree.Bind(wx.EVT_TREE_ITEM_COLLAPSING, self.OnItemCollapsing) self.m_tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated) try: self.m_tree.Bind(wx.EVT_TREE_ITEM_GETTOOLTIP, self.OnItemToolTip) except: pass self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroyWindow) sizerv.Add(self.m_tree, flag = wx.GROW, proportion = 1) self.SetSizer(sizerv) sizerv.Fit(self) def OnDestroyWindow(self, event): self.shutdown_jobs() def _clear(self): self.m_tree.DeleteAllItems() def set_filter(self, filter_level): self.m_filter_level = filter_level def bind_caption(self, caption_manager): w = self.m_tree.GetMainWindow() caption_manager.bind_caption(w) def OnItemActivated(self, event): item = event.GetItem() (expr, is_valid) = self.m_tree.GetPyData(item) if expr in [STR_NAMESPACE_LOADING, STR_NAMESPACE_DEADLOCK, rpdb2.STR_MAX_NAMESPACE_WARNING_TITLE]: return if is_valid: default_value = self.m_tree.GetItemText(item, 2)[1:] else: default_value = '' expr_dialog = CExpressionDialog(self, default_value) pos = self.GetPositionTuple() expr_dialog.SetPosition((pos[0] + 50, pos[1] + 50)) r = expr_dialog.ShowModal() if r != wx.ID_OK: expr_dialog.Destroy() return _expr = expr_dialog.get_expression() expr_dialog.Destroy() _suite = "%s = %s" % (expr, _expr) self.m_async_sm.with_callback(self.callback_execute).execute(_suite) def callback_execute(self, r, exc_info): (t, v, tb) = exc_info if t != None: rpdb2.print_exception(t, b, tb) return (warning, error) = r if error != '': dlg = wx.MessageDialog(self, error, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() if not warning in g_ignored_warnings: dlg = wx.MessageDialog(self, MSG_WARNING_TEMPLATE % (warning, ), MSG_WARNING_TITLE, wx.OK | wx.CANCEL | wx.YES_DEFAULT | wx.ICON_WARNING) res = dlg.ShowModal() dlg.Destroy() if res == wx.ID_CANCEL: g_ignored_warnings[warning] = True def OnItemToolTip(self, event): item = event.GetItem() tt = self.m_tree.GetItemText(item, 2)[1:] event.SetToolTip(tt) def OnItemCollapsing(self, event): item = event.GetItem() event.Skip() def GetChildrenCount(self, item): n = self.m_tree.GetChildrenCount(item) if n != 1: return n child = self.get_children(item)[0] (expr, is_valid) = self.m_tree.GetPyData(child) if expr in [STR_NAMESPACE_LOADING, STR_NAMESPACE_DEADLOCK]: return 0 return 1 def expand_item(self, item, _map, froot = False, fskip_expansion_check = False): if not self.m_tree.ItemHasChildren(item): return if not froot and not fskip_expansion_check and self.m_tree.IsExpanded(item): return if self.GetChildrenCount(item) > 0: return (expr, is_valid) = self.m_tree.GetPyData(item) l = [e for e in _map if e.get(rpdb2.DICT_KEY_EXPR, None) == expr] if l == []: return None _r = l[0] if _r is None: return if rpdb2.DICT_KEY_ERROR in _r: return if _r[rpdb2.DICT_KEY_N_SUBNODES] == 0: self.m_tree.SetItemHasChildren(item, False) return # # Create a list of the subitems. # The list is indexed by name or directory key. # In case of a list, no sorting is needed. # snl = _r[rpdb2.DICT_KEY_SUBNODES] for r in snl: if g_fUnicode: _name = r[rpdb2.DICT_KEY_NAME] _type = r[rpdb2.DICT_KEY_TYPE] _repr = r[rpdb2.DICT_KEY_REPR] else: _name = rpdb2.as_string(r[rpdb2.DICT_KEY_NAME], wx.GetDefaultPyEncoding()) _type = rpdb2.as_string(r[rpdb2.DICT_KEY_TYPE], wx.GetDefaultPyEncoding()) _repr = rpdb2.as_string(r[rpdb2.DICT_KEY_REPR], wx.GetDefaultPyEncoding()) identation = '' #identation = ['', ' '][os.name == rpdb2.POSIX and r[rpdb2.DICT_KEY_N_SUBNODES] == 0] child = self.m_tree.AppendItem(item, identation + _name) self.m_tree.SetItemText(child, ' ' + _repr, 2) self.m_tree.SetItemText(child, ' ' + _type, 1) self.m_tree.SetItemPyData(child, (r[rpdb2.DICT_KEY_EXPR], r[rpdb2.DICT_KEY_IS_VALID])) self.m_tree.SetItemHasChildren(child, (r[rpdb2.DICT_KEY_N_SUBNODES] > 0)) self.m_tree.Expand(item) def OnItemExpanding(self, event): item = event.GetItem() if not self.m_tree.ItemHasChildren(item): event.Skip() return if self.GetChildrenCount(item) > 0: event.Skip() self.m_tree.Refresh(); return self.m_tree.DeleteChildren(item) child = self.m_tree.AppendItem(item, STR_NAMESPACE_LOADING) self.m_tree.SetItemText(child, ' ' + STR_NAMESPACE_LOADING, 2) self.m_tree.SetItemText(child, ' ' + STR_NAMESPACE_LOADING, 1) self.m_tree.SetItemPyData(child, (STR_NAMESPACE_LOADING, False)) (expr, is_valid) = self.m_tree.GetPyData(item) f = lambda r, exc_info: self.callback_ns(r, exc_info, expr) self.m_async_sm.with_callback(f).get_namespace([(expr, True)], self.m_filter_level) event.Skip() def callback_ns(self, r, exc_info, expr): (t, v, tb) = exc_info item = self.find_item(expr) if item == None: return self.m_tree.DeleteChildren(item) if t != None or r is None or len(r) == 0: child = self.m_tree.AppendItem(item, STR_NAMESPACE_DEADLOCK) self.m_tree.SetItemText(child, ' ' + STR_NAMESPACE_DEADLOCK, 2) self.m_tree.SetItemText(child, ' ' + STR_NAMESPACE_DEADLOCK, 1) self.m_tree.SetItemPyData(child, (STR_NAMESPACE_DEADLOCK, False)) self.m_tree.Expand(item) return self.expand_item(item, r, False, True) self.m_tree.Refresh() def find_item(self, expr): item = self.m_tree.GetRootItem() while item: (expr2, is_valid) = self.m_tree.GetPyData(item) if expr2 == expr: return item item = self.m_tree.GetNext(item) return None def get_children(self, item): (child, cookie) = self.m_tree.GetFirstChild(item) cl = [] while child and child.IsOk(): cl.append(child) (child, cookie) = self.m_tree.GetNextChild(item, cookie) return cl def get_expression_list(self): if self.m_tree.GetCount() == 0: return None item = self.m_tree.GetRootItem() s = [item] el = [] while len(s) > 0: item = s.pop(0) (expr, is_valid) = self.m_tree.GetPyData(item) fExpand = self.m_tree.IsExpanded(item) and self.GetChildrenCount(item) > 0 if not fExpand: continue el.append((expr, True)) items = self.get_children(item) s = items + s return el def update_namespace(self, key, el): old_key = self.m_key old_el = self.get_expression_list() if key == old_key: el = old_el self.m_key = key if el is None: el = [(self.get_root_expr(), True)] self.post(el, self.m_filter_level) return (old_key, old_el) def post(self, el, filter_level): self.m_jobs.insert(0, (el, filter_level)) if self.m_n_workers == 0: self.job_post(self.job_update_namespace, ()) def job_update_namespace(self): while len(self.m_jobs) > 0: self.m_lock.acquire() self.m_n_workers += 1 self.m_lock.release() try: del self.m_jobs[1:] (el, filter_level) = self.m_jobs.pop() rl = self.m_session_manager.get_namespace(el, filter_level) wx.CallAfter(self.do_update_namespace, rl) except (rpdb2.ThreadDone, rpdb2.NoThreads): wx.CallAfter(self.m_tree.DeleteAllItems) except: rpdb2.print_debug_exception() self.m_lock.acquire() self.m_n_workers -= 1 self.m_lock.release() def do_update_namespace(self, rl): self.m_tree.DeleteAllItems() root = self.m_tree.AddRoot('root') self.m_tree.SetItemPyData(root, (self.get_root_expr(), False)) self.m_tree.SetItemHasChildren(root, True) s = [root] while len(s) > 0: item = s.pop(0) self.expand_item(item, rl, item is root) items = self.get_children(item) s = items + s self.m_tree.Refresh() def get_root_expr(self): """ Over-ride in derived classes """ pass class CLocals(CNamespacePanel): def get_root_expr(self): return rpdb2.as_unicode('locals()') class CGlobals(CNamespacePanel): def get_root_expr(self): return rpdb2.as_unicode('globals()') class CException(CNamespacePanel): def get_root_expr(self): return rpdb2.RPDB_EXEC_INFO class CNamespaceViewer(wx.Panel, CCaptionManager): def __init__(self, *args, **kwargs): self.m_session_manager = kwargs.pop('session_manager') self.m_key_map = {} wx.Panel.__init__(self, *args, **kwargs) _sizerv = wx.BoxSizer(wx.VERTICAL) sizerv = wx.BoxSizer(wx.VERTICAL) _sizerv.Add(sizerv, 1, wx.EXPAND | wx.ALL, 3) self.m_caption = CCaption(self, label = CAPTION_NAMESPACE) sizerv.Add(self.m_caption, 0, wx.EXPAND | wx.ALL, 0) self.m_notebook = wx.Notebook(self) self.m_locals = CLocals(self.m_notebook, session_manager = self.m_session_manager) self.m_notebook.AddPage(self.m_locals, "Locals") self.m_globals = CGlobals(self.m_notebook, session_manager = self.m_session_manager) self.m_notebook.AddPage(self.m_globals, "Globals") self.m_exception = CException(self.m_notebook, session_manager = self.m_session_manager) self.m_notebook.AddPage(self.m_exception, "Exception") self.bind_caption(self.m_notebook) self.m_locals.bind_caption(self) self.m_globals.bind_caption(self) self.m_exception.bind_caption(self) sizerv.Add(self.m_notebook, 1, wx.EXPAND | wx.ALL, 0) self.SetSizer(_sizerv) _sizerv.Fit(self) def _clear(self): self.m_locals._clear() self.m_globals._clear() self.m_exception._clear() def _disable(self): self.m_notebook.Disable() self.m_locals.Disable() self.m_globals.Disable() self.m_exception.Disable() def _enable(self): self.m_notebook.Enable() self.m_locals.Enable() self.m_globals.Enable() self.m_exception.Enable() def set_filter(self, filter_level): self.m_locals.set_filter(filter_level) self.m_globals.set_filter(filter_level) self.m_exception.set_filter(filter_level) def get_local_key(self, _stack): frame_index = self.m_session_manager.get_frame_index() c = _stack.get(rpdb2.DICT_KEY_CODE_LIST, []) key = c[-(1 + frame_index)] return key def get_global_key(self, _stack): frame_index = self.m_session_manager.get_frame_index() s = _stack.get(rpdb2.DICT_KEY_STACK, []) key = s[-(1 + frame_index)][0] return key def update_namespace(self, _stack): try: key = self.get_local_key(_stack) el = self.m_key_map.get(key, None) (key0, el0) = self.m_locals.update_namespace(key, el) self.m_key_map[key0] = el0 key = self.get_global_key(_stack) el = self.m_key_map.get(key, None) (key1, el1) = self.m_globals.update_namespace(key, el) self.m_key_map[key1] = el1 key = 'exception' el = self.m_key_map.get(key, None) (key1, el1) = self.m_exception.update_namespace(key, el) self.m_key_map[key] = el1 except rpdb2.NotAttached: return class CStackViewer(wx.Panel, CCaptionManager): def __init__(self, *args, **kwargs): self.m_select_command = kwargs.pop('select_command', None) wx.Panel.__init__(self, *args, **kwargs) self.m_suppress_recursion = 0 _sizerv = wx.BoxSizer(wx.VERTICAL) sizerv = wx.BoxSizer(wx.VERTICAL) _sizerv.Add(sizerv, 1, wx.EXPAND | wx.ALL, 3) self.m_caption = CCaption(self, label = CAPTION_STACK) sizerv.Add(self.m_caption, 0, wx.EXPAND | wx.ALL, 0) self.m_stack = CListCtrl(parent = self, style = wx.LC_REPORT | wx.LC_SINGLE_SEL) self.bind_caption(self.m_stack) self.m_stack.InsertColumn(0, HLIST_HEADER_FRAME) self.m_stack.InsertColumn(1, HLIST_HEADER_FILENAME) self.m_stack.InsertColumn(2, HLIST_HEADER_LINENO) self.m_stack.InsertColumn(3, HLIST_HEADER_FUNCTION) self.m_stack.InsertColumn(4, HLIST_HEADER_PATH) sizerv.Add(self.m_stack, 1, wx.EXPAND | wx.ALL, 0) if self.m_select_command: self.m_stack.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnFrameSelected) self.SetSizer(_sizerv) _sizerv.Fit(self) def set_cursor(self, id): cursor = wx.StockCursor(id) self.SetCursor(cursor) self.m_stack.SetCursor(cursor) def _clear(self): self.m_stack.DeleteAllItems() def _disable(self): self.m_stack.Disable() def _enable(self): self.m_stack.Enable() def is_selected(self, index): return self.m_stack.IsSelected(index) def update_stack_list(self, st): self.m_stack.DeleteAllItems() s = st.get(rpdb2.DICT_KEY_STACK, []) i = 0 while i < len(s): e = s[-(1 + i)] filename = e[0] lineno = e[1] function = e[2] if not g_fUnicode: filename = rpdb2.as_string(filename, wx.GetDefaultPyEncoding()) function = rpdb2.as_string(function, wx.GetDefaultPyEncoding()) index = self.m_stack.InsertStringItem(sys.maxint, repr(i)) self.m_stack.SetStringItem(index, 1, os.path.basename(filename)) self.m_stack.SetStringItem(index, 2, repr(lineno)) self.m_stack.SetStringItem(index, 3, function) self.m_stack.SetStringItem(index, 4, os.path.dirname(filename)) self.m_stack.SetItemData(index, i) i += 1 self.m_stack.set_columns_width() self.m_suppress_recursion += 1 self.m_stack.Select(0) def select_frame(self, index): if self.m_suppress_recursion > 0: self.m_suppress_recursion -= 1 return if (index < 0) or (index > self.m_stack.GetItemCount()): return if self.m_stack.IsSelected(index): return self.m_suppress_recursion += 1 self.m_stack.Select(index) def OnFrameSelected(self, event): if self.m_suppress_recursion == 0: self.m_suppress_recursion += 1 self.m_select_command(event) else: self.m_suppress_recursion -= 1 event.Skip() class CHTMLDialog(wx.Dialog): def __init__(self, parent, title, text): wx.Dialog.__init__(self, parent, -1, title) sizerv = wx.BoxSizer(wx.VERTICAL) self.m_html = wx.html.HtmlWindow(self, -1, size = (600, -1)) sizerv.Add(self.m_html, 0, wx.ALIGN_CENTRE | wx.ALL, 5) if "gtk2" in wx.PlatformInfo: self.m_html.SetStandardFonts() self.m_html.SetPage(self.get_html_text(text)) ir = self.m_html.GetInternalRepresentation() self.m_html.SetSize((ir.GetWidth() + 25, min(500, ir.GetHeight() + 25))) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_CENTRE | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.SetDefault() btnsizer.AddButton(self.m_ok) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) self.CentreOnParent(wx.BOTH) def get_html_text(self, text): tl = text.split('\n') t = '
'.join(tl) return ABOUT_HTML_PREFIX + t + ABOUT_HTML_SUFFIX class CListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): def __init__(self, *args, **kwargs): wx.ListCtrl.__init__(self, *args, **kwargs) listmix.ListCtrlAutoWidthMixin.__init__(self) def set_columns_width(self): n = self.GetColumnCount() for i in range(0, n - 1): self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) if wx.Platform != '__WXMSW__': a = [self.GetColumnWidth(i) for i in range(0, n - 1)] for i in range(0, n - 1): self.SetColumnWidth(i, wx.LIST_AUTOSIZE) b = [self.GetColumnWidth(i) for i in range(0, n - 1)] c = [max(i) for i in zip(a, b)] for i in range(0, n - 1): self.SetColumnWidth(i, c[i]) self.resizeLastColumn(50) class CAttachDialog(wx.Dialog, CJobs): def __init__(self, parent, session_manager): wx.Dialog.__init__(self, parent, -1, DLG_ATTACH_TITLE) CJobs.__init__(self) self.init_jobs() self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.m_session_manager = session_manager self.m_async_sm = CAsyncSessionManager(self.m_session_manager, self) self.m_server_list = None self.m_errors = {} self.m_index = None sizerv = wx.BoxSizer(wx.VERTICAL) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_ATTACH_HOST) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) host = self.m_session_manager.get_host() self.m_entry_host = wx.TextCtrl(self, value = host, size = (200, -1)) self.m_entry_host.SetFocus() sizerh.Add(self.m_entry_host, 0, wx.ALIGN_CENTRE | wx.ALL, 5) btn = wx.Button(self, label = BUTTON_ATTACH_REFRESH) self.Bind(wx.EVT_BUTTON, self.do_refresh, btn) btn.SetDefault() sizerh.Add(btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5) self.m_listbox_scripts = CListCtrl(parent = self, style = wx.LC_REPORT | wx.LC_SINGLE_SEL, size = (-1, 300)) self.m_listbox_scripts.InsertColumn(0, HLIST_HEADER_PID + ' ') self.m_listbox_scripts.InsertColumn(1, HLIST_HEADER_FILENAME) self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.m_listbox_scripts) self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.m_listbox_scripts) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.m_listbox_scripts) sizerv.Add(self.m_listbox_scripts, 0, wx.EXPAND | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.Disable() btnsizer.AddButton(self.m_ok) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) wx.CallAfter(self.init2) def init2(self): pwd = self.m_session_manager.get_password() if pwd is not None: self.do_refresh() return pwd_dialog = CPwdDialog(self, pwd) pos = self.GetPositionTuple() pwd_dialog.SetPosition((pos[0] + 50, pos[1] + 50)) r = pwd_dialog.ShowModal() if r != wx.ID_OK: pwd_dialog.Destroy() self.Close() return pwd = pwd_dialog.get_password() pwd_dialog.Destroy() try: self.m_session_manager.set_password(pwd) except rpdb2.AlreadyAttached: assert(0) self.Close() return self.do_refresh() def set_cursor(self, id): cursor = wx.StockCursor(id) self.SetCursor(cursor) self.m_listbox_scripts.SetCursor(cursor) def OnCloseWindow(self, event): self.shutdown_jobs() self.Destroy() def get_server(self): return self.m_server_list[self.m_index] def do_refresh(self, event = None): host = self.m_entry_host.GetValue() if host == '': host = 'localhost' host = rpdb2.as_unicode(host, wx.GetDefaultPyEncoding()) f = lambda r, exc_info: self.callback_sethost(r, exc_info, host) self.m_async_sm.with_callback(f).set_host(host) def callback_sethost(self, r, exc_info, host): (t, v, tb) = exc_info if t == socket.gaierror: dlg = wx.MessageDialog(self, rpdb2.MSG_ERROR_HOST_TEXT % (host, v), MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() host = self.m_session_manager.get_host() self.m_entry_host.SetValue(host) return elif t != None: self.m_session_manager.report_exception(t, v, tb) return self.m_async_sm.with_callback(self.update_body).calc_server_list() def update_body(self, r, exc_info): (t, v, tb) = exc_info if t != None: if t == rpdb2.FirewallBlock: dlg = wx.MessageDialog(self, rpdb2.STR_FIREWALL_BLOCK, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() self.m_session_manager.report_exception(t, v, tb) return (self.m_server_list, self.m_errors) = r if len(self.m_errors) > 0: for k, el in self.m_errors.items(): if k in [rpdb2.AuthenticationBadData, rpdb2.AuthenticationFailure]: self.report_attach_warning(rpdb2.STR_ACCESS_DENIED) elif k == rpdb2.EncryptionNotSupported: self.report_attach_warning(rpdb2.STR_DEBUGGEE_NO_ENCRYPTION) elif k == rpdb2.EncryptionExpected: self.report_attach_warning(rpdb2.STR_ENCRYPTION_EXPECTED) elif k == rpdb2.BadVersion: for (t, v, tb) in el: self.report_attach_warning(rpdb2.STR_BAD_VERSION % {'value': v}) self.m_ok.Disable() host = self.m_session_manager.get_host() self.m_entry_host.SetValue(host) self.m_listbox_scripts.DeleteAllItems() for i, s in enumerate(self.m_server_list): index = self.m_listbox_scripts.InsertStringItem(sys.maxint, repr(s.m_pid)) filename = s.m_filename if not g_fUnicode: filename = rpdb2.as_string(filename, wx.GetDefaultPyEncoding()) self.m_listbox_scripts.SetStringItem(index, 1, filename) self.m_listbox_scripts.SetItemData(index, i) self.m_listbox_scripts.set_columns_width() def report_attach_warning(self, warning): dlg = wx.MessageDialog(self, warning, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() def OnItemSelected(self, event): self.m_index = event.m_itemIndex self.m_ok.Enable() event.Skip() def OnItemDeselected(self, event): if self.m_listbox_scripts.GetSelectedItemCount() == 0: self.m_ok.Disable() event.Skip() def OnItemActivated(self, event): self.m_index = event.m_itemIndex self.EndModal(wx.ID_OK) class CExpressionDialog(wx.Dialog): def __init__(self, parent, default_value): wx.Dialog.__init__(self, parent, -1, DLG_EXPR_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) label = wx.StaticText(self, -1, STATIC_EXPR) sizerv.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_EXPR) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) if not g_fUnicode: default_value = rpdb2.as_string(default_value, wx.GetDefaultPyEncoding()) self.m_entry_expr = wx.TextCtrl(self, value = default_value, size = (200, -1)) self.m_entry_expr.SetFocus() self.Bind(wx.EVT_TEXT, self.OnText, self.m_entry_expr) sizerh.Add(self.m_entry_expr, 0, wx.ALIGN_CENTRE | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.SetDefault() self.m_ok.Disable() btnsizer.AddButton(self.m_ok) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) def OnText(self, event): if event.GetString() == '': self.m_ok.Disable() else: self.m_ok.Enable() event.Skip() def get_expression(self): expr = self.m_entry_expr.GetValue() expr = rpdb2.as_unicode(expr, wx.GetDefaultPyEncoding()) return expr class CEncodingDialog(wx.Dialog): def __init__(self, parent, current_encoding, current_fraw): wx.Dialog.__init__(self, parent, -1, DLG_ENCODING_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) label = wx.StaticText(self, -1, STATIC_ENCODING, size = (300, -1)) try: label.Wrap(300) except: label.SetLabel(STATIC_ENCODING_SPLIT) sizerv.Add(label, 1, wx.ALIGN_LEFT | wx.ALL, 5) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_ENCODING) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) encoding = [current_encoding, ''][current_encoding is None] if not g_fUnicode: encoding = rpdb2.as_string(encoding, wx.GetDefaultPyEncoding()) self.m_entry_encoding = wx.TextCtrl(self, value = encoding, size = (200, -1)) self.m_entry_encoding.SetFocus() self.Bind(wx.EVT_TEXT, self.OnText, self.m_entry_encoding) sizerh.Add(self.m_entry_encoding, 0, wx.ALIGN_CENTRE | wx.ALL, 5) self.m_cb = wx.CheckBox(self, -1, CHECKBOX_ENCODING) self.m_cb.SetValue(current_fraw) sizerv.Add(self.m_cb, 0, wx.ALIGN_LEFT | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.SetDefault() self.Bind(wx.EVT_BUTTON, self.do_ok, self.m_ok) if encoding == '': self.m_ok.Disable() btnsizer.AddButton(self.m_ok) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) def OnText(self, event): if event.GetString() == '': self.m_ok.Disable() else: self.m_ok.Enable() event.Skip() def get_encoding(self): encoding = self.m_entry_encoding.GetValue() encoding = rpdb2.as_unicode(encoding, wx.GetDefaultPyEncoding()) return encoding, self.m_cb.GetValue() def do_validate(self): encoding, fraw = self.get_encoding() if encoding == rpdb2.ENCODING_AUTO: return True try: codecs.lookup(encoding) return True except: pass dlg = wx.MessageDialog(self, rpdb2.STR_ENCODING_BAD, MSG_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() return True def do_ok(self, event): f = self.do_validate() if not f: return event.Skip() class CSynchronicityDialog(wx.Dialog): def __init__(self, parent, current_fsynchronicity): wx.Dialog.__init__(self, parent, -1, DLG_SYNCHRONICITY_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) label = wx.StaticText(self, -1, STATIC_SYNCHRONICITY, size = (300, -1)) try: label.Wrap(300) except: label.SetLabel(STATIC_SYNCHRONICITY_SPLIT) sizerv.Add(label, 1, wx.ALIGN_LEFT | wx.ALL, 5) self.m_cb = wx.CheckBox(self, -1, CHECKBOX_SYNCHRONICITY) self.m_cb.SetValue(current_fsynchronicity) sizerv.Add(self.m_cb, 0, wx.ALIGN_LEFT | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) btn = wx.Button(self, wx.ID_OK) btn.SetDefault() btnsizer.AddButton(btn) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) def get_synchronicity(self): return self.m_cb.GetValue() class CPwdDialog(wx.Dialog): def __init__(self, parent, current_password): wx.Dialog.__init__(self, parent, -1, DLG_PWD_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) label = wx.StaticText(self, -1, STATIC_PWD, size = (300, -1)) try: label.Wrap(300) except: label.SetLabel(STATIC_PWD_SPLIT) sizerv.Add(label, 1, wx.ALIGN_LEFT | wx.ALL, 5) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_PWD) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) pwd = [current_password, ''][current_password is None] if not g_fUnicode: pwd = rpdb2.as_string(pwd, wx.GetDefaultPyEncoding()) self.m_entry_pwd = wx.TextCtrl(self, value = pwd, size = (200, -1)) self.m_entry_pwd.SetFocus() self.Bind(wx.EVT_TEXT, self.OnText, self.m_entry_pwd) sizerh.Add(self.m_entry_pwd, 0, wx.ALIGN_CENTRE | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.SetDefault() self.Bind(wx.EVT_BUTTON, self.do_ok, self.m_ok) if pwd == '': self.m_ok.Disable() btnsizer.AddButton(self.m_ok) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) def OnText(self, event): if event.GetString() == '': self.m_ok.Disable() else: self.m_ok.Enable() event.Skip() def get_password(self): pwd = self.m_entry_pwd.GetValue() pwd = rpdb2.as_unicode(pwd, wx.GetDefaultPyEncoding()) return pwd def do_validate(self): if rpdb2.is_valid_pwd(self.get_password()): return True dlg = wx.MessageDialog(self, rpdb2.STR_PASSWORD_BAD, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return False def do_ok(self, event): f = self.do_validate() if not f: return event.Skip() class COpenDialog(wx.Dialog): def __init__(self, parent, fLocal): wx.Dialog.__init__(self, parent, -1, DLG_OPEN_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) label = wx.StaticText(self, -1, STATIC_OPEN) sizerv.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_OPEN) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) self.m_entry = wx.TextCtrl(self, size = (200, -1)) self.m_entry.SetFocus() self.Bind(wx.EVT_TEXT, self.OnText, self.m_entry) sizerh.Add(self.m_entry, 0, wx.ALIGN_CENTRE | wx.ALL, 5) if fLocal: btn = wx.Button(self, label = BUTTON_LAUNCH_BROWSE) self.Bind(wx.EVT_BUTTON, self.do_browse, btn) sizerh.Add(btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.m_ok = wx.Button(self, wx.ID_OK) self.m_ok.Disable() self.m_ok.SetDefault() btnsizer.AddButton(self.m_ok) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() self.SetSizer(sizerv) sizerv.Fit(self) def OnText(self, event): if event.GetString() == '': self.m_ok.Disable() else: self.m_ok.Enable() event.Skip() def do_browse(self, event = None): command_line = self.m_entry.GetValue() (_path, filename, args) = rpdb2.split_command_line_path_filename_args(command_line) _abs_path = os.path.abspath(_path) dlg = wx.FileDialog(self, defaultDir = _abs_path, defaultFile = filename, wildcard = WINPDB_WILDCARD, style = wx.OPEN | wx.CHANGE_DIR) r = dlg.ShowModal() if r == wx.ID_OK: path = dlg.GetPaths()[0] abs_path = os.path.abspath(path) if (' ' in abs_path): abs_path = '"' + abs_path + '"' else: abs_path = command_line dlg.Destroy() self.m_entry.SetValue(abs_path) def get_file_name(self): filename = self.m_entry.GetValue() filename = rpdb2.as_unicode(filename, wx.GetDefaultPyEncoding()) return filename class CLaunchDialog(wx.Dialog): def __init__(self, parent, fchdir = True, command_line = ''): wx.Dialog.__init__(self, parent, -1, DLG_LAUNCH_TITLE) sizerv = wx.BoxSizer(wx.VERTICAL) sizerh = wx.BoxSizer(wx.HORIZONTAL) sizerv.Add(sizerh, 0, wx.ALIGN_CENTRE | wx.ALL, 5) label = wx.StaticText(self, -1, LABEL_LAUNCH_COMMAND_LINE) sizerh.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5) if not g_fUnicode: command_line = rpdb2.as_string(command_line, wx.GetDefaultPyEncoding()) self.m_entry_commandline = wx.TextCtrl(self, value = command_line, size = (200, -1)) self.m_entry_commandline.SetFocus() self.Bind(wx.EVT_TEXT, self.OnText, self.m_entry_commandline) sizerh.Add(self.m_entry_commandline, 0, wx.ALIGN_CENTRE | wx.ALL, 5) btn = wx.Button(self, label = BUTTON_LAUNCH_BROWSE) self.Bind(wx.EVT_BUTTON, self.do_browse, btn) sizerh.Add(btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5) self.m_cb = wx.CheckBox(self, -1, CHECKBOX_LAUNCH) self.m_cb.SetValue(fchdir) sizerv.Add(self.m_cb, 0, wx.ALIGN_LEFT | wx.ALL, 5) label = wx.StaticText(self, -1, STATIC_LAUNCH_ENV, size = (400, -1)) try: label.Wrap(400) except: label.SetLabel(STATIC_LAUNCH_ENV_SPLIT) sizerv.Add(label, 1, wx.ALIGN_LEFT | wx.ALL, 5) btnsizer = wx.StdDialogButtonSizer() self.m_ok = wx.Button(self, wx.ID_OK) self.Bind(wx.EVT_BUTTON, self.do_ok, self.m_ok) self.m_ok.SetDefault() btnsizer.AddButton(self.m_ok) if command_line == '': self.m_ok.Disable() btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() sizerv.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5) self.SetSizer(sizerv) sizerv.Fit(self) def OnText(self, event): if event.GetString() == '': self.m_ok.Disable() else: self.m_ok.Enable() event.Skip() def do_browse(self, event = None): command_line = self.m_entry_commandline.GetValue() (_path, filename, args) = rpdb2.split_command_line_path_filename_args(command_line) _abs_path = os.path.abspath(_path) cwd = os.getcwdu() dlg = wx.FileDialog(self, defaultDir = _abs_path, defaultFile = filename, wildcard = WINPDB_WILDCARD, style = wx.OPEN | wx.CHANGE_DIR) r = dlg.ShowModal() os.chdir(cwd) if r == wx.ID_OK: path = dlg.GetPaths()[0] abs_path = os.path.abspath(path) if (' ' in abs_path): abs_path = '"' + abs_path + '"' else: abs_path = command_line dlg.Destroy() self.m_entry_commandline.SetValue(abs_path) def do_validate(self): command_line = self.m_entry_commandline.GetValue() command_line = rpdb2.as_unicode(command_line, wx.GetDefaultPyEncoding()) (_path, filename, args) = rpdb2.split_command_line_path_filename_args(command_line) try: _filename = os.path.join(_path, filename) abs_path = rpdb2.FindFile(_filename) except IOError: dlg = wx.MessageDialog(self, MSG_ERROR_FILE_NOT_FOUND, MSG_ERROR_TITLE, wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return False if ' ' in abs_path: command_line = ('"' + abs_path + '" ' + args).strip() else: command_line = (abs_path + ' ' + args).strip() self.m_entry_commandline.SetValue(command_line) return True def do_ok(self, event): f = self.do_validate() if not f: return event.Skip() def get_command_line(self): command_line = self.m_entry_commandline.GetValue() command_line = rpdb2.as_unicode(command_line, wx.GetDefaultPyEncoding()) return (command_line, self.m_cb.GetValue()) def StartClient(command_line, fAttach, fchdir, pwd, fAllowUnencrypted, fRemote, host): sm = rpdb2.CSessionManager(pwd, fAllowUnencrypted, fRemote, host) try: app = CWinpdbApp(sm, fchdir, command_line, fAttach, fAllowUnencrypted) except SystemError: if os.name == rpdb2.POSIX: rpdb2._print(STR_X_ERROR_MSG, sys.__stderr__) sys.exit(1) raise if not 'unicode' in wx.PlatformInfo: dlg = wx.MessageDialog(None, STR_WXPYTHON_ANSI_WARNING_MSG, STR_WXPYTHON_ANSI_WARNING_TITLE, wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() app.MainLoop() sm.shutdown() def main(): if rpdb2.get_version() != "RPDB_2_3_4": rpdb2._print(STR_ERROR_INTERFACE_COMPATIBILITY % ("RPDB_2_3_4", rpdb2.get_version())) return return rpdb2.main(StartClient) def get_version(): return WINPDB_VERSION if __name__=='__main__': ret = main() # # Debuggee breaks (pauses) here # before program termination. # # You can step to debug any exit handlers. # rpdb2.setbreak() spe-0.8.4.h/_spe/plugins/winpdb/PKG-INFO0000644000175000017500000000067710743417221016560 0ustar stanistaniMetadata-Version: 1.0 Name: winpdb Version: 1.3.4 Summary: A platform independent GPL Python debugger. Home-page: http://www.winpdb.org/ Author: Nir Aides Author-email: nir@winpdb.org License: GNU GPL Description: Winpdb is a platform independent GPL Python debugger with support for multiple threads, namespace modification, embedded debugging, encrypted communication and is up to 20 times faster than pdb. Platform: any spe-0.8.4.h/_spe/plugins/winpdb/artwork/0000755000175000017500000000000011004131464017133 5ustar stanistanispe-0.8.4.h/_spe/plugins/winpdb/artwork/winpdb-icon-32.png0000644000175000017500000000321010743417221022277 0ustar stanistaniPNG  IHDR szzbKGD pHYs  tIME 6B1IDATXíklgڻqbM^v% !IIkA$H&EJ"UjU҇ZUU5VJ%Ej P(&Ɔwfm+=?g#2Rn`=pjZWIH#"ˀm׌N|r7xKW0bILvXe:[8HϼPJ}'>%6IffN[̺S-WXgϙRjϺwrDY;=N {mr"iJ8gׇ'd*ars4hmW?:E,6}sw){<"pvps i)ûG?*4Zv~eϱ# ?ONƴT}xӃWR "0<%p~8ogI%F/O]2m5Ʀ'ƮzWL,*76c\Od\SYǗ[֘n8٧P|*m·B'b;)MB*CyZ2RjGy1J lbM9Bڍza׵H"f׷8?:B6c&r\򒢻l55p@a(2w@"rY+q+%Mߟ?Mρ1'QR^ nEdMRGb(o^Ltpn%Ͱ\+8(^ϊʗϡVŠ?<>JRJUa }}68+"#\*sWl m̕#Nx/8'"%Y2mC]@ՄdOO"IENDB`spe-0.8.4.h/_spe/plugins/winpdb/artwork/winpdb-icon-64.png0000644000175000017500000000742410743417221022317 0ustar stanistaniPNG  IHDR@@iqbKGD pHYs  tIME 5 zIDATxݛ{t\uKь,ȖMP^ ;W!ibRP\/JVCMJP 14`\!c,WƶlKYd-H{w;xf@:9w}g}bDD\B 6Z~R*"-yWD'aݐ.aݐ )?(@VvtqOG0)nÛbJi7IXU)5 e 4PUD?V41Lt撅jL|;o*>pH&{{:҄nI%%!9+敋e#J AeaxkO-Gib۸J`J+*o罼cړy=A*uuZ5J "r{iKnے|;mWQ\}F 9e=ӂ?R`&ZJہ+ƃ- P۪{$a7`bOvDt2<}-cN([9КZMeP~c(QQUGmc"2p0F>OT xa>&`Hg'' E$t}`H`Gҍ4SZ >>J ]~t?qdN{'eg!]5 1}4`P}# t әN}T]Mu)ZnL<0y k>(4m,8%FD= =gOǔ%/Mۙs.hg+D͞\k\/"?P7LNtpR AQpGc/6Pd/AG3No.\v,W_ |{1Mj.8p+tE2aHb(ch3z< _|KRT\L @^}u.tB îa:=8譅A/ VDnSJgH>HwurRԛIqA_D]|e`^%1ѫJNn1 "[C0ќ{DJԁLEG>M<\Igk+'wn^A-,ӌ+F4>{oP4`\0R a)F@]ƶ_be,ɰ9ܱa7Y$D P8&ֵcؽs?t&v:C'18Bxop)5klk;=" ^X$"_thS9X4P\ 6RF"dx I_~yl5>ވ~?ٹ)*Y#n]jT24 [lʎ0O9d8 >ٜHnI0w'| p--<kz^8Q@Vd_O Xϸ"?4!Ex٥OޒZMS:qsa6cJ,nn?th@fr/el*o4-fvɴȈhia~k+3$Ѳb@iȤ).-MÔ`#4lTJj˅9+ʋs9dr0EE֡| x(p8bGeRb|>| }d r#MLف<OMv,4w{"/7MA6Mv a \ imj‘,mpz/P@'tiV{牛9bό h{&_VDRJvE.?VES[OݜC$i>g"5?=\ p0xdBD6 n IsF;*L*mZUKр)ꕾA](P04RAœw׭993=0'K- /,[Ίj ^ |&˭zqLQB֒ϟS7\Pۓ|I j Uv u(΋nxX$,fY埬{dUz~C0L'S?]2;^I͈N?G Z+K~x]Wg[³a j(15k߰|u%.GJ <)+6ҏ%)|z6-r8%s}n^s׎xc=ɉ4,_tΓ|KG?=\`0h5C 7ET}2uE5p9x.HMI 7.0l1ۇ{ ,O>{D n[x]Nl`#p)b[ܲBl 5@UJ#!@VTg88*qhlTgKDRQ"`=\Ț̈́gg" A~^9 1Hj^9p TXj3K@IzL5A'u~ǜ)u=c(^^pN0k+|R`/^ Y-{<'ʼnc*[<6,x*L`]qƕRߦh ~쐠4F D7H0ǁoqb x$~>P+6i {olYJo* &A)dZE9""_~J;M2JKnRjː)ρK驆O~ ;9䯀{;Mz':@hzNB#1H\?zwsZ";g ?] P }Bt+{kG.x,9*J)}svuD_dH/'+Y)u3рiDFr-@m9V?ᔔTKIENDB`spe-0.8.4.h/_spe/plugins/winpdb/artwork/winpdb-icon.svg0000644000175000017500000003620710743417221022104 0ustar stanistani image/svg+xml spe-0.8.4.h/_spe/plugins/winpdb/artwork/winpdb-icon-16.png0000644000175000017500000000143210743417221022305 0ustar stanistaniPNG  IHDRabKGD pHYs  tIME qIDAT8˅[HQsvswr/jjx[ID RS=EыQO`H=TfDd7!1XQ7u]]o33%4/saQ7[E=QXD]1a8ug1Uo.) L4}v -`ݪDNIa B! Z7 y"*yIaiKfQf Qf(jGV*EBTD.vUyH~_z6X* Te~Cj f ]hz59tX:7 V$naha=|~@OKv-$S(,YC|UIENDB`spe-0.8.4.h/_spe/plugins/wxGlade/xml_parse.py0000644000175000017500000010316510743421035020131 0ustar stanistani# xml_parse.py: parsers used to load an app and to generate the code # from an xml file. # $Id: xml_parse.py,v 1.46 2007/08/07 12:16:44 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # # NOTE: custom tag handler interface (called by XmlWidgetBuilder) # class CustomTagHandler: # def start_elem(self, name, attrs): # pass # def end_elem(self, name): # return True -> the handler must be removed from the Stack # def char_data(self, data): # return False -> no further processing needed import os import common, edit_sizers from xml.sax import SAXException, make_parser from xml.sax.handler import ContentHandler import traceback # ALB 2005-03-10: importing the module here prevents a segfault with python 2.4 # hmmm... need to investigate this more (it seems that import of # xml.sax.expatreader should happen before something else... but what?) import xml.sax.expatreader if common.use_gui: #from wxPython import wx import wx class XmlParsingError(SAXException): """\ Custom exception to report problems during parsing """ locator = None def __init__(self, msg): if self.locator: l = self.locator msg += ' _((line: %s, column: %s))' % (l.getLineNumber(), l.getColumnNumber()) SAXException.__init__(self, msg) # end of class XmlParsingError class XmlParser(ContentHandler): """\ 'abstract' base class of the parsers used to load an app and to generate the code """ def __init__(self): self._objects = Stack() # stack of 'alive' objects self._windows = Stack() # stack of window objects (derived by wxWindow) self._sizers = Stack() # stack of sizer objects self._sizer_item = Stack() # stack of sizer items self._curr_prop = None # name of the current property self._curr_prop_val = [] # value of the current property (list into # which the various pieces of char data # collected are inserted) self._appl_started = False self.top = self._objects.top self.parser = make_parser() self.parser.setContentHandler(self) self.locator = None # document locator def parse(self, source): self.parser.parse(source) def parse_string(self, source): from cStringIO import StringIO source = StringIO(source) self.parser.parse(source) source.close() def setDocumentLocator(self, locator): self.locator = locator XmlParsingError.locator = locator def startElement(self, name, attrs): raise NotImplementedError def endElement(self, name, attrs): raise NotImplementedError def characters(self, data): raise NotImplementedError def pop(self): try: return self._objects.pop().pop() except AttributeError: return None # end of class XmlParser class XmlWidgetBuilder(XmlParser): """\ parser used to build the tree of widgets from an xml file """ def startElement(self, name, attrs): if name == 'application': # get properties of the app self._appl_started = True app = common.app_tree.app encoding = attrs.get("encoding") if encoding: try: unicode('a', encoding) except LookupError: pass else: app.encoding = encoding app.encoding_prop.set_value(encoding) path = attrs.get("path") if path: app.output_path = path app.outpath_prop.set_value(path) name = attrs.get("name") if name: app.name = name app.name_prop.toggle_active(True) app.name_prop.set_value(name) klass = attrs.get("class") if klass: app.klass = klass app.klass_prop.toggle_active(True) app.klass_prop.set_value(klass) option = attrs.get("option") if option: try: option = int(option) except ValueError: option = 0 app.codegen_opt = option app.codegen_prop.set_value(option) language = attrs.get('language') if language: app.codewriters_prop.set_str_value(language) app.set_language(language) top_win = attrs.get("top_window") if top_win: self.top_window = top_win try: use_gettext = int(attrs["use_gettext"]) except (KeyError, ValueError): use_gettext = False if use_gettext: app.use_gettext = True app.use_gettext_prop.set_value(True) try: is_template = int(attrs["is_template"]) except (KeyError, ValueError): is_template = False app.is_template = is_template try: overwrite = int(attrs['overwrite']) except (KeyError, ValueError): overwrite = False if overwrite: app.overwrite = True app.overwrite_prop.set_value(True) # ALB 2004-01-18 try: use_new_namespace = int(attrs['use_new_namespace']) except (KeyError, ValueError): use_new_namespace = False ## app.set_use_new_namespace(use_new_namespace) ## app.use_new_namespace_prop.set_value(use_new_namespace) app.set_use_old_namespace(not use_new_namespace) app.use_old_namespace_prop.set_value(not use_new_namespace) # ALB 2004-12-05 try: for_version = attrs['for_version'] app.for_version = for_version app.for_version_prop.set_str_value(for_version) except KeyError: pass return if not self._appl_started: raise XmlParsingError(_("the root of the tree must be ")) if name == 'object': # create the object and push it on the appropriate stacks XmlWidgetObject(attrs, self) else: # handling of the various properties try: # look for a custom handler to push on the stack handler = self.top().obj.get_property_handler(name) if handler: self.top().prop_handlers.push(handler) # get the top custom handler and use it if there's one handler = self.top().prop_handlers.top() if handler: handler.start_elem(name, attrs) except AttributeError: pass self._curr_prop = name def endElement(self, name): if name == 'application': self._appl_started = False if hasattr(self, 'top_window'): common.app_tree.app.top_window = self.top_window common.app_tree.app.top_win_prop.SetStringSelection( self.top_window) return if name == 'object': # remove last object from the stack obj = self.pop() if obj.klass in ('sizeritem', 'sizerslot'): return si = self._sizer_item.top() if si is not None and si.parent == obj.parent: sprop = obj.obj.sizer_properties # update the values sprop['option'].set_value(si.obj.option) sprop['flag'].set_value(si.obj.flag_str()) sprop['border'].set_value(si.obj.border) # call the setter functions obj.obj['option'][1](si.obj.option) obj.obj['flag'][1](si.obj.flag_str()) obj.obj['border'][1](si.obj.border) else: # end of a property or error # 1: set _curr_prop value data = common._encode_from_xml("".join(self._curr_prop_val)) if data: try: handler = self.top().prop_handlers.top() if not handler or handler.char_data(data): # if char_data returned False, # we don't have to call add_property self.top().add_property(self._curr_prop, data) except AttributeError: pass # 2: call custom end_elem handler try: # if there is a custom handler installed for this property, # call its end_elem function: if this returns True, remove # the handler from the Stack handler = self.top().prop_handlers.top() if handler.end_elem(name): self.top().prop_handlers.pop() except AttributeError: pass self._curr_prop = None self._curr_prop_val = [] def characters(self, data): if not data or data.isspace(): return if self._curr_prop is None: raise XmlParsingError(_("character data can be present only " \ "inside properties")) self._curr_prop_val.append(data) # end of class XmlWidgetBuilder class ProgressXmlWidgetBuilder(XmlWidgetBuilder): """\ Adds support for a progress dialog to the widget builder parser """ def __init__(self, *args, **kwds): self.input_file = kwds.get('input_file') if self.input_file: del kwds['input_file'] self.size = len(self.input_file.readlines()) self.input_file.seek(0) self.progress = wx.ProgressDialog(_("Loading..."), _("Please wait " "while loading the app"), 20) self.step = 4 self.i = 1 else: self.size = 0 self.progress = None XmlWidgetBuilder.__init__(self, *args, **kwds) def endElement(self, name): if self.progress: if name == 'application': self.progress.Destroy() else: if self.locator: where = self.locator.getLineNumber() value = int(round(where*20.0/self.size)) else: # we don't have any information, so we update the progress # bar ``randomly'' value = (self.step*self.i) % 20 self.i += 1 self.progress.Update(value) XmlWidgetBuilder.endElement(self, name) def parse(self, *args): try: XmlWidgetBuilder.parse(self, *args) finally: if self.progress: self.progress.Destroy() def parse_string(self, *args): try: XmlWidgetBuilder.parse_string(self, *args) finally: if self.progress: self.progress.Destroy() # end of class ProgressXmlWidgetBuilder class ClipboardXmlWidgetBuilder(XmlWidgetBuilder): """\ Parser used to cut&paste widgets. The differences with XmlWidgetBuilder are: - No tag in the piece of xml to parse - Fake parent, sizer and sizeritem objects to push on the three stacks: they keep info about the destination of the hierarchy of widgets (i.e. the target of the 'paste' command) - The first widget built must be hidden and shown again at the end of the operation """ def __init__(self, parent, sizer, pos, option, flag, border): XmlWidgetBuilder.__init__(self) class XmlClipboardObject: def __init__(self, **kwds): self.__dict__.update(kwds) par = XmlClipboardObject(obj=parent, parent=parent) # fake window obj if sizer is not None: # fake sizer object szr = XmlClipboardObject(obj=sizer, parent=parent) sizeritem = Sizeritem() sizeritem.option = option sizeritem.flag = flag sizeritem.border = border sizeritem.pos = pos # fake sizer item si = XmlClipboardObject(obj=sizeritem, parent=parent) # push the fake objects on the stacks self._objects.push(par); self._windows.push(par) if sizer is not None: self._objects.push(szr); self._sizers.push(szr) self._objects.push(si); self._sizer_item.push(si) self.depth_level = 0 self._appl_started = True # no application tag when parsing from the # clipboard def startElement(self, name, attrs): if name == 'object' and attrs.has_key('name'): # generate a unique name for the copy oldname = str(attrs['name']) newname = oldname i = 0 while common.app_tree.has_name(newname): if not i: newname = '%s_copy' % oldname else: newname = '%s_copy_%s' % (oldname, i) i += 1 attrs = dict(attrs) attrs['name'] = newname XmlWidgetBuilder.startElement(self, name, attrs) if name == 'object': if not self.depth_level: common.app_tree.auto_expand = False try: self.top_obj = self.top().obj except AttributeError: print _('Exception! obj: %s') % self.top_obj traceback.print_exc() self.depth_level += 1 def endElement(self, name): if name == 'object': obj = self.top() self.depth_level -= 1 if not self.depth_level: common.app_tree.auto_expand = True try: # show the first object and update its layout common.app_tree.show_widget(self.top_obj.node) self.top_obj.show_properties() common.app_tree.select_item(self.top_obj.node) except AttributeError: print _('Exception! obj: %s') % self.top_obj traceback.print_exc() XmlWidgetBuilder.endElement(self, name) # end of class ClipboardXmlWidgetBuilder class XmlWidgetObject: """\ A class to encapsulate a widget read from an xml file: its purpose is to store various widget attributes until the widget can be created """ def __init__(self, attrs, parser): # prop_handlers is a stack of custom handler functions to set # properties of this object self.prop_handlers = Stack() self.parser = parser self.in_windows, self.in_sizers = False, False try: base = attrs.get('base', None) self.klass = attrs['class'] except KeyError: raise XmlParsingError(_("'object' items must have a 'class' " \ "attribute")) if base is not None: # if base is not None, the object is a widget (or sizer), and not a # sizeritem sizer = self.parser._sizers.top() parent = self.parser._windows.top() if parent is not None: parent = self.parent = parent.obj else: self.parent = None sizeritem = self.parser._sizer_item.top() if sizeritem is not None: sizeritem = sizeritem.obj if sizer is not None: # we must check if the sizer on the top of the stack is # really the one we are looking for: to check this if sizer.parent != parent: sizer = None else: sizer = sizer.obj if hasattr(sizeritem, 'pos'): pos = sizeritem.pos else: pos = None if parent and hasattr(parent, 'virtual_sizer') and \ parent.virtual_sizer: sizer = parent.virtual_sizer sizer.node = parent.node sizeritem = Sizeritem() if pos is None: pos = sizer.get_itempos(attrs) # build the widget if pos is not None: pos = int(pos) self.obj = common.widgets_from_xml[base](attrs, parent, sizer, sizeritem, pos) try: #self.obj.klass = self.klass self.obj.set_klass(self.klass) self.obj.klass_prop.set_value(self.klass) except AttributeError: pass # push the object on the appropriate stack if isinstance(self.obj, edit_sizers.SizerBase): self.parser._sizers.push(self) self.in_sizers = True else: self.parser._windows.push(self) self.in_windows = True elif self.klass == 'sizeritem': self.obj = Sizeritem() self.parent = self.parser._windows.top().obj self.parser._sizer_item.push(self) elif self.klass == 'sizerslot': sizer = self.parser._sizers.top().obj assert sizer is not None, \ _("malformed wxg file: slots can only be inside sizers!") sizer.add_slot() self.parser._sizer_item.push(self) # push the object on the _objects stack self.parser._objects.push(self) def pop(self): if self.in_windows: return self.parser._windows.pop() elif self.in_sizers: return self.parser._sizers.pop() else: return self.parser._sizer_item.pop() def add_property(self, name, val): """\ adds a property to this widget. This method is not called if there was a custom handler for this property, and its char_data method returned False """ if name == 'pos': # sanity check, this shouldn't happen... print 'add_property pos' return try: self.obj[name][1](val) # call the setter for this property try: prop = self.obj.properties[name] prop.set_value(val) prop.toggle_active(True) except AttributeError: pass except KeyError: # unknown property for this object # issue a warning and ignore the property import sys print >> sys.stderr, _("Warning: property '%s' not supported by " \ "this object ('%s') ") % (name, self.obj) #end of class XmlWidgetObject class CodeWriter(XmlParser): """parser used to produce the source from a given xml file""" def __init__(self, writer, input, from_string=False, out_path=None, preview=False, class_names=None): # writer: object that actually writes the code XmlParser.__init__(self) self._toplevels = Stack() # toplevel objects, i.e. instances of a # custom class self.app_attrs = {} # attributes of the app (name, class, top_window) self.top_win = '' # class name of the top window of the app (if any) self.out_path = out_path # this allows to override the output path # specified in the xml file self.code_writer = writer self.preview = preview # if True, we are generating the code for the # preview # used in the CustomWidget preview code, to generate better previews # (see widgets/custom_widget/codegen.py) self.class_names = class_names if self.class_names is None: self.class_names = set() if from_string: self.parse_string(input) else: inputfile = None try: inputfile = open(input) self.parse(inputfile) finally: if inputfile: inputfile.close() def startElement(self, name, attrs_impl): attrs = {} try: encoding = self.app_attrs['encoding'] unicode('a', encoding) except (KeyError, LookupError): if name == 'application': encoding = str(attrs_impl.get('encoding', 'ISO-8859-1')) else: encoding = 'ISO-8859-1' # turn all the attribute values from unicode to str objects for attr, val in attrs_impl.items(): attrs[attr] = common._encode_from_xml(val, encoding) if name == 'application': # get the code generation options self._appl_started = True self.app_attrs = attrs try: attrs['option'] = bool(int(attrs['option'])) use_multiple_files = attrs['option'] except (KeyError, ValueError): use_multiple_files = attrs['option'] = False if self.out_path is None: try: self.out_path = attrs['path'] except KeyError: raise XmlParsingError(_("'path' attribute missing: could " "not generate code")) else: attrs['path'] = self.out_path # ALB 2004-11-01: check if the values of # use_multiple_files and out_path agree if use_multiple_files: if not os.path.isdir(self.out_path): raise IOError(_("Output path must be an existing directory" " when generating multiple files")) else: if os.path.isdir(self.out_path): raise IOError(_("Output path can't be a directory when " "generating a single file")) # initialize the writer self.code_writer.initialize(attrs) return if not self._appl_started: raise XmlParsingError(_("the root of the tree must be ")) if name == 'object': # create the CodeObject which stores info about the current widget CodeObject(attrs, self, preview=self.preview) if attrs.has_key('name') and \ attrs['name'] == self.app_attrs.get('top_window', ''): self.top_win = attrs['class'] else: # handling of the various properties try: # look for a custom handler to push on the stack w = self.top() handler = self.code_writer.get_property_handler(name, w.base) if handler: w.prop_handlers.push(handler) # get the top custom handler and use it if there's one handler = w.prop_handlers.top() if handler: handler.start_elem(name, attrs) except AttributeError: print 'ATTRIBUTE ERROR!!' traceback.print_exc() self._curr_prop = name def endElement(self, name): if name == 'application': self._appl_started = False if self.app_attrs: self.code_writer.add_app(self.app_attrs, self.top_win) # call the finalization function of the code writer self.code_writer.finalize() return if name == 'object': obj = self.pop() if obj.klass in ('sizeritem', 'sizerslot'): return # at the end of the object, we have all the information to add it # to its toplevel parent, or to generate the code for the custom # class if obj.is_toplevel and not obj.in_sizers: self.code_writer.add_class(obj) topl = self._toplevels.top() if topl: self.code_writer.add_object(topl, obj) # if the object is not a sizeritem, check whether it # belongs to some sizer (in this case, # self._sizer_item.top() doesn't return None): if so, # write the code to add it to the sizer at the top of # the stack si = self._sizer_item.top() if si is not None and si.parent == obj.parent: szr = self._sizers.top() if not szr: return self.code_writer.add_sizeritem(topl, szr, obj, si.obj.option, si.obj.flag_str(), si.obj.border) else: # end of a property or error # 1: set _curr_prop value try: encoding = self.app_attrs['encoding'] unicode('a', encoding) except (KeyError, LookupError): encoding = 'ISO-8859-1' data = common._encode_from_xml(u"".join(self._curr_prop_val), encoding) if data: handler = self.top().prop_handlers.top() if not handler or handler.char_data(data): # if char_data returned False, # we don't have to call add_property self.top().add_property(self._curr_prop, data) # 2: call custom end_elem handler try: # if there is a custom handler installed for this property, # call its end_elem function: if this returns True, remove # the handler from the stack obj = self.top() handler = obj.prop_handlers.top() if handler.end_elem(name, obj): obj.prop_handlers.pop() except AttributeError: pass self._curr_prop = None self._curr_prop_val = [] def characters(self, data): if not data or data.isspace(): return if self._curr_prop is None: raise XmlParsingError(_("character data can only appear inside " \ "properties")) self._curr_prop_val.append(data) # end of class CodeWriter class CodeObject: """\ A class to store information needed to generate the code for a given object """ def __init__(self, attrs, parser, preview=False): self.parser = parser self.in_windows = self.in_sizers = False self.is_toplevel = False # if True, the object is a toplevel one: # for window objects, this means that they are # instances of a custom class, for sizers, that # they are at the top of the hierarchy self.is_container = False # if True, the widget is a container # (frame, dialog, panel, ...) self.properties = {} # properties of the widget/sizer # prop_handlers is a stack of custom handler functions to set # properties of this object self.prop_handlers = Stack() self.preview = preview try: base = attrs.get('base', None) self.klass = attrs['class'] except KeyError: raise XmlParsingError(_("'object' items must have a 'class' " \ "attribute")) self.parser._objects.push(self) self.parent = self.parser._windows.top() # -------- added 2002-08-26 to detect container widgets -------------- if self.parent is not None: self.parent.is_container = True # -------- end added 2002-08-26 -------------------------------------- self.base = None if base is not None: # this is a ``real'' object, not a sizeritem self.name = attrs['name'] self.base = common.class_names[base] can_be_toplevel = common.toplevels.has_key(base) if (self.parent is None or self.klass != self.base) and \ can_be_toplevel: #self.base != 'CustomWidget': self.is_toplevel = True # ALB 2005-11-19: for panel objects, if the user sets a # custom class but (s)he doesn't want the code # to be generated... if int(attrs.get('no_custom_class', False)) and \ not self.preview: self.is_toplevel = False #print 'OK:', str(self) #self.in_windows = True #self.parser._windows.push(self) else: self.parser._toplevels.push(self) #------------- 2003-05-07: preview -------------------------------- elif self.preview and not can_be_toplevel and \ self.base != 'CustomWidget': # if this is a custom class, but not a toplevel one, # for the preview we have to use the "real" class # # ALB 2007-08-04: CustomWidgets handle this in a special way # (see widgets/custom_widget/codegen.py) self.klass = self.base #------------------------------------------------------------------ # temporary hack: to detect a sizer, check whether the name # of its class contains the string 'Sizer': TODO: find a # better way!! if base.find('Sizer') != -1: self.in_sizers = True if not self.parser._sizers.count(): self.is_toplevel = True else: # the sizer is a toplevel one if its parent has not a # sizer yet sz = self.parser._sizers.top() if sz.parent != self.parent: self.is_toplevel = True self.parser._sizers.push(self) else: self.parser._windows.push(self) self.in_windows = True else: # the object is a sizeritem self.obj = Sizeritem() self.obj.flag_s = '0' self.parser._sizer_item.push(self) def __str__(self): return "" % (self.name, self.base, self.klass) def add_property(self, name, value): if hasattr(self, 'obj'): # self is a sizeritem try: if name == 'flag': ## flag = 0 ## for f in value.split('|'): ## flag |= Sizeritem.flags[f.strip()] ## setattr(self.obj, name, flag) self.obj.flag_s = value.strip() else: setattr(self.obj, name, int(value)) except: raise XmlParsingError(_("property '%s' not supported by " \ "'%s' objects") % (name, self.klass)) self.properties[name] = value def pop(self): if self.is_toplevel and not self.in_sizers: self.parser._toplevels.pop() if self.in_windows: return self.parser._windows.pop() elif self.in_sizers: return self.parser._sizers.pop() else: return self.parser._sizer_item.pop() # end of class CodeObject class Stack: def __init__(self): self._repr = [] def push(self, elem): self._repr.append(elem) def pop(self): try: return self._repr.pop() except IndexError: return None def top(self): try: return self._repr[-1] except IndexError: return None def count(self): return len(self._repr) # end of class Stack class Sizeritem: if common.use_gui: flags = { 'wxALL': wx.ALL, 'wxEXPAND': wx.EXPAND, 'wxALIGN_RIGHT': wx.ALIGN_RIGHT, 'wxALIGN_BOTTOM': wx.ALIGN_BOTTOM, 'wxALIGN_CENTER_HORIZONTAL': wx.ALIGN_CENTER_HORIZONTAL, 'wxALIGN_CENTER_VERTICAL': wx.ALIGN_CENTER_VERTICAL, 'wxLEFT': wx.LEFT, 'wxRIGHT': wx.RIGHT, 'wxTOP': wx.TOP, 'wxBOTTOM': wx.BOTTOM, 'wxSHAPED': wx.SHAPED, 'wxADJUST_MINSIZE': wx.ADJUST_MINSIZE, } import misc if misc.check_wx_version(2, 5, 2): flags['wxFIXED_MINSIZE'] = wx.FIXED_MINSIZE else: flags['wxFIXED_MINSIZE'] = 0 def __init__(self): self.option = self.border = 0 self.flag = 0 def __getitem__(self, name): if name != 'flag': return (None, lambda v: setattr(self, name, v)) def get_flag(v): val = reduce(lambda a, b: a|b, [Sizeritem.flags[t] for t in v.split("|")]) setattr(self, name, val) return (None, get_flag) ## lambda v: setattr(self, name, ## reduce(lambda a,b: a|b, ## [Sizeritem.flags[t] for t in ## v.split("|")]))) def flag_str(self): # returns the flag attribute as a string of tokens separated # by a '|' (used during the code generation) if hasattr(self, 'flag_s'): return self.flag_s else: try: tmp = {} for k in self.flags: if self.flags[k] & self.flag: tmp[k] = 1 # patch to make wxALL work remove_wxall = 4 for k in ('wxLEFT', 'wxRIGHT', 'wxTOP', 'wxBOTTOM'): if k in tmp: remove_wxall -= 1 if remove_wxall: try: del tmp['wxALL'] except KeyError: pass else: for k in ('wxLEFT', 'wxRIGHT', 'wxTOP', 'wxBOTTOM'): try: del tmp[k] except KeyError: pass tmp['wxALL'] = 1 tmp = '|'.join(tmp.keys()) except: print 'EXCEPTION: self.flags = %s, self.flag = %s' % \ (self.flags, repr(self.flag)) raise if tmp: return tmp else: return '0' # end of class Sizeritem spe-0.8.4.h/_spe/plugins/wxGlade/font_dialog.py0000644000175000017500000001457110743421035020426 0ustar stanistani# generated by wxGlade 0.2 on Sat Nov 30 15:30:36 2002 # $Id: font_dialog.py,v 1.9 2007/08/07 12:21:56 agriggio Exp $ #from wxPython.wx import * import wx import misc _reverse_dict = misc._reverse_dict class wxGladeFontDialog(wx.Dialog): font_families_to = { 'default': wx.DEFAULT, 'decorative': wx.DECORATIVE, 'roman': wx.ROMAN, 'swiss': wx.SWISS, 'script':wx.SCRIPT, 'modern': wx.MODERN } font_families_from = _reverse_dict(font_families_to) font_styles_to = { 'normal': wx.NORMAL, 'slant': wx.SLANT, 'italic': wx.ITALIC } font_styles_from = _reverse_dict(font_styles_to) font_weights_to = {'normal': wx.NORMAL, 'light': wx.LIGHT, 'bold': wx.BOLD } font_weights_from = _reverse_dict(font_weights_to) import misc if misc.check_wx_version(2, 3, 3): font_families_to['teletype'] = wx.TELETYPE font_families_from[wx.TELETYPE] = 'teletype' def __init__(self, *args, **kwds): # begin wxGlade: wxGladeFontDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.label_2_copy = wx.StaticText(self, -1, _("Family:")) self.label_3_copy = wx.StaticText(self, -1, _("Style:")) self.label_4_copy = wx.StaticText(self, -1, _("Weight:")) self.family = wx.Choice(self, -1, choices=[ "Default", "Decorative", "Roman", "Script", "Swiss", "Modern"]) self.style = wx.Choice(self, -1, choices=["Normal", "Slant", "Italic"]) self.weight = wx.Choice(self, -1, choices=["Normal", "Light", "Bold"]) self.label_1 = wx.StaticText(self, -1, _("Size in points:")) self.point_size = wx.SpinCtrl(self, -1, "", min=0, max=100) self.underline = wx.CheckBox(self, -1, _("Underlined")) self.font_btn = wx.Button(self, -1, _("Specific font...")) self.static_line_1 = wx.StaticLine(self, -1) self.ok_btn = wx.Button(self, wx.ID_OK, _("OK")) self.cancel_btn = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.__set_properties() self.__do_layout() # end wxGlade self.value = None wx.EVT_BUTTON(self, self.font_btn.GetId(), self.choose_specific_font) wx.EVT_BUTTON(self, self.ok_btn.GetId(), self.on_ok) def choose_specific_font(self, event): dialog = wx.FontDialog(self, wx.FontData()) if dialog.ShowModal() == wx.ID_OK: font = dialog.GetFontData().GetChosenFont() family = font.GetFamily() if misc.check_wx_version(2, 3, 3): for f in (wx.VARIABLE, wx.FIXED): if family & f: family = family ^ f self.value = "['%s', '%s', '%s', '%s', '%s', '%s']" % \ (font.GetPointSize(), self.font_families_from[family], self.font_styles_from[font.GetStyle()], self.font_weights_from[font.GetWeight()], font.GetUnderlined() and 1 or 0, font.GetFaceName()) self.EndModal(wx.ID_OK) def on_ok(self, event): self.value = "['%s', '%s', '%s', '%s', '%s', '']" % \ (self.point_size.GetValue(), self.family.GetStringSelection().lower(), self.style.GetStringSelection().lower(), self.weight.GetStringSelection().lower(), self.underline.GetValue() and 1 or 0) self.EndModal(wx.ID_OK) def get_value(self): return self.value def set_value(self, props): self.family.SetStringSelection(props[1].capitalize()) self.style.SetStringSelection(props[2].capitalize()) self.weight.SetStringSelection(props[3].capitalize()) try: try: underline = int(props[4]) except ValueError: if props[4].lower() == "true": underline = 1 else: underline = 0 self.underline.SetValue(underline) self.point_size.SetValue(int(props[0])) except ValueError: import traceback; traceback.print_exc() def __set_properties(self): # begin wxGlade: wxGladeFontDialog.__set_properties self.SetTitle(_("Select font attributes")) self.family.SetSelection(0) self.style.SetSelection(0) self.weight.SetSelection(0) self.ok_btn.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: wxGladeFontDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_2 = wx.BoxSizer(wx.VERTICAL) sizer_4 = wx.BoxSizer(wx.HORIZONTAL) sizer_5 = wx.BoxSizer(wx.VERTICAL) grid_sizer_1_copy = wx.FlexGridSizer(2, 3, 2, 10) grid_sizer_2_copy = wx.FlexGridSizer(2, 3, 2, 5) grid_sizer_2_copy.Add(self.label_2_copy, 0, wx.ALIGN_BOTTOM, 3) grid_sizer_2_copy.Add(self.label_3_copy, 0, wx.ALIGN_BOTTOM, 3) grid_sizer_2_copy.Add(self.label_4_copy, 0, wx.ALIGN_BOTTOM, 3) grid_sizer_2_copy.Add(self.family, 0, wx.EXPAND, 0) grid_sizer_2_copy.Add(self.style, 0, wx.EXPAND, 0) grid_sizer_2_copy.Add(self.weight, 0, wx.EXPAND, 0) grid_sizer_2_copy.AddGrowableCol(0) grid_sizer_2_copy.AddGrowableCol(1) grid_sizer_2_copy.AddGrowableCol(2) sizer_5.Add(grid_sizer_2_copy, 0, wx.EXPAND, 0) grid_sizer_1_copy.Add(self.label_1, 0, wx.ALIGN_BOTTOM, 0) grid_sizer_1_copy.Add((20, 5), 0, wx.ALIGN_BOTTOM, 0) grid_sizer_1_copy.Add((20, 5), 0, wx.ALIGN_BOTTOM, 0) grid_sizer_1_copy.Add(self.point_size, 0, 0, 0) grid_sizer_1_copy.Add(self.underline, 0, wx.EXPAND, 0) grid_sizer_1_copy.Add(self.font_btn, 0, 0, 0) grid_sizer_1_copy.AddGrowableCol(1) sizer_5.Add(grid_sizer_1_copy, 0, wx.TOP|wx.EXPAND, 3) sizer_5.Add(self.static_line_1, 0, wx.TOP|wx.EXPAND, 8) sizer_2.Add(sizer_5, 0, wx.EXPAND, 0) sizer_4.Add(self.ok_btn, 0, wx.RIGHT, 12) sizer_4.Add(self.cancel_btn, 0, 0, 0) sizer_2.Add(sizer_4, 0, wx.TOP|wx.ALIGN_RIGHT, 9) sizer_1.Add(sizer_2, 1, wx.ALL|wx.EXPAND, 10) self.SetAutoLayout(1) self.SetSizer(sizer_1) sizer_1.Fit(self) sizer_1.SetSizeHints(self) self.Layout() # end wxGlade self.CenterOnScreen() # end of class wxGladeFontDialog spe-0.8.4.h/_spe/plugins/wxGlade/CHANGES.txt0000644000175000017500000006635610743421035017410 0ustar stanistani2007-04-02: version 0.5 released, with some improvements, code ported to the "new" wx namespace, wxWidgets 2.8 support, and more... ------------------------------------------------------------------------------- 2006-03-02: version 0.4.1 released. Note that this file isn't very much up to date anymore... ------------------------------------------------------------------------------- 2005-10-10: version 0.4 released. ------------------------------------------------------------------------------- 2005-05-01: edit_sizers/edit_sizers.py: updated layout() to work with wx2.6 widgets/frame/frame.py: fixed a segfault when deleting a frame with a statusbar on wx2.6 widgets/notebook/notebook.py: updated notebook virtual sizer to fix broken layout on wx2.6 edit_windows.py: fixed property_panel layout which was broken on wx2.6 tree.py: - added wxBegin/EndBusyCursor() calls when showing a toplevel widget - called fit_parent at the end of show_widget for toplevel widgets without a specific size 2005-??-??: sorry, I didn't update this for a while, but there have been changes and improvements even during this period :-) To summarize: - added event handlers support (not for perl at the moment) - better sizers layout - many bugs fixed - updated copyright information - ... ------------------------------------------------------------------------------- 2004-11-08: version 0.3.5.1 released, due to a bug in version 0.3.5 (size property not updating correctly) ------------------------------------------------------------------------------- 2004-11-04: version 0.3.5 released 2004-11-02: kdefiledialog.py: support for native file and dir dialogs on KDE debian/: support for Debian package (by Georges Khaznadar) 2004-10-15: common.py, config.py, configUI.py, main.py, res/preferences.wxg: auto save support (i.e. now wxg files can be saved automatically periodically) 2004-09-17: edit_sizers/sizers_codegen.py, edit_sizers/perl_sizers_codegen.py, codegen/*.py: fixed issue with wxStaticBoxSizer code generation edit_sizers/edit_sizers.py, edit_windows.py: fixed segfault on wxGTK2 when removing a widget from the popup menu *.py: updated copyright information 2004-09-04: version 0.3.4.1 released, due to the introduction of a workaround for a bug in wxPython 2.5.2.8 (about wxGrid and its default size...) ------------------------------------------------------------------------------- 2004-09-01: version 0.3.4 released 2004-08-12: common.py: minor UI tweak edit_windows.py, config.py, configUI.py: added `show "handles" of sizers' option added `allow duplicate widget names' option 2004-07-18: widgets/menubar/codegen.py: changed python code generator to be smarter about menu items with a user defined name 2004-05-05: edit_windows.py, widget_properties.py: fixed a couple of wxMac issues widgets/frame/codegen.py: added xrc code generator for wxStatusBar widgets/choice/choice.py, widgets/combo_box/combo_box.py, widgets/list_box/list_box.py: removed default entry in Choices property widgets/combo_box/codegen.py, widgets/spin_ctrl/codegen.py: applied patch #944642 widgets/list_ctrl/list_ctrl.py: added a couple of extra styles widgets/button/*: added wxButton styles 2004-03-06: widgets/panel/panel.py: fixed (hopefully) bug #880674 2004-02-19: clipboard.py, main.py: added Drag&Drop of wxg files for opening them (thanks to Chris Liechti) 2004-02-17: main.py, docs/index.html, docs/html/*: new manual added 2004-02-07: config.py: config path is now under APPDATA ok windows 2004-01-25: widgets/bitmap_button/*, widgets/toolbar/*, widgets/static_bitmap/*: added "code:" tag 2003-12-28: xrc2wxg.py: added wxSplitterWindow support 2003-12-07: tree.py: partially fixed bug #798041 (renaming of cut widgets) 2003-12-06: widgets/panel/panel.py: added ability to paste a sizer inside a panel, notebook page and splitter pane 2003-11-24: codegen/py_codegen.py, widgets/*/codegen.py, edit_sizers/sizers_codegen.py: changes to the python code generator to support new wx namespace ------------------------------------------------------------------------------- 2003-08-30: version 0.3.1 released: sigh! we found an annoying bug on pl_codegen.py right after releasing 0.3 :-( ------------------------------------------------------------------------------- 2003-08-29: version 0.3 released 2003-07-26: codegen/pl_codegen.py, toolbar/perl_codegen.py, menubar/perl_codegen.py: brought Perl code generator up to date: - multiple files support - ``keep contents'' support - automatic ids generation (ID_FOO=?) support everything is still *experimental* and NEEDS EXTENSIVE TESTING 2003-07-18: widgets/toolbar/codegen.py, widgets/bitmap_button/codegen.py, widgets/static_bitmap/codegen.py: added (limited) support to xpm data (not on files). I.e. if the bitmap property is something like var:variable_name, variable_name is taken to be a variable that holds xpm data 2003-07-16: codegen/xrc_codegen.py, xml_parse.py, docs/turorial.html: added subclass support to XRC output 2003-07-15: application.py, tree.py, xml_parse.py, codegen/py_codegen.py, codegen/cpp_codegen.py: added "overwrite" property to Application, to allow re-generation of (C++ and python) code from scratch (as opposed to updating wxGlade blocks). docs/tutorial.html: updated notes 2003-07-11: codegen/py_codegen.py, codegen/cpp_codegen.py: enhanced generate_code_id, to recognize ID_SOMETHING=? and generate a "unique" id automatically codegen/cpp_codegen.py: fixed ids code generation when the output file already exists widgets/toolbar.py: fixed xrc code generation common.py: updated version number to 0.3pre1 2003-07-05: edit_windows.py, application.py: added validation code for `name' and `class' properties (fixed bug #764186) credits.txt: updated developer names codegen/py_codegen.py, codegen/cpp_codegen.py: fixed bug in quote_str 2003-06-26: tree.py, widgets/panel/*: added scrolled window support (this required a small change in Tree.Node.write in tree.py) 2003-06-23: perl generation support added 2003-06-21: nearly all around: fixed various Unicode-related bugs misc.py added functions, streq and wxstr, to fix some Unicode issues 2003-06-20: edit_windows.py, edit_sizers/edit_sizers.py, xml_parse.py: added cut&paste support for toplevel sizers 2003-06-02: common.py, main.py: added ToggleButtonBox to separate the "core" components from the "custom" ones (similar to Glade and QT-Designer) 2003-05-22: common.py, config.py: added local widgets path support ------------------------------------------------------------------------------- 2003-05-19: version 0.2.3 released docs/tutorial.html: some updates to the tutorial 2003-05-15: widgets/frame/*, widgets/dialog/*, edit_windows.py: added new properties 'icon', 'centered' (for dialog and frames) and 'disabled', 'focused' and 'hidden' (for all widgets) 2003-05-13: widgets/button/button.py, widgets/toggle_button/toggle_button.py, widgets/checkbox/checkbox.py, widgets/radio_button/radio_button.py: changed 'label' property to accept multiline strings xrc2wxg.py: moved initialization code to a 'main' function 2003-05-10: custom_widget/*, xrc2wxg.py: support of XRC code generation (and import) for custom widgets 2003-05-07: application.py, edit_windows.py, xml_parse.py, widgets/menubar/codegen.py, widgets/toolbar/codegen.py, widgets/custom_widget/codegen.py: added preview support ------------------------------------------------------------------------------- 2003-05-01: version 0.2.2 released 2003-04-24: widgets/toolbar/*: first ToolBar support (only tools, not controls yet) config.py: added test to check for the WXGLADE_CONFIG_PATH env var, to fix issue #726563 2003-04-23: edit_sizers/edit_sizers.py, widgets/splitter_window/*, widgets/notebook/*, xml_parse.py et al: new "virtual sizers" interface 2003-04-17: main.py, widgets/frame/frame.py, widgets/dialog/dialog.py, misc.py, config.py, common.py: - added ability to cancel the addition of a widget - added new config option to remember the geometry of wxGlade windows 2003-04-14: widgets/menubar/*: added support for radio menu items 2003-03-30: codegen/*, widgets/*/codegen.py: change of API to cleanup code widgets/menubar: added toplevel menubar support 2003-03-20: edit_windows.py: fixed bug #706890 2003-03-15: widgets/frame/frame.py: fixed bug #704091 2003-03-14: config.py, main.py: added new preference buttons_per_row, to control the geometry of the main palette 2003-03-11: widgets/list_ctrl/*, widgets/tree_ctrl/*: first support for wxListCtrl and wxTreeCtrl 2003-03-10: widget_properties.py, widgets/... (various modules), fixed some UI bugs (horizontal scrollbars - bug #701088, size of columns in some GridProperty) widgets/notebook/notebook.py: fixed serious bug on win32 (added the function _ugly_hack_for_win32_notebook_bug) 2003-03-08: codegen/cpp_codegen.py, codegen/py_codegen.py: fixed a couple of bugs in the regex to match class decl (still not 100% accurate, but better...) 2003-03-06: misc.py: added sizer_fixed_Insert to fix bug in wxPython 2.4 2003-03-05: widget_properties.py: modified the display function of each property, to get rid of useless wxPanels 2003-02-14: main.py, application.py: better error messages in case of IOError or OSError exceptions 2003-02-02: version 0.2.1 released ------------------------------------------------------------------------------ 2003-01-27: codegen/py_codegen.py, codegen/cpp_codegen.py: fixed bugs in multi-files mode code generation 2003-01-24: widget_properties.py: fixed segfault caused by a change (bug?) in wxPython 2.4.0.2 2003-01-01: main.py, common.py, config.py, codegen/*: added support for automatic backup application.py, codegen/*: added gettext support for the generated code (python and C++) ------------------------------------------------------------------------------- 2002-12-28: version 0.2 released edit_sizers/edit_sizers.py: better (hopefully) implementation of SizerBase.layout 2002-12-23: main.py, application.py: slightly better error messages 2002-12-14: docs/tutorial.html: added notes 2002-12-12: edit_sizers/edit_sizers.py, widgets/frame/frame.py: changed the EditFrame builder function to automatically set a sizer for the new frame 2002-12-11: edit_sizers/edit_sizers.py: - added methods insert_row and insert_col to GridSizerBase - EVT_MIDDLE_DOWN event handler to SizerSlot to paste from the clipboard "the X way" 2002-12-07: color_dialog.py, widget_properties.py: changed ColorDialogProperty to use a new custom dialog, using wxPyColorChooser by Michael Gilfix (thanks!) 2002-12-06: font_dialog.py, widget_properties.py: changed FontDialogProperty to use a new custom dialog (made in wxGlade!) edit_sizers/edit_sizers.py: changed set_growable_rows and set_growable_cols of EditFlexGridSizer to allow the effective removal of growable rows/cols edit_sizers/edit_sizers.py, edit_windows.py: restored 2.3.2.1 compatibility, broken by calls to wxCallAfter instead of misc.wxCallAfter 2002-11-28: edit_sizers/edit_sizers.py, tree.py: fixed bug on change_item_pos and change_node_pos 2002-11-27: codegen/py_codegen.py: if the output file for code generation already exists, honor the indentation. This is desirable for instance for conditional code, e.g. if you have to change behaviour if your app is invoked in GUI or non-GUI mode. about.py: updated developers credits 2002-11-24: widgets/*/codegen.py, xml_parse.py, edit_windows.py: changed code generation for "contol" widgets: now if you change the "Class" property, no extra code is generated, but it is assumed that you have a declaration of such a custom class somewhere. This makes much more sense than the previous behaviour (which I considered broken) 2002-11-17: codegen/py_codegen.py: added import_modules argument to add_widget_handler to allow widgets that need extra modules imported 2002-11-12: change (hopefully the last!) of license, from the Python2.2 one to MIT (for the reasons, see http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&frame=right&th=f37858bb262e4cff&seekm=918bc22f.0211051301.2010d077%40posting.google.com and following) 2002-11-11: codegen/cpp_codegen.py: modified attribute scope from private to protected in the generated code, to allow attribute access from a subclass 2002-11-05: misc.py: fixed bug in check_wx_version config.py, main.py: added support for wxFileHistory on wxPython >= 2.3.3 2002-11-01: misc.py: added focused_widget, accel_table, _remove, _cut, _copy, _paste to support keyboard shortcuts for some widgets' popup menu items in a cross-platform way 2002-10-28: widgets/custom_widget/*: added custom_widget module, to build apps which host widgets unknown to wxGlade 2002-10-25: codegen/py_codegen.py: changed wxGlade tags to fix bug caused by nested classes 2002-10-24: application.py, xml_parse.py, tree.py: added new encoding property to Application objects, which controls the encoding for the xml generation 2002-10-23: widgets/panel/panel.py, widgets/dialog/dialog.py: added new class EditTopLevelPanel to create panels without the need to create a container frame/dialog (the new class is available from the Dialog button in the palette) 2002-10-22: config.py: added config.py to configure some aspects of wxGlade (through View->Preferences... menu) 2002-10-20: edit_windows.py, edit_sizers/edit_sizers.py, main.py, misc.py: - added icons for menu items - support for keyboard shortcuts for popup menus (not on GTK yet) 2002-10-19: widget_properties.py, widgets/static_text/static_text.py, widgets/text_ctrl/text_ctrl.py: added multiline option to TextProperty to edit long values widgets/panel/*: added style property 2002-10-12: edit_sizers/edit_sizers.py: added method SizerBase.change_item_pos to change the position of an item in the sizer tree.py: added method Tree.change_node_pos to change the position of a node (and all its sub-nodes) on the tree edit_windows.py: added 'pos' property to ManagedBase instances to change the position of a widget inside its sizer 2002-10-10: widgets/button/*, widgets/bitmap_button/*: added 'default' property to implement wxButton.SetDefault 2002-10-08: edit_sizers/edit_sizers.py: - added function change_sizer (and related SizerBase.change event handler) to change the type of a sizer without deleting its contents - renamed SizerBase.Layout to SizerBase.layout for consistency - added optional recursive argument to SizerBase.Layout to call the method recursively on the sizer's sizer (if any) 2002-10-06: codegen/cpp_codegen.py, codegen/py_codegen.py, edit_sizers/edit_sizers.py: fixed bug related to notebook sizers edit_sizers/edit_sizers.py: fixed layout update on GridSizerBase, fixed add_col bug widgets/*: various layout improvements on some dialogs used to add widgets main.py: better layout of the tutorial window 2002-09-08: codegen/xrc_codegen.py: fixed bug (background colour) main.py, application.py: better path handling of file dialogs on GTK edit_sizers/edit_sizers.py: added add_row and add_col methods to GridSizerBase 2002-09-06: about.py: new about box with wxGlade logo ------------------------------------------------------------------------------- 2002-09-02: version 0.1.3 released switch from GPL license to the Python 2.2 (PSF) one 2002-08-27: codegen/cpp_codegen.py: fixed bug in id code generation widgets/frame/frame.py, widgets/dialog/dialog.py: fixed bug in get_style 2002-08-26: widgets/*/codegen.py, codegen/py_codegen.py, codegen/cpp_codegen.py: changed code generation to initialize widgets in the right order, so as to preserve the tab traversal order 2002-08-15: edit_windows.py, codegen/py_codegen.py, codegen/cpp_codegen.py: added "tooltip" property main.py: modified file dialogs to display a filter for wxGlade XML files (.wxg extension) wxglade.py, main.py: added ability to open a wxGlade file at program startup 2002-08-12: codegen/cpp_codegen.py, widgets/*/codegen.py: added experimental C++ code generator 2002-08-11: edit_windows.py, codegen/py_codegen.py: support of dialog units 2002-08-10: widgets/*/codegen.py: better python code generator functions widgets/button/codegen.py, widgets/frame/codegen.py: translation from "&" to "_" as accelerator marker in XRC output main.py: added "Generate Code..." menu item to the File menu 2002-08-09: widgets/*: fixed bug in the python code generation function when the object is an instance of a custom class 2002-08-04 / 2002-08-06: many bugfixes all around, codegen/xrc_codegen.py: first experimental code generator for wxWindows' XRC resources codegen/py_codegen.py: added a self.Layout() call at the end of __do_layout (as this is necessary for Dialogs on Windows) 2002-08-03: codegen/py_codegen.py, edit_sizers/sizers_codegen.py, xml_parse.py: changes to separate sizers from windows in the generated code, and to put sizers declarations in the __do_layout method application.py, widget_properties.py: fix for a just introduced wxPython 2.3.2.1 incompatibility widgets/MenuTree.py: added support for help strings on menu items 2002-08-02: widgets/* edit_sizers: turned into packages with two modules, to decouple code generation functions from the rest common.py: - moved Application to the new application.py - moved misc._encode and widget_properties._encode here misc.py: moved _encode to common.py widget_properties.py: moved _encode to common.py wxglade.py: added functions usage and command_line_code_generation to support code generation without starting the GUI main.py, widgets/frame/frame.py, widgets/frame/codegen.py: modified wxMenu.Append with checkable items for wxPython 2.3.3 compatibility 2002-08-01: main.py: added a View->Show Properties menu item widgets/frame.py: experimental fix for menubar-related segfaults on GTK ------------------------------------------------------------------------------- 2002-08-01: version 0.1.2 released 2002-08-01: clipboard.py: removed dirt at the end of xml_str when retrieved from the clipboard (this may happen on Windows) Removed renaming code xml_parse.py: added code to rename copied widgets in ClipboardXmlWidgetBuilder tree.py: fixed bug when a toplevel window is shown and it doesn't have a sizer widgets/dialog.py: changed create_widget to use a default style and not the current one, to avoid for example frames without a caption edit_sizers.py: fixed a memory leak widgets/splitter_window.py: fixed bug in the code generation widget_properties.py: fixed bug in HiddenProperty widgets/radio_box.py, widgets/static_bitmap.py, widgets/bitmap_button.py: fixed bugs README file added 2002-07-30: xml_parse.py: removed fake obj replacement in XmlWidgetObject.add_property since it is not necessary anymore edit_sizers.py, widgets/static_line.py, widgets/notebook.py, widgets/splitter_window.py, widgets/slider.py: removed obsolete use of Fake* objects during xml loading widgets/splitter_window.py: fixed bug in set_size regarding the position of the sash clipboard.py: changes to use system clipboard with wxTheClipboard 2002-07-29: tree.py, main.py: prevention of auto expansion of tree nodes during xml loading widget_properties.py: fixed bug in self._enabler for many Properties edit_sizers.py: - fixed bug on EditStaticBoxSizer - changed self._rmenu to be an instance of wxGladePopupMenu - renamed Refresh to refresh for consistency with the implicit coding conventions edit_windows.py: changed self._rmenu to be an instance of wxGladePopupMenu misc.py: added wxGladePopupMenu tree.py: added popup menu to show hidden toplevel widgets widgets/panel.py, widgets/notebook.py, widgets/splitter_window.py: removed obsolete on_parent_size methods widgets/panel.py: fixed bug that caused a bad layout of the panel when resized 2002-07-28: about.py: updated developers credits 2002-07-26 / 2002-07-28: transition to the new implementation, i.e. (partial) separation of the GUI from the core logic 2002-07-22: TODO.txt: updated docs/tech_notes.txt: added (incomplete) 2002-07-20: edit_sizers.py: - added a create_properties method, with the same purpose of EditBase.create_properties - fixed a couple of bugs (double Destroy call) on SizerSlot widgets/splitter_window.py: completed transition from the old Property behaviour to the new one xml_parse.py: created ClipboardXmlWidgetBuilder, to parse the contents of the clipboard clipboard.py: changes to use the new ClipboardXmlWidgetBuilder 2002-07-19: main.py, widget_properties.py, edit_windows.py, edit_sizers.py: fixed a lot of memory leaks 2002-07-18: widget_properties.py: changed all the Properties: they are not instances of wxPanel anymore, but they have a panel attribute, which is initialized only when needed (i.e. when the owner of the Property has focus) edit_windows.py, edit_sizers.py: changes to reflect the new behaviour of Properties: now the notebook inside which Properties are displayed is built only when needed 2002-07-17: codegen/py_codegen.py: - support for multiple output files - initial support for tags in the generated source files to know what to overwrite and what to leave untouched 2002-07-16: codegen/py_codegen.py: - initial support for multiple files - if __name__ == '__main__' block on generated code - remove duplicate declarations of custom classes when there is more than one instance main.py: fixed some memory leaks common.py: initial support for generation of multiple files xml_parse.py: initial support for generation of multiple files TODO.txt: added plan to support an XRC code generator 2002-07-14: version 0.1alpha2 wxglade.py: added comments, added an if __name__ == '__main__' block codegen/py_codegen.py: - fixed bug in the generated code when a __do_layout method is empty - translated the last Italian comment to English widgets/notebook.py: - fixed bug in the generated code when the notebook is an instance of a custom class - fixed bug in xml_builder which prevented the 'class' property from having the right value widgets/splitter_window.py: - fixed bug in the generated code when the window is an instance of a custom class - fixed bug in xml_builder which prevented the 'class' property from having the right value widgets/static_line.py: fixed bug in xml_builder which prevented the 'class' property from having the right value docs/tutorial.html: - fixed some errors - added information about custom classes ------------------------------------------------------------------------------- 2002-07-12: version 0.1alpha (first public release) spe-0.8.4.h/_spe/plugins/wxGlade/.hgignore0000644000175000017500000000012310743421035017356 0ustar stanistani# Files to be ignored by mercurial syntax: glob **.pyc **.pyo **~ \#*\# **/\#*\# spe-0.8.4.h/_spe/plugins/wxGlade/wxglade.spec0000644000175000017500000000470210743421035020071 0ustar stanistani%define name wxGlade %define version 0.3.5.1 %define release 1 Summary: wxWidgets/wxPython/wxPerl GUI designer Name: %{name} Version: %{version} Release: %{release} Source0: %{name}-%{version}.tar.gz License: MIT Group: Development/Tools BuildRoot: %{_tmppath}/%{name}-buildroot Prefix: %{_prefix} BuildArch: noarch Requires: python Requires: wxPython %description wxGlade is a GUI designer written in Python with the popular GUI toolkit wxPython, that helps you create wxWidgets/wxPython user interfaces. At the moment it can generate Python, C++, Perl and XRC (wxWidgets' XML resources) code. #' %prep %setup -q -n wxGlade-%{version} %build # nothing to do %install # cleanup rm -rf $RPM_BUILD_ROOT # make dirs mkdir -p $RPM_BUILD_ROOT%{_prefix}/bin mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/%{name} # copy files needed at runtime cp -p *.py $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -p credits.txt $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -p license.txt $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -pr codegen $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -pr docs $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -pr edit_sizers $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -pr icons $RPM_BUILD_ROOT%{_prefix}/lib/%{name} cp -pr widgets $RPM_BUILD_ROOT%{_prefix}/lib/%{name} # make a launcher script cat > $RPM_BUILD_ROOT%{_prefix}/bin/wxglade < 0.3.5-1 - Updated to version 0.3.5 * Wed Mar 10 2004 Alberto Griggio 0.3.4-1 - Updated to version 0.3.4 * Wed Mar 10 2004 Alberto Griggio 0.3.2-1 - Updated to version 0.3.2 * Tue Sep 02 2003 Alberto Griggio 0.3.1-1 - Updated to version 0.3.1 * Fri Aug 29 2003 Robin Dunn 0.3-5 - Initial version spe-0.8.4.h/_spe/plugins/wxGlade/configUI.py0000755000175000017500000002104010743421035017634 0ustar stanistani#!/usr/bin/env python # -*- coding: iso-8859-15 -*- # generated by wxGlade 0.6 import wx # begin wxGlade: extracode import common import os _icon_path = os.path.join(common.wxglade_path, 'icons', 'icon.xpm') import common import os _icon_path = os.path.join(common.wxglade_path, 'icons', 'icon.xpm') # end wxGlade class wxGladePreferencesUI(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: wxGladePreferencesUI.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.notebook_1 = wx.Notebook(self, -1, style=0) self.notebook_1_pane_2 = wx.Panel(self.notebook_1, -1) self.sizer_6_staticbox = wx.StaticBox(self.notebook_1_pane_2, -1, _("Local widget path")) self.notebook_1_pane_1 = wx.Panel(self.notebook_1, -1) self.use_menu_icons = wx.CheckBox(self.notebook_1_pane_1, -1, _("Use icons in menu items")) self.frame_tool_win = wx.CheckBox(self.notebook_1_pane_1, -1, _("Show properties and tree windows as small frames")) self.show_progress = wx.CheckBox(self.notebook_1_pane_1, -1, _("Show progress dialog when loading wxg files")) self.remember_geometry = wx.CheckBox(self.notebook_1_pane_1, -1, _("Remember position and size of wxGlade windows")) self.show_sizer_handle = wx.CheckBox(self.notebook_1_pane_1, -1, _("Show \"handles\" of sizers")) self.use_kde_dialogs = wx.CheckBox(self.notebook_1_pane_1, -1, _("Use native file dialogs on KDE")) self.open_save_path = wx.TextCtrl(self.notebook_1_pane_1, -1, "") self.codegen_path = wx.TextCtrl(self.notebook_1_pane_1, -1, "") self.number_history = wx.SpinCtrl(self.notebook_1_pane_1, -1, "4", min=0, max=100) self.buttons_per_row = wx.SpinCtrl(self.notebook_1_pane_1, -1, "5", min=1, max=100) self.use_dialog_units = wx.CheckBox(self.notebook_1_pane_2, -1, _("Use dialog units by default for size properties")) self.wxg_backup = wx.CheckBox(self.notebook_1_pane_2, -1, _("Create backup wxg files")) self.codegen_backup = wx.CheckBox(self.notebook_1_pane_2, -1, _("Create backup files for generated source")) self.allow_duplicate_names = wx.CheckBox(self.notebook_1_pane_2, -1, _("Allow duplicate widget names")) self.default_border = wx.CheckBox(self.notebook_1_pane_2, -1, _("Default border width for widgets")) self.default_border_size = wx.SpinCtrl(self.notebook_1_pane_2, -1, "", min=0, max=20) self.autosave = wx.CheckBox(self.notebook_1_pane_2, -1, _("Auto save wxg files every ")) self.autosave_delay = wx.SpinCtrl(self.notebook_1_pane_2, -1, "120", min=30, max=300) self.write_timestamp = wx.CheckBox(self.notebook_1_pane_2, -1, _("Insert timestamp on generated source files")) self.write_generated_from = wx.CheckBox(self.notebook_1_pane_2, -1, _("Insert .wxg file name on generated source files")) self.backup_suffix = wx.RadioBox(self.notebook_1_pane_2, -1, _("Backup options"), choices=[_("append ~ to filename"), _("append .bak to filename")], majorDimension=2, style=wx.RA_SPECIFY_COLS) self.local_widget_path = wx.TextCtrl(self.notebook_1_pane_2, -1, "") self.choose_widget_path = wx.Button(self.notebook_1_pane_2, -1, _("..."), style=wx.BU_EXACTFIT) self.ok = wx.Button(self, wx.ID_OK, "") self.cancel = wx.Button(self, wx.ID_CANCEL, "") self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: wxGladePreferencesUI.__set_properties self.SetTitle(_("wxGlade: preferences")) _icon = wx.EmptyIcon() _icon.CopyFromBitmap(wx.Bitmap(_icon_path, wx.BITMAP_TYPE_ANY)) self.SetIcon(_icon) self.use_menu_icons.SetValue(1) self.frame_tool_win.SetValue(1) self.show_progress.SetValue(1) self.remember_geometry.SetValue(1) self.show_sizer_handle.SetValue(1) self.use_kde_dialogs.SetValue(1) self.open_save_path.SetMinSize((196, -1)) self.codegen_path.SetMinSize((196, -1)) self.number_history.SetMinSize((196, -1)) self.buttons_per_row.SetMinSize((196, -1)) self.wxg_backup.SetValue(1) self.codegen_backup.SetValue(1) self.allow_duplicate_names.Hide() self.default_border_size.SetMinSize((45, 22)) self.autosave_delay.SetMinSize((45, 22)) self.write_timestamp.SetValue(1) self.backup_suffix.SetSelection(0) self.ok.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: wxGladePreferencesUI.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_5 = wx.BoxSizer(wx.VERTICAL) sizer_6 = wx.StaticBoxSizer(self.sizer_6_staticbox, wx.HORIZONTAL) sizer_7_copy = wx.BoxSizer(wx.HORIZONTAL) sizer_7 = wx.BoxSizer(wx.HORIZONTAL) sizer_3 = wx.BoxSizer(wx.VERTICAL) sizer_4 = wx.FlexGridSizer(4, 2, 0, 0) sizer_3.Add(self.use_menu_icons, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.frame_tool_win, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.show_progress, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.remember_geometry, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.show_sizer_handle, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.use_kde_dialogs, 0, wx.ALL|wx.EXPAND, 5) label_1 = wx.StaticText(self.notebook_1_pane_1, -1, _("Initial path for \nfile opening/saving dialogs:")) sizer_4.Add(label_1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_4.Add(self.open_save_path, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) label_2_copy = wx.StaticText(self.notebook_1_pane_1, -1, _("Initial path for \ncode generation file dialogs:")) sizer_4.Add(label_2_copy, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_4.Add(self.codegen_path, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) label_2 = wx.StaticText(self.notebook_1_pane_1, -1, _("Number of items in file history")) sizer_4.Add(label_2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_4.Add(self.number_history, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) label_2_copy_1 = wx.StaticText(self.notebook_1_pane_1, -1, _("Number of buttons per row\nin the main palette")) sizer_4.Add(label_2_copy_1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_4.Add(self.buttons_per_row, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_4.AddGrowableCol(1) sizer_3.Add(sizer_4, 0, wx.EXPAND, 3) self.notebook_1_pane_1.SetSizer(sizer_3) sizer_5.Add(self.use_dialog_units, 0, wx.ALL|wx.EXPAND, 5) sizer_5.Add(self.wxg_backup, 0, wx.ALL|wx.EXPAND, 5) sizer_5.Add(self.codegen_backup, 0, wx.ALL|wx.EXPAND, 5) sizer_5.Add(self.allow_duplicate_names, 0, wx.ALL|wx.EXPAND, 5) sizer_7.Add(self.default_border, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) sizer_7.Add(self.default_border_size, 0, wx.ALL, 5) sizer_5.Add(sizer_7, 0, wx.EXPAND, 0) sizer_7_copy.Add(self.autosave, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL, 5) sizer_7_copy.Add(self.autosave_delay, 0, wx.TOP|wx.BOTTOM, 5) label_3 = wx.StaticText(self.notebook_1_pane_2, -1, _(" seconds")) sizer_7_copy.Add(label_3, 0, wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 5) sizer_5.Add(sizer_7_copy, 0, wx.EXPAND, 0) sizer_5.Add(self.write_timestamp, 0, wx.ALL|wx.EXPAND, 5) sizer_5.Add(self.write_generated_from, 0, wx.ALL|wx.EXPAND, 5) sizer_5.Add(self.backup_suffix, 0, wx.ALL|wx.EXPAND, 5) sizer_6.Add(self.local_widget_path, 1, wx.ALL, 3) sizer_6.Add(self.choose_widget_path, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 3) sizer_5.Add(sizer_6, 0, wx.ALL|wx.EXPAND, 5) self.notebook_1_pane_2.SetSizer(sizer_5) self.notebook_1.AddPage(self.notebook_1_pane_1, _("Interface")) self.notebook_1.AddPage(self.notebook_1_pane_2, _("Other")) sizer_1.Add(self.notebook_1, 1, wx.ALL|wx.EXPAND, 5) sizer_2.Add(self.ok, 0, 0, 0) sizer_2.Add(self.cancel, 0, wx.LEFT, 10) sizer_1.Add(sizer_2, 0, wx.ALL|wx.ALIGN_RIGHT, 10) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() self.Centre() # end wxGlade # end of class wxGladePreferencesUI if __name__ == "__main__": import gettext gettext.install("app") # replace with the appropriate catalog name app = wx.PySimpleApp(0) wx.InitAllImageHandlers() dialog_1 = wxGladePreferencesUI(None, -1, "") app.SetTopWindow(dialog_1) dialog_1.Show() app.MainLoop() spe-0.8.4.h/_spe/plugins/wxGlade/wxglade.pyw0000644000175000017500000000055510743421035017760 0ustar stanistani#!/usr/bin/env python # wxglade.pyw: entry point of wxGlade on windows # $Id: wxglade.pyw,v 1.1 2004/10/27 11:11:19 agriggio Exp $ # # Copyright (c) 2002-2004 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #import the wxglade module import wxglade #run the main function wxglade.run_main() spe-0.8.4.h/_spe/plugins/wxGlade/clipboard.py0000644000175000017500000001043010743421035020066 0ustar stanistani# clipboard.py: support for cut & paste of wxGlade widgets # $Id: clipboard.py,v 1.19 2007/07/21 11:30:29 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * import wx # Format used by wxGlade for the clipboard. _widget_data_format = wx.CustomDataFormat("wxglade_widget") class _WidgetDataObject(wx.CustomDataObject): """\ Object representig a widget in the clipboard. """ def __init__(self, *args): wx.CustomDataObject.__init__(self, _widget_data_format) if args: data = apply(self._widget2repr, args) self.SetData(data) def _widget2repr(self, *args): """\ Convert *args into a string and returns it. *args contains option, flag, border, xml_str. """ assert len(args) == 4 return ":".join([str(elem) for elem in args]) def GetWidgetData(self): """\ Convert a string into option, flag, border and xml_string and returns them in a list. """ ret = self.GetData().split(":", 3) assert len(ret) == 4, _("Invalid data in the clipboard") # remove the dirt at the end of xml_str bound = ret[3].rfind('>')+1 ret[3] = ret[3][:bound] for i in range(3): # option, flag and border are integers. ret[i] = int(ret[i]) return ret def copy(widget): """\ Copies widget and all its children to the clipboard. """ from cStringIO import StringIO xml_str = StringIO() widget.node.write(xml_str, 0) flag = widget.get_int_flag() option = widget.get_option() border = widget.get_border() if wx.TheClipboard.Open(): try: wdo = _WidgetDataObject(option, flag, border, xml_str.getvalue()) if not wx.TheClipboard.SetData(wdo): print _("Data can't be copied to clipboard.") return False return True finally: wx.TheClipboard.Close() else: print _("Clipboard can't be opened.") return False def cut(widget): """\ Copies widget and all its children to the clipboard and then removes them. """ if copy(widget): widget.remove() return True else: return False def paste(parent, sizer, pos): """\ Copies a widget (and all its children) from the clipboard to the given destination (parent, sizer and position inside the sizer) returns True if there was something to paste, False otherwise. """ if wx.TheClipboard.Open(): try: if wx.TheClipboard.IsSupported(_widget_data_format): wdo = _WidgetDataObject() if not wx.TheClipboard.GetData(wdo): print _("Data can't be copied from clipboard.") return False else: return False finally: wx.TheClipboard.Close() else: print _("Clipboard can't be opened.") return False option, flag, border, xml_str = wdo.GetWidgetData() if xml_str: import xml_parse try: wx.BeginBusyCursor() parser = xml_parse.ClipboardXmlWidgetBuilder(parent, sizer, pos, option, flag, border) parser.parse_string(xml_str) return True # Widget hierarchy pasted. finally: wx.EndBusyCursor() return False # There's nothing to paste. #----------------------------------------------------------------------------- # 2004-02-19 ALB: D&D support (thanks to Chris Liechti) #----------------------------------------------------------------------------- class FileDropTarget(wx.FileDropTarget): def __init__(self, parent): wx.FileDropTarget.__init__(self) self.parent = parent def OnDropFiles(self, x, y, filenames): if len(filenames) > 1: wx.MessageBox(_("Please only drop one file at a time"), "wxGlade", wx.ICON_ERROR) elif filenames: path = filenames[0] if self.parent.ask_save(): self.parent._open_app(path) # end of class FileDropTarget spe-0.8.4.h/_spe/plugins/wxGlade/license.txt0000644000175000017500000000211210743421035017736 0ustar stanistaniCopyright (c) 2002-2007 Alberto Griggio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. spe-0.8.4.h/_spe/plugins/wxGlade/tree.py0000644000175000017500000006346410743421035017105 0ustar stanistani# tree.py: classes to handle and display the structure of a wxGlade app # $Id: tree.py,v 1.56 2007/08/07 12:13:44 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * import wx from xml.sax.saxutils import quoteattr import misc, common, os.path try: set except NameError: from sets import Set as set class Tree: """\ A class to represent a hierarchy of widgets. """ class Node: __empty_win = None def __init__(self, widget=None, children=None): self.widget = widget self.children = children self.parent = None def remove(self): def remove_rec(node): if node.children is not None: map(remove_rec, node.children) node.children = None if node.widget is not None: # replace the just destroyed notebook with an empty window pw = node.widget.property_window pw.SetTitle(_('Properties - <>')) if Tree.Node.__empty_win is None: Tree.Node.__empty_win = wx.Window(pw, -1) pw.GetSizer().GetChildren()[0].SetWindow( Tree.Node.__empty_win) #wxNotebook(node.widget.property_window, -1)) # call the widget's ``destructor'' node.widget.delete() node.widget = None remove_rec(self) try: self.parent.children.remove(self) except: pass def __repr__(self): try: return self.widget.name except AttributeError: return repr(self.widget) def write(self, outfile, tabs, class_names=None): """\ Writes the xml code for the widget to the given output file """ import edit_sizers fwrite = outfile.write assert self.widget is not None w = self.widget classname = getattr(w, '_classname', w.__class__.__name__) # ALB 2005-11-19: to disable custom class code generation # (for panels...) no_custom = "" if getattr(w, 'no_custom_class', False): no_custom = ' no_custom_class="1"' fwrite(' ' * tabs + '\n' % (quoteattr(w.klass), quoteattr(w.name), quoteattr(classname), no_custom)) for p in w.properties: w.properties[p].write(outfile, tabs+1) if class_names is not None: class_names.add(w.klass) if isinstance(w, edit_sizers.SizerBase): maxpos = len(w.children) children = self.children is not None and self.children or [] tmp = {} for c in children: tmp[c.widget.pos] = c children = [] class SlotNode: def write(self, outfile, tabs): fwrite(' ' * tabs + '\n') for i in range(1, maxpos): children.append(tmp.get(i, SlotNode())) #if self.children is not None: # for c in self.children: for c in children: if hasattr(c, 'widget'): fwrite(' ' * (tabs+1) + '\n') sp = c.widget.sizer_properties for p in sp: sp[p].write(outfile, tabs+2) c.write(outfile, tabs+2, class_names) fwrite(' ' * (tabs+1) + '\n') else: c.write(outfile, tabs+1) elif self.children is not None: for c in self.children: c.write(outfile, tabs+1, class_names) fwrite(' ' * tabs + '\n') # end of class Node def __init__(self, root=None, app=None): self.root = root if self.root is None: self.root = Tree.Node() self.current = self.root self.app = app # reference to the app properties self.names = {} # dictionary of names of the widgets: each entry is # itself a dictionary, one for each toplevel widget... def _find_toplevel(self, node): assert node is not None, _("None node in _find_toplevel") if node.parent is self.root: return node.parent while node.parent is not self.root: node = node.parent return node def has_name(self, name, node=None): if node is None: #print '\nname to check:', name for n in self.names: #print 'names of %s: %s' % (n.widget.name, self.names[n]) if name in self.names[n]: return True return False else: node = self._find_toplevel(node) #print '\nname to check:', name #print 'names of node %s: %s' % (node.widget.name, self.names[node]) return name in self.names[node] #return self.names.has_key(name) def add(self, child, parent=None): if parent is None: parent = self.root if parent.children is None: parent.children = [] parent.children.append(child) child.parent = parent self.current = child #self.names[str(child.widget.name)] = 1 #self.names.setdefault(parent, {})[str(child.widget.name)] = 1 self.names.setdefault(self._find_toplevel(child), {})[ str(child.widget.name)] = 1 if parent is self.root and \ getattr(child.widget.__class__, '_is_toplevel', False): self.app.add_top_window(child.widget.name) def insert(self, child, parent, index): if parent is None: parent = self.root if parent.children is None: parent.children = [] parent.children.insert(index, child) child.parent = parent self.current = child #self.names[str(child.widget.name)] = 1 #self.names.setdefault(parent, {})[str(child.widget.name)] = 1 self.names.setdefault(self._find_toplevel(child), {})[ str(child.widget.name)] = 1 if parent is self.root: self.app.add_top_window(child.widget.name) def remove(self, node=None): if node is not None: def clear_name(n): try: #del self.names[str(n.widget.name)] del self.names[self._find_toplevel(n)][str(n.widget.name)] except (KeyError, AttributeError): pass if n.children: for c in n.children: clear_name(c) clear_name(node) if node.parent is self.root: self.app.remove_top_window(node.widget.name) node.remove() elif self.root.children: for n in self.root.children: n.remove() self.root.children = None self.names = {} def write(self, outfile=None, tabs=0): """\ Writes the xml equivalent of this tree to the given output file """ if outfile is None: import sys outfile = sys.stdout from time import asctime import common outfile.write('\n\n\n' % (common.version, asctime())) outpath = os.path.expanduser(self.app.output_path.strip()) name = self.app.get_name() klass = self.app.get_class() option = str(self.app.codegen_opt) top_window = self.app.get_top_window() language = self.app.get_language() encoding = self.app.get_encoding() use_gettext = str(int(self.app.use_gettext)) is_template = str(int(self.app.is_template)) overwrite = str(int(self.app.overwrite)) # ALB 2004-01-18 #use_new_namespace = str(int(self.app.get_use_new_namespace())) use_new_namespace = str(int(not self.app.get_use_old_namespace())) # ALB 2004-12-05 for_version = str(self.app.for_version) outfile.write('\n' \ % tuple([quoteattr(common._encode_to_xml(i)) for i in (outpath, name, klass, option, language, top_window, encoding, use_gettext, overwrite, use_new_namespace, for_version, is_template)])) if self.app.is_template and getattr(self.app, 'template_data', None): self.app.template_data.write(outfile, tabs+1) class_names = set() if self.root.children is not None: for c in self.root.children: c.write(outfile, tabs+1, class_names) outfile.write('\n') return class_names def change_node(self, node, widget): """\ Changes the node 'node' so that it refers to 'widget' """ try: #del self.names[node.widget.name] del self.names[self._find_toplevel(node)][node.widget.name] except KeyError: pass node.widget = widget #self.names[widget.name] = 1 self.names.setdefault(self._find_toplevel(node), {})[widget.name] = 1 def change_node_pos(self, node, new_pos, index=None): if index is None: index = node.parent.children.index(node) if index >= new_pos: node.parent.children.insert(new_pos, node) del node.parent.children[index+1] else: del node.parent.children[index] node.parent.children.insert(new_pos+1, node) # end of class Tree class WidgetTree(wx.TreeCtrl, Tree): """\ Tree with the ability to display the hierarchy of widgets """ images = {} # dictionary of icons of the widgets displayed def __init__(self, parent, application): id = wx.NewId() style = wx.TR_DEFAULT_STYLE|wx.TR_HAS_VARIABLE_ROW_HEIGHT if wx.Platform == '__WXGTK__': style |= wx.TR_NO_LINES|wx.TR_FULL_ROW_HIGHLIGHT elif wx.Platform == '__WXMAC__': style &= ~wx.TR_ROW_LINES wx.TreeCtrl.__init__(self, parent, id, style=style) root_node = Tree.Node(application) self.cur_widget = None # reference to the selected widget Tree.__init__(self, root_node, application) image_list = wx.ImageList(21, 21) image_list.Add(wx.Bitmap(os.path.join(common.wxglade_path, 'icons/application.xpm'), wx.BITMAP_TYPE_XPM)) for w in WidgetTree.images: ## WidgetTree.images[w] = image_list.Add(wx.Bitmap( ## WidgetTree.images[w], wx.BITMAP_TYPE_XPM)) WidgetTree.images[w] = image_list.Add( misc.get_xpm_bitmap(WidgetTree.images[w])) self.AssignImageList(image_list) root_node.item = self.AddRoot(_('Application'), 0) self.SetPyData(root_node.item, root_node) self.skip_select = 0 # necessary to avoid an infinite loop on win32, as # SelectItem fires an EVT_TREE_SEL_CHANGED event self.title = ' ' self.set_title(self.title) self.auto_expand = True # this control the automatic expansion of # nodes: it is set to False during xml loading self._show_menu = misc.wxGladePopupMenu('widget') # popup menu to # show toplevel # widgets SHOW_ID = wx.NewId() self._show_menu.Append(SHOW_ID, _('Show')) wx.EVT_TREE_SEL_CHANGED(self, id, self.on_change_selection) wx.EVT_RIGHT_DOWN(self, self.popup_menu) wx.EVT_LEFT_DCLICK(self, self.show_toplevel) wx.EVT_MENU(self, SHOW_ID, self.show_toplevel) def on_key_down(event): evt_flags = 0 if event.ControlDown(): evt_flags = wx.ACCEL_CTRL evt_key = event.GetKeyCode() for flags, key, function in misc.accel_table: if evt_flags == flags and evt_key == key: wx.CallAfter(function) break event.Skip() wx.EVT_KEY_DOWN(self, on_key_down) def _build_label(self, node): s = node.widget.name if node.widget.klass != node.widget.base and \ node.widget.klass != 'wxScrolledWindow': # special case... s += ' (%s)' % node.widget.klass return s def add(self, child, parent=None, image=None): # is image still used? """\ appends child to the list of parent's children """ Tree.add(self, child, parent) import common name = child.widget.__class__.__name__ index = WidgetTree.images.get(name, -1) if parent is None: parent = parent.item = self.GetRootItem() child.item = self.AppendItem(parent.item, self._build_label(child), index) self.SetPyData(child.item, child) if self.auto_expand: self.Expand(parent.item) self.select_item(child) child.widget.show_properties() self.app.check_codegen(child.widget) def insert(self, child, parent, pos, image=None): """\ inserts child to the list of parent's children, before index """ if parent.children is None: self.add(child, parent, image) return import common name = child.widget.__class__.__name__ image_index = WidgetTree.images.get(name, -1) if parent is None: parent = parent.item = self.GetRootItem() index = 0 if misc.check_wx_version(2, 5): item, cookie = self.GetFirstChild(parent.item) else: item, cookie = self.GetFirstChild(parent.item, 1) while item.IsOk(): item_pos = self.GetPyData(item).widget.pos if pos < item_pos: break index += 1 item, cookie = self.GetNextChild(parent.item, cookie) Tree.insert(self, child, parent, index) child.item = self.InsertItemBefore(parent.item, index, self._build_label(child), image_index) self.SetPyData(child.item, child) if self.auto_expand: self.Expand(parent.item) self.select_item(child) child.widget.show_properties() self.app.check_codegen(child.widget) def remove(self, node=None): self.app.saved = False # update the status of the app Tree.remove(self, node) if node is not None: try: self.cur_widget = None self.SelectItem(node.parent.item) except: self.SelectItem(self.GetRootItem()) self.Delete(node.item) else: wx.TreeCtrl.Destroy(self) def clear(self): self.app.reset() self.skip_select = True if self.root.children: while self.root.children: c = self.root.children[-1] if c.widget: c.widget.remove() self.root.children = None self.skip_select = False app = self.GetPyData(self.GetRootItem()) app.widget.show_properties() def refresh_name(self, node, oldname=None): #, name=None): if oldname is not None: try: #del self.names[self.GetItemText(node.item)] del self.names[self._find_toplevel(node)][oldname] except KeyError: pass #self.names[name] = 1 #self.SetItemText(node.item, name) #self.names[node.widget.name] = 1 self.names.setdefault(self._find_toplevel(node), {})[ node.widget.name] = 1 self.SetItemText(node.item, self._build_label(node)) def select_item(self, node): self.skip_select = True self.SelectItem(node.item) self.skip_select = False if self.cur_widget: self.cur_widget.update_view(False) self.cur_widget = node.widget self.cur_widget.update_view(True) self.cur_widget.show_properties() misc.focused_widget = self.cur_widget def on_change_selection(self, event): if not self.skip_select: item = event.GetItem() try: if self.cur_widget: self.cur_widget.update_view(False) self.cur_widget = self.GetPyData(item).widget misc.focused_widget = self.cur_widget self.cur_widget.show_properties(None) self.cur_widget.update_view(True) except AttributeError: pass except Exception: import traceback traceback.print_exc() def popup_menu(self, event): node = self._find_item_by_pos(*event.GetPosition()) if not node: return else: self.select_item(node) item = node.widget if not item.widget or not item.is_visible(): import edit_windows #if isinstance(item, edit_windows.TopLevelBase): if node.parent is self.root: self._show_menu.SetTitle(item.name) self.PopupMenu(self._show_menu, event.GetPosition()) return try: x, y = self.ClientToScreen(event.GetPosition()) x, y = item.widget.ScreenToClient((x, y)) event.m_x, event.m_y = x, y item.popup_menu(event) except AttributeError: import traceback; traceback.print_exc() def expand(self, node=None, yes=True): """\ expands or collapses the given node """ if node is None: node = self.root if yes: self.Expand(node.item) else: self.Collapse(node.item) def set_title(self, value): if value is None: value = "" self.title = value try: self.GetParent().SetTitle(_('wxGlade: Tree %s') % value) except: pass def get_title(self): if not self.title: self.title = ' ' return self.title def show_widget(self, node, toplevel=False): """\ Shows the widget of the given node and all its children """ if toplevel: if not wx.IsBusy(): wx.BeginBusyCursor() if not node.widget.widget: node.widget.create_widget() node.widget.finish_widget_creation() if node.children: for c in node.children: self.show_widget(c) node.widget.post_load() node.widget.show_widget(True) node.widget.show_properties() node.widget.widget.Raise() # set the best size for the widget (if no one is given) props = node.widget.properties if 'size' in props and not props['size'].is_active() and \ node.widget.sizer: node.widget.sizer.fit_parent() if wx.IsBusy(): wx.EndBusyCursor() else: import edit_sizers def show_rec(node): node.widget.show_widget(True) self.expand(node, True) if node.children: for c in node.children: show_rec(c) node.widget.post_load() ## w = node.widget ## if isinstance(w, edit_sizers.SizerBase): return ## elif not w.properties['size'].is_active() and \ ## w.sizer and w.sizer.toplevel: ## w.sizer.fit_parent() show_rec(node) def show_toplevel(self, event): """\ Event handler for left double-clicks: if the click is above a toplevel widget and this is hidden, shows it """ try: x, y = event.GetPosition() except AttributeError: # if we are here, event is a CommandEvent and not a MouseEvent node = self.GetPyData(self.GetSelection()) self.expand(node) # if we are here, the widget must be shown else: node = self._find_item_by_pos(x, y, True) if node is not None: if not node.widget.is_visible(): # added by rlawson to expand node on showing top level widget self.expand(node) self.show_widget(node, True) else: node.widget.show_widget(False) #self.select_item(self.root) # added by rlawson to collapse only the toplevel node, # not collapse back to root node self.select_item(node) self.app.show_properties() event.Skip() #event.Skip() def _find_item_by_pos(self, x, y, toplevels_only=False): """\ Finds the node which is displayed at the given coordinates. Returns None if there's no match. If toplevels_only is True, scans only root's children """ item, flags = self.HitTest((x, y)) if item and flags & (wx.TREE_HITTEST_ONITEMLABEL | wx.TREE_HITTEST_ONITEMICON): node = self.GetPyData(item) if not toplevels_only or node.parent is self.root: return node return None def change_node(self, node, widget): Tree.change_node(self, node, widget) self.SetItemImage(node.item, self.images.get( widget.__class__.__name__, -1)) self.SetItemText(node.item, self._build_label(node)) #widget.name) def change_node_pos(self, node, new_pos): if new_pos >= self.GetChildrenCount(node.parent.item, False): return index = node.parent.children.index(node) Tree.change_node_pos(self, node, new_pos, index) old_item = node.item image = self.GetItemImage(node.item) self.Freeze() #print self._build_label(node), index, new_pos if index >= new_pos: node.item = self.InsertItemBefore( node.parent.item, new_pos, self._build_label(node), image) else: node.item = self.InsertItemBefore( node.parent.item, new_pos+1, self._build_label(node), image) self.SetPyData(node.item, node) def append(parent, node): idx = WidgetTree.images.get(node.widget.__class__.__name__, -1) node.item = self.AppendItem(parent.item, self._build_label(node), idx) self.SetPyData(node.item, node) if node.children: for c in node.children: append(node, c) self.Expand(node.item) if node.children: for c in node.children: append(node, c) self.Expand(node.item) self.Delete(old_item) self.Thaw() def get_selected_path(self): """\ returns a list of widget names, from the toplevel to the selected one Example: ['frame_1', 'sizer_1', 'panel_1', 'sizer_2', 'button_1'] if button_1 is the currently selected widget. """ from edit_sizers import SizerBase ret = [] w = self.cur_widget oldw = None while w is not None: oldw = w ret.append(w.name) sizer = getattr(w, 'sizer', None) if getattr(w, 'parent', "") is None: w = w.parent elif sizer is not None and not sizer.is_virtual(): w = sizer else: if isinstance(w, SizerBase): w = w.window else: w = w.parent ret.reverse() # ALB 2007-08-28: remember also the position of the toplevel window in # the selected path if oldw is not None: assert oldw.widget pos = misc.get_toplevel_parent(oldw.widget).GetPosition() ret[0] = (ret[0], pos) return ret def select_path(self, path): """\ sets the selected widget from a path_list, which should be in the form returned by get_selected_path """ index = 0 item, cookie = self._get_first_child(self.GetRootItem()) itemok = None parent = None pos = None while item.Ok() and index < len(path): widget = self.GetPyData(item).widget name = path[index] if index == 0 and type(name) == type(()): name, pos = name if misc.streq(widget.name, name): #print 'OK:', widget.name #self.EnsureVisible(item) itemok = item if parent is None: parent = self.GetPyData(itemok) self.cur_widget = widget item, cookie = self._get_first_child(item) index += 1 else: #print 'NO:', widget.name item = self.GetNextSibling(item) if itemok is not None: node = self.GetPyData(itemok) if parent is not None: self.show_widget(parent, True) if pos is not None: misc.get_toplevel_parent(parent.widget).SetPosition(pos) self.select_item(node) def _get_first_child(self, item): if misc.check_wx_version(2, 5): return self.GetFirstChild(item) else: return self.GetFirstChild(item, 1) # end of class WidgetTree spe-0.8.4.h/_spe/plugins/wxGlade/epydoc.conf0000644000175000017500000000224010743421035017707 0ustar stanistani#epydoc.conf - configuration file for epydoc used to generate the developer documentation for wxGlade # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/epydoc.conf,v 1.1 2006/10/14 10:52:57 guyru Exp $ [epydoc] # Epydoc section marker (required by ConfigParser) # Information about the project. name: wxGlade url: http://wxglade.sourceforge.net/ # The list of modules to document. Modules can be named using # dotted names, module filenames, or package directory names. # This option may be repeated. modules: ./ # Write html output to the directory "apidocs" output: html target: htmldocs/ # imports # Whether or not to list each module's imports. imports: yes # parse # Whether or not parsing should be used to examine objects. parse: yes # introspect # Whether or not introspection should be used to examine objects. introspect: no #for some reason using introspect creates many errors - Guy # graph # The list of graph types that should be automatically included # in the output. Graphs are generated using the Graphviz "dot" # executable. Graph types include: "classtree", "callgraph", # "umlclass". Use "all" to include all graph types graph: all spe-0.8.4.h/_spe/plugins/wxGlade/application.py0000644000175000017500000005721710743421035020450 0ustar stanistani# application.py: Application class to store properties of the application # being created # $Id: application.py,v 1.64 2007/08/07 12:13:44 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from widget_properties import * from tree import Tree, WidgetTree import common, math, misc, os, config import traceback, re class FileDirDialog: """\ Custom class which displays a FileDialog or a DirDialog, according to the value of the codegen_opt of its parent (instance of Application) """ def __init__(self, owner, parent, wildcard=_("All Files|*"), file_message=_("Choose a file"), dir_message=None, style=0): self.owner = owner self.prev_dir = config.preferences.codegen_path self.wildcard = wildcard self.file_message = file_message self.dir_message = dir_message self.file_style = style self.dir_style = wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON self.parent = parent self.value = None def ShowModal(self): if self.owner.codegen_opt == 0: self.value = misc.FileSelector( self.file_message, self.prev_dir or "", wildcard=self.wildcard, flags=self.file_style) else: self.value = misc.DirSelector( self.dir_message, self.prev_dir or "", style=self.dir_style) if self.value: self.prev_dir = self.value if not os.path.isdir(self.prev_dir): self.prev_dir = os.path.dirname(self.prev_dir) return wx.ID_OK return wx.ID_CANCEL def get_value(self): return self.value def set_wildcard(self, wildcard): self.wildcard = wildcard # end of class FileDirDialog class Application(object): """\ properties of the application being created """ def __init__(self, property_window): self.property_window = property_window self.notebook = wx.Notebook(self.property_window, -1) if not misc.check_wx_version(2, 5, 2): nb_sizer = wx.NotebookSizer(self.notebook) self.notebook.sizer = nb_sizer else: self.notebook.sizer = None self.notebook.SetAutoLayout(True) self.notebook.Hide() panel = wx.ScrolledWindow( self.notebook, -1, style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE) self.name = "app" # name of the wxApp instance to generate self.__saved = True # if True, there are no changes to save self.__filename = None # name of the output xml file self.klass = "MyApp" self.codegen_opt = 0 # if != 0, generates a separate file # for each class def set_codegen_opt(value): try: opt = int(value) except ValueError: pass else: self.codegen_opt = opt self.output_path = "" self.language = 'python' # output language def get_output_path(): return os.path.expanduser(self.output_path) def set_output_path(value): self.output_path = value self.is_template = False self.use_gettext = False def set_use_gettext(value): self.use_gettext = bool(int(value)) self.for_version = wx.VERSION_STRING[:3] def set_for_version(value): self.for_version = self.for_version_prop.get_str_value() self.access_functions = { 'name': (lambda : self.name, self.set_name), 'class': (lambda : self.klass, self.set_klass), 'code_generation': (lambda : self.codegen_opt, set_codegen_opt), 'output_path': (get_output_path, set_output_path), 'language': (self.get_language, self.set_language), 'encoding': (self.get_encoding, self.set_encoding), 'use_gettext': (lambda : self.use_gettext, set_use_gettext), 'for_version': (lambda : self.for_version, set_for_version), } self.name_prop = TextProperty(self, "name", panel, True) self.klass_prop = TextProperty(self, "class", panel, True) self.encoding = self._get_default_encoding() self.encoding_prop = TextProperty(self, 'encoding', panel) self.use_gettext_prop = CheckBoxProperty(self, "use_gettext", panel, _("Enable gettext support")) TOP_WIN_ID = wx.NewId() self.top_win_prop = wx.Choice(panel, TOP_WIN_ID, choices=[], size=(1, -1)) self.top_window = '' # name of the top window of the generated app self.codegen_prop = RadioProperty(self, "code_generation", panel, [_("Single file"), _("Separate file for" \ " each class")], label=_("Code Generation")) ext = getattr(common.code_writers.get('python'), 'default_extensions', []) wildcard = [] for e in ext: wildcard.append('%s files (*.%s)|*.%s' % ('Python', e, e)) wildcard.append('All files|*') dialog = FileDirDialog(self, panel, '|'.join(wildcard), _("Select output file"), _("Select output directory"), wx.SAVE|wx.OVERWRITE_PROMPT) _writers = common.code_writers.keys() columns = 3 self.codewriters_prop = RadioProperty(self, "language", panel, _writers, columns=columns) self.codewriters_prop.set_str_value('python') self.for_version_prop = RadioProperty(self, "for_version", panel, ['2.4', '2.6', '2.8'], columns=3, label=_("wxWidgets compatibility")) self.for_version_prop.set_str_value(self.for_version) # ALB 2004-01-18 self.access_functions['use_new_namespace'] = ( self.get_use_old_namespace, self.set_use_old_namespace) self.use_old_namespace_prop = CheckBoxProperty( self, 'use_new_namespace', panel, _('Use old "from wxPython.wx"\n' 'import (python output only)')) # `overwrite' property - added 2003-07-15 self.overwrite = False def get_overwrite(): return self.overwrite def set_overwrite(val): self.overwrite = bool(int(val)) self.access_functions['overwrite'] = (get_overwrite, set_overwrite) self.overwrite_prop = CheckBoxProperty(self, 'overwrite', panel, _('Overwrite existing sources')) self.outpath_prop = DialogProperty(self, "output_path", panel, dialog, label=_('Output path')) BTN_ID = wx.NewId() btn = wx.Button(panel, BTN_ID, _("Generate code")) # layout of self.notebook sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name_prop.panel, 0, wx.EXPAND) sizer.Add(self.klass_prop.panel, 0, wx.EXPAND) sizer.Add(self.encoding_prop.panel, 0, wx.EXPAND) sizer.Add(self.use_gettext_prop.panel, 0, wx.EXPAND) szr = wx.BoxSizer(wx.HORIZONTAL) from widget_properties import _label_initial_width as _w label = wx.StaticText(panel, -1, _("Top window"), size=(_w, -1)) label.SetToolTip(wx.ToolTip(_("Top window"))) szr.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) szr.Add(self.top_win_prop, 5, wx.ALL|wx.ALIGN_CENTER, 3) sizer.Add(szr, 0, wx.EXPAND) sizer.Add(self.codegen_prop.panel, 0, wx.ALL|wx.EXPAND, 4) sizer.Add(self.codewriters_prop.panel, 0, wx.ALL|wx.EXPAND, 4) sizer.Add(self.for_version_prop.panel, 0, wx.ALL|wx.EXPAND, 4) sizer.Add(self.use_old_namespace_prop.panel, 0, wx.EXPAND) sizer.Add(self.overwrite_prop.panel, 0, wx.EXPAND) sizer.Add(self.outpath_prop.panel, 0, wx.EXPAND) sizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(sizer) sizer.Layout() sizer.Fit(panel) h = panel.GetSize()[1] self.notebook.AddPage(panel, _("Application")) import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) wx.EVT_BUTTON(btn, BTN_ID, self.generate_code) wx.EVT_CHOICE(self.top_win_prop, TOP_WIN_ID, self.set_top_window) # this is here to keep the interface similar to the various widgets # (to simplify Tree) self.widget = None # this is always None def set_name(self, value): value = "%s" % value if not re.match(self.set_name_pattern, value): self.name_prop.set_value(self.name) else: self.name = value set_name_pattern = re.compile('^[a-zA-Z]+[\w0-9-]*$') def set_klass(self, value): value = "%s" % value if not re.match(self.set_klass_pattern, value): self.klass_prop.set_value(self.klass) else: self.klass = value set_klass_pattern = re.compile('^[a-zA-Z]+[\w:.0-9-]*$') def _get_default_encoding(self): """\ Returns the name of the default character encoding of this machine """ import locale locale.setlocale(locale.LC_ALL) try: return locale.nl_langinfo(locale.CODESET) except AttributeError: return 'ISO-8859-15' # this is what I use... def get_encoding(self): return self.encoding def set_encoding(self, value): try: unicode('a', value) except LookupError, e: wx.MessageBox(str(e), _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) self.encoding_prop.set_value(self.encoding) else: self.encoding = value def set_language(self, value): language = self.codewriters_prop.get_str_value() ext = getattr(common.code_writers[language], 'default_extensions', []) wildcard = [] for e in ext: wildcard.append(_('%s files (*.%s)|*.%s') % (language.capitalize(), e, e)) wildcard.append(_('All files|*')) self.outpath_prop.dialog.set_wildcard('|'.join(wildcard)) # check that the new language supports all the widgets in the tree if self.language != language: self.language = language self.check_codegen() def get_language(self): return self.language #codewriters_prop.get_str_value() def _get_saved(self): return self.__saved def _set_saved(self, value): if self.__saved != value: self.__saved = value t = common.app_tree.get_title().strip() if not value: common.app_tree.set_title('* ' + t) else: if t[0] == '*': common.app_tree.set_title(t[1:].strip()) saved = property(_get_saved, _set_saved) def _get_filename(self): return self.__filename def _set_filename(self, value): if not misc.streq(self.__filename, value): self.__filename = value if self.__saved: flag = ' ' else: flag = '* ' if self.__filename is not None: common.app_tree.set_title('%s(%s)' % (flag, self.__filename)) else: common.app_tree.set_title(flag) filename = property(_get_filename, _set_filename) def get_top_window(self): return self.top_window def set_top_window(self, *args): self.top_window = self.top_win_prop.GetStringSelection() def add_top_window(self, name): self.top_win_prop.Append("%s" % name) if not self.top_window: self.top_win_prop.SetSelection(self.top_win_prop.GetCount()-1) self.set_top_window() def remove_top_window(self, name): index = self.top_win_prop.FindString("%s" % name) if index != -1: if wx.Platform == '__WXGTK__': choices = [ self.top_win_prop.GetString(i) for i in \ range(self.top_win_prop.GetCount()) if i != index ] self.top_win_prop.Clear() for c in choices: self.top_win_prop.Append(c) else: self.top_win_prop.Delete(index) def update_top_window_name(self, oldname, newname): index = self.top_win_prop.FindString(oldname) if index != -1: if self.top_window == oldname: self.top_window = newname if wx.Platform == '__WXGTK__': sel_index = self.top_win_prop.GetSelection() choices = [ self.top_win_prop.GetString(i) for i in \ range(self.top_win_prop.GetCount()) ] choices[index] = newname self.top_win_prop.Clear() for c in choices: self.top_win_prop.Append(c) self.top_win_prop.SetSelection(sel_index) else: self.top_win_prop.SetString(index, newname) def reset(self): """\ resets the default values of the attributes of the app """ self.klass = "MyApp"; self.klass_prop.set_value("MyApp") self.klass_prop.toggle_active(False) self.name = "app"; self.name_prop.set_value("app") self.name_prop.toggle_active(False) self.codegen_opt = 0; self.codegen_prop.set_value(0) self.output_path = ""; self.outpath_prop.set_value("") # do not reset language, but call set_language anyway to update the # wildcard of the file dialog self.set_language(self.get_language()) self.top_window = '' self.top_win_prop.Clear() # ALB 2004-01-18 #self.set_use_new_namespace(True) #self.use_new_namespace_prop.set_value(True) self.set_use_old_namespace(False) self.use_old_namespace_prop.set_value(False) def show_properties(self, *args): sizer_tmp = self.property_window.GetSizer() child = sizer_tmp.GetChildren()[0] w = child.GetWindow() if w is self.notebook: return w.Hide() self.notebook.Reparent(self.property_window) child.SetWindow(self.notebook) w.Reparent(misc.hidden_property_panel) self.notebook.Show(True) self.property_window.Layout() self.property_window.SetTitle(_('Properties - <%s>') % self.name) try: common.app_tree.select_item(self.node) except AttributeError: pass def __getitem__(self, name): return self.access_functions[name] def generate_code(self, *args, **kwds): preview = kwds.get('preview', False) if not self.output_path: return wx.MessageBox(_("You must specify an output file\n" "before generating any code"), _("Error"), wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION, self.notebook) if not preview and \ ((self.name_prop.is_active() or self.klass_prop.is_active()) \ and self.top_win_prop.GetSelection() < 0): return wx.MessageBox(_("Please select a top window " "for the application"), _("Error"), wx.OK | wx.CENTRE | wx.ICON_EXCLAMATION, self.notebook) from cStringIO import StringIO out = StringIO() #common.app_tree.write(out) # write the xml onto a temporary buffer from xml_parse import CodeWriter try: # generate the code from the xml buffer cw = self.get_language() #self.codewriters_prop.get_str_value() if preview and cw == 'python': # of course cw == 'python', but... old = common.code_writers[cw].use_new_namespace common.code_writers[cw].use_new_namespace = True #False overwrite = self.overwrite self.overwrite = True class_names = common.app_tree.write(out) # write the xml onto a # temporary buffer if not os.path.isabs(self.output_path) and \ self.filename is not None: out_path = os.path.join(os.path.dirname(self.filename), self.output_path) else: out_path = None CodeWriter(common.code_writers[cw], out.getvalue(), True, preview=preview, out_path=out_path, class_names=class_names) if preview and cw == 'python': common.code_writers[cw].use_new_namespace = old self.overwrite = overwrite except (IOError, OSError), msg: wx.MessageBox(_("Error generating code:\n%s") % msg, _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) except Exception, msg: import traceback; traceback.print_exc() wx.MessageBox(_("An exception occurred while generating the code " "for the application.\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback " "on the console.\nIf you think this is a wxGlade bug," " please report it.") % msg, _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) else: if not preview: wx.MessageBox(_("Code generation completed successfully"), _("Information"), wx.OK|wx.CENTRE|wx.ICON_INFORMATION) def get_name(self): if self.name_prop.is_active(): return self.name return '' def get_class(self): if self.klass_prop.is_active(): return self.klass return '' def update_view(self, *args): pass def is_visible(self): return True def preview(self, widget, out_name=[None]): if out_name[0] is None: import warnings warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, "application") out_name[0] = os.tempnam(None, 'wxg') + '.py' #print 'Temporary name:', out_name[0] widget_class_name = widget.klass # make a valid name for the class (this can be invalid for # some sensible reasons...) widget.klass = widget.klass[widget.klass.rfind('.')+1:] widget.klass = widget.klass[widget.klass.rfind(':')+1:] #if widget.klass == widget.base: # ALB 2003-11-08: always randomize the class name: this is to make # preview work even when there are multiple classes with the same name # (which makes sense for XRC output...) import random widget.klass = '_%d_%s' % \ (random.randrange(10**8, 10**9), widget.klass) self.real_output_path = self.output_path self.output_path = out_name[0] real_codegen_opt = self.codegen_opt real_language = self.language real_use_gettext = self.use_gettext self.use_gettext = False self.language = 'python' self.codegen_opt = 0 overwrite = self.overwrite self.overwrite = 0 frame = None try: self.generate_code(preview=True) # dynamically import the generated module FrameClass = misc.import_name(self.output_path, widget.klass) if issubclass(FrameClass, wx.MDIChildFrame): frame = wx.MDIParentFrame(None, -1, '') child = FrameClass(frame, -1, '') child.SetTitle(' - ' + child.GetTitle()) w, h = child.GetSize() frame.SetClientSize((w+20, h+20)) elif not (issubclass(FrameClass, wx.Frame) or issubclass(FrameClass, wx.Dialog)): # the toplevel class isn't really toplevel, add a frame... frame = wx.Frame(None, -1, widget_class_name) if issubclass(FrameClass, wx.MenuBar): menubar = FrameClass() frame.SetMenuBar(menubar) elif issubclass(FrameClass, wx.ToolBar): toolbar = FrameClass(frame, -1) frame.SetToolBar(toolbar) else: panel = FrameClass(frame, -1) frame.Fit() else: frame = FrameClass(None, -1, '') # make sure we don't get a modal dialog... s = frame.GetWindowStyleFlag() frame.SetWindowStyleFlag(s & ~wx.DIALOG_MODAL) def on_close(event): frame.Destroy() widget.preview_widget = None widget.preview_button.SetLabel(_('Preview')) wx.EVT_CLOSE(frame, on_close) frame.SetTitle(_(' - %s') % frame.GetTitle()) # raise the frame frame.CenterOnScreen() frame.Show() # remove the temporary file (and the .pyc/.pyo ones too) for ext in '', 'c', 'o', '~': name = self.output_path + ext if os.path.isfile(name): os.unlink(name) except Exception, e: #traceback.print_exc() widget.preview_widget = None widget.preview_button.SetLabel(_('Preview')) wx.MessageBox(_("Problem previewing gui: %s") % str(e), _("Error"), wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION)#, self.notebook) # restore app state widget.klass = widget_class_name self.output_path = self.real_output_path del self.real_output_path self.codegen_opt = real_codegen_opt self.language = real_language self.use_gettext = real_use_gettext self.overwrite = overwrite return frame def get_use_old_namespace(self): try: return not common.code_writers['python'].use_new_namespace except: return False def set_use_old_namespace(self, val): #print "set use old namespace" try: common.code_writers['python'].use_new_namespace = not bool(int(val)) except: pass def check_codegen(self, widget=None, language=None): """\ Checks whether widget has a suitable code generator for the given language (default: the current active language). If not, the user is informed with a message. """ if language is None: language = self.language if widget is not None: cname = common.class_names[widget.__class__.__name__] if language != 'XRC': ok = cname in common.code_writers[language].obj_builders else: # xrc is special... xrcgen = common.code_writers['XRC'] ok = xrcgen.obj_builders.get(cname, None) is not \ xrcgen.NotImplementedXrcObject if not ok: common.message(_('WARNING'), _('No %s code generator for %s (of type %s)' ' available'), language.capitalize(), widget.name, cname) else: # in this case, we check all the widgets in the tree def check_rec(node): if node.widget is not None: self.check_codegen(node.widget) if node.children: for c in node.children: check_rec(c) if common.app_tree.root.children: for c in common.app_tree.root.children: check_rec(c) # end of class Application spe-0.8.4.h/_spe/plugins/wxGlade/common.py0000644000175000017500000003301010743421035017416 0ustar stanistani# common.py: global variables # $Id: common.py,v 1.61 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import os # if False, the program is invoked from the command-line in "batch" mode (for # code generation only) use_gui = True # version identification string version = '0.6.2' # program path, set in wxglade.py wxglade_path = '.' # widgets dictionary: each key is the name of some EditWidget class; the mapped # value is a 'factory' function which actually builds the object. Each of these # functions accept 3 parameters: the parent of the widget, the sizer by which # such widget is controlled, and the position inside this sizer. widgets = {} # widgets_from_xml dictionary: table of factory functions to build objects from # an xml file widgets_from_xml = {} # property_panel wxPanel: container inside which Properties of the current # focused widget are displayed property_panel = None # app_tree Tree: represents the widget hierarchy of the application; the root # is the application itself app_tree = None # if True, the user is adding a widget to some sizer adding_widget = False # needed to add toplevel sizers adding_sizer = False # reference to the widget that is being added: this is a key in the # 'widgets' dictionary widget_to_add = None # reference to the main window (the one which contains the various buttons to # add the different widgets) palette = None # dictionary which maps the ids used in the event handlers to the # corresponding widgets: used to call the appropriate builder function # when a dropping of a widget occurs, knowing only the id of the event refs = {} # dictionary which maps the name of the classes used by wxGlade to the # correspondent classes of wxWindows class_names = {} # names of the Edit* classes that can be toplevels, i.e. widgets for which to # generate a class declaration in the code toplevels = {} # dictionary of objects used to generate the code in a given language. # NOTE: a code writer object must implement this interface: # - initialize(out_path, multi_files) # - language # - add_widget_handler(widget_name, handler[, properties_handler]) # - add_property_handler(property_name, handler[, widget_name]) # - add_object(top_obj, sub_obj) # - add_class(obj) # - add_sizeritem(toplevel, sizer, obj_name, option, flag, border) # - add_app(app_attrs, top_win_class) # - ... code_writers = {} def load_code_writers(): """\ Fills the common.code_writers dictionary: to do so, loads the modules found in the 'codegen/' subdir """ import sys codegen_path = os.path.join(wxglade_path, 'codegen') sys.path.insert(0, codegen_path) for module in os.listdir(codegen_path): name, ext = os.path.splitext(module) if name not in sys.modules and \ os.path.isfile(os.path.join(codegen_path, module)): try: writer = __import__(name).writer except (ImportError, AttributeError, ValueError): if use_gui: print _('"%s" is not a valid code generator module') % \ module else: code_writers[writer.language] = writer if hasattr(writer, 'setup'): writer.setup() if use_gui: print _('loaded code generator for %s') % writer.language def load_widgets(): """\ Scans the 'widgets/' directory to find the installed widgets, and returns 2 lists of buttons to handle them: the first contains the ``core'' components, the second the user-defined ones """ import config buttons = [] # load the "built-in" widgets built_in_dir = os.path.join(wxglade_path, 'widgets') buttons.extend(__load_widgets(built_in_dir)) # load the "local" widgets local_widgets_dir = config.preferences.local_widget_path return buttons, __load_widgets(local_widgets_dir) def __load_widgets(widget_dir): buttons = [] # test if the "widgets.txt" file exists widgets_file = os.path.join(widget_dir, 'widgets.txt') if not os.path.isfile(widgets_file): return buttons # add the dir to the sys.path import sys sys.path.append(widget_dir) modules = open(widgets_file) if use_gui: print _('Found widgets listing -> %s') % widgets_file print _('loading widget modules:') for line in modules: module = line.strip() if not module or module.startswith('#'): continue module = module.split('#')[0].strip() try: try: b = __import__(module).initialize() except ImportError: # try importing from a zip archive if os.path.exists(os.path.join(widget_dir, module + '.zip')): sys.path.append(os.path.join(widget_dir, module + '.zip')) try: b = __import__(module).initialize() finally: sys.path.pop() else: raise except (ImportError, AttributeError): if use_gui: print _('ERROR loading "%s"') % module import traceback; traceback.print_exc() else: if use_gui: print '\t' + module buttons.append(b) modules.close() return buttons def load_sizers(): import edit_sizers return edit_sizers.init_all() def add_object(event): """\ Adds a widget or a sizer to the current app. """ global adding_widget, adding_sizer, widget_to_add adding_widget = True adding_sizer = False tmp = event.GetId() widget_to_add = refs[tmp] # TODO: find a better way if widget_to_add.find('Sizer') != -1: adding_sizer = True def add_toplevel_object(event): """\ Adds a toplevel widget (Frame or Dialog) to the current app. """ widgets[refs[event.GetId()]](None, None, 0) app_tree.app.saved = False # function used by the various widget modules to add a button to the widgets # toolbar def make_object_button(widget, icon_path, toplevel=False, tip=None): """\ creates a button for the widgets toolbar. Params: - widget: (name of) the widget the button will add to the app - icon_path: path to the icon used for the button - toplevel: true if the widget is a toplevel object (frame, dialog) - tip: tool tip to display Returns: the newly created wxBitmapButton """ #from wxPython import wx import wx from tree import WidgetTree id = wx.NewId() if not os.path.isabs(icon_path): icon_path = os.path.join(wxglade_path, icon_path) if wx.Platform == '__WXGTK__': style = wx.NO_BORDER else: style = wx.BU_AUTODRAW import misc bmp = misc.get_xpm_bitmap(icon_path) tmp = wx.BitmapButton(palette, id, bmp, size=(31, 31), style=style) if not toplevel: wx.EVT_BUTTON(tmp, id, add_object) else: wx.EVT_BUTTON(tmp, id, add_toplevel_object) refs[id] = widget if not tip: tip = _('Add a %s') % widget.replace(_('Edit'), '') tmp.SetToolTip(wx.ToolTip(tip)) WidgetTree.images[widget] = icon_path # add support for ESC key. We bind the handler to the button, because # (at least on GTK) EVT_CHAR are not generated for wxFrame objects... def on_char(event): #print 'on_char' if event.HasModifiers() or event.GetKeyCode() != wx.WXK_ESCAPE: event.Skip() return global adding_widget, adding_sizer, widget_to_add adding_widget = False adding_sizer = False widget_to_add = None import misc if misc._currently_under_mouse is not None: misc._currently_under_mouse.SetCursor(wx.STANDARD_CURSOR) event.Skip() wx.EVT_CHAR(tmp, on_char) return tmp def _encode_from_xml(label, encoding=None): """\ Returns a str which is the encoded version of the unicode label """ if encoding is None: encoding = app_tree.app.encoding return label.encode(encoding, 'replace') def _encode_to_xml(label, encoding=None): """\ returns a utf-8 encoded representation of label. This is equivalent to: str(label).decode(encoding).encode('utf-8') """ if encoding is None: encoding = app_tree.app.encoding if type(label) == type(u''): return label.encode('utf-8') return str(label).decode(encoding).encode('utf-8') _backed_up = {} # set of filenames already backed up during this session def save_file(filename, content, which='wxg'): """\ Saves 'filename' and, if user's preferences say so and 'filename' exists, makes a backup copy of it. Exceptions that may occur while performing the operations are not handled. 'content' is the string to store into 'filename' 'which' is the kind of backup: 'wxg' or 'codegen' """ import os, os.path, config if which == 'wxg': ok = config.preferences.wxg_backup else: ok = config.preferences.codegen_backup try: if ok and filename not in _backed_up and os.path.isfile(filename): # make a backup copy of filename infile = open(filename) outfile = open(filename + config.preferences.backup_suffix, 'w') outfile.write(infile.read()) infile.close() outfile.close() _backed_up[filename] = 1 # save content to file (but only if content has changed) savecontent = 1 if os.path.isfile(filename): oldfile = open(filename) savecontent = (oldfile.read() != content) oldfile.close() if savecontent: if not os.path.isdir(os.path.dirname(filename)): os.mkdir(os.path.dirname(filename)) outfile = open(filename, 'w') outfile.write(content) outfile.close() finally: if 'infile' in locals(): infile.close() if 'outfile' in locals(): outfile.close() if 'oldfile' in locals(): oldfile.close() #------------------------------------------------------------------------------ # Autosaving, added 2004-10-15 #------------------------------------------------------------------------------ def get_name_for_autosave(filename=None): if filename is None: filename = app_tree.app.filename if not filename: import config path, name = config._get_home(), "" else: path, name = os.path.split(filename) ret = os.path.join(path, "#~wxg.autosave~%s#" % name) return ret def autosave_current(): if app_tree.app.saved: return False # do nothing in this case... try: outfile = open(get_name_for_autosave(), 'w') app_tree.write(outfile) outfile.close() except Exception, e: print e return False return True def remove_autosaved(filename=None): autosaved = get_name_for_autosave(filename) if os.path.exists(autosaved): try: os.unlink(autosaved) except OSError, e: print e def check_autosaved(filename): """\ Returns True iff there are some auto saved data for filename """ if filename is not None and filename == app_tree.app.filename: # this happens when reloading, no autosave-restoring in this case... return False autosaved = get_name_for_autosave(filename) try: if filename: orig = os.stat(filename) auto = os.stat(autosaved) return orig.st_mtime < auto.st_mtime else: return os.path.exists(autosaved) except OSError, e: if e.errno != 2: print e return False def restore_from_autosaved(filename): autosaved = get_name_for_autosave(filename) # when restoring, make a backup copy (if user's preferences say so...) if os.access(autosaved, os.R_OK): try: save_file(filename, open(autosaved).read(), 'wxg') except OSError, e: print e return False return True return False def generated_from(): import config if config.preferences.write_generated_from and app_tree.app.filename: return ' from "' + app_tree.app.filename + '"' return "" class MessageLogger(object): def __init__(self): self.disabled = False self.lines = [] self.logger = None def _setup_logger(self): import msgdialog self.logger = msgdialog.MessageDialog(None, -1, "") self.logger.msg_list.InsertColumn(0, "") def __call__(self, kind, fmt, *args): if self.disabled: return kind = kind.upper() if use_gui: import wx, misc if args: msg = misc.wxstr(fmt) % tuple([misc.wxstr(a) for a in args]) else: msg = misc.wxstr(fmt) self.lines.extend(msg.splitlines()) ## if kind == 'WARNING': ## wx.LogWarning(msg) ## else: ## wx.LogMessage(msg) else: if args: msg = fmt % tuple(args) else: msg = fmt print "%s: %s" % (kind, msg) def flush(self): if self.lines and use_gui: if not self.logger: self._setup_logger() self.logger.msg_list.Freeze() self.logger.msg_list.DeleteAllItems() for line in self.lines: self.logger.msg_list.Append([line]) self.lines = [] self.logger.msg_list.SetColumnWidth(0, -1) self.logger.msg_list.Thaw() self.logger.ShowModal() # end of class MessageLogger message = MessageLogger() spe-0.8.4.h/_spe/plugins/wxGlade/misc.py0000644000175000017500000003733710743421035017101 0ustar stanistani# misc.py: Miscellaneus stuff, used in many parts of wxGlade # $Id: misc.py,v 1.47 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * import wx if wx.Platform == '__WXMSW__': class wxGladeRadioButton(wx.RadioButton): """ custom wxRadioButton class which tries to implement a better GetBestSize than the default one for WXMSW (mostly copied from wxCheckBox::DoGetBestSize in checkbox.cpp) """ __radio_size = None def GetBestSize(self): if not self.__radio_size: dc = wx.ScreenDC() dc.SetFont(wx.SystemSettings_GetFont( wx.SYS_DEFAULT_GUI_FONT)) self.__radio_size = (3*dc.GetCharHeight())/2 label = self.GetLabel() if label: w, h = self.GetTextExtent(label) w += self.__radio_size + self.GetCharWidth() if h < self.__radio_size: h = self.__radio_size else: w = h = self.__radio_size; return w, h # end of class wxGladeRadioButton else: wxGladeRadioButton = wx.RadioButton # ALB 2004-10-27 FileSelector = wx.FileSelector DirSelector = wx.DirSelector #--------------------- Selection Markers ---------------------------------- class SelectionTag(wx.Window): """\ This is one of the small black squares that appear at the corners of the active widgets """ def __init__(self, parent, pos=None): kwds = { 'size': (7, 7) } if pos: kwds['position'] = pos wx.Window.__init__(self, parent, -1, **kwds) self.SetBackgroundColour(wx.BLUE) #wx.BLACK) self.Hide() # end of class SelectionTag class SelectionMarker: """\ Collection of the 4 SelectionTagS for each widget """ def __init__(self, owner, parent, visible=False): self.visible = visible self.owner = owner self.parent = parent if wx.Platform == '__WXMSW__': self.parent = owner self.tag_pos = None self.tags = None #self.tags = [ SelectionTag(self.parent) for i in range(4) ] self.update() if visible: for t in self.tags: t.Show() def update(self, event=None): if self.owner is self.parent: x, y = 0, 0 else: x, y = self.owner.GetPosition() w, h = self.owner.GetClientSize() def position(j): if not j: return x, y # top-left elif j == 1: return x+w-7, y # top-right elif j == 2: return x+w-7, y+h-7 # bottom-right else: return x, y+h-7 # bottom-left ## for i in range(len(self.tags)): ## self.tags[i].SetPosition(position(i)) self.tag_pos = [ position(i) for i in range(4) ] if self.visible: if not self.tags: self.tags = [ SelectionTag(self.parent) for i in range(4) ] for i in range(4): self.tags[i].SetPosition(self.tag_pos[i]) if event: event.Skip() def Show(self, visible): ## self.visible = visible ## for tag in self.tags: tag.Show(visible) if self.visible != visible: self.visible = visible if self.visible: if not self.tags: self.tags = [ SelectionTag(self.parent) for i in range(4) ] for i in range(4): self.tags[i].SetPosition(self.tag_pos[i]) self.tags[i].Show() else: for tag in self.tags: tag.Destroy() self.tags = None def Destroy(self): if self.tags: for tag in self.tags: tag.Destroy() self.tags = None def Reparent(self, parent): self.parent = parent if self.tags: for tag in self.tags: tag.Reparent(parent) # end of class SelectionMarker #---------------------------------------------------------------------------- import common _encode = common._encode_from_xml def bound(number, lower, upper): return min(max(lower, number), upper) def color_to_string(color): """\ returns the hexadecimal string representation of the given color: for example: wxWHITE ==> #ffffff """ import operator return '#' + reduce(operator.add, ['%02x' % bound(c, 0, 255) for c in color.Get()]) def string_to_color(color): """\ returns the wxColour which corresponds to the given hexadecimal string representation: for example: #ffffff ==> wxColour(255, 255, 255) """ if len(color) != 7: raise ValueError return apply(wx.Colour, [int(color[i:i+2], 16) for i in range(1, 7, 2)]) def get_toplevel_parent(obj): if not isinstance(obj, wx.Window): window = obj.widget else: window = obj while window and not window.IsTopLevel(): window = window.GetParent() return window def get_toplevel_widget(widget): from edit_windows import EditBase, TopLevelBase from edit_sizers import Sizer if isinstance(widget, Sizer): widget = widget.window assert isinstance(widget, EditBase), _("EditBase or SizerBase object needed") while widget and not isinstance(widget, TopLevelBase): widget = widget.parent return widget if wx.Platform == '__WXGTK__': # default wxMenu seems to have probles with SetTitle on GTK class wxGladePopupMenu(wx.Menu): def __init__(self, title): wx.Menu.__init__(self) self.TITLE_ID = wx.NewId() item = self.Append(self.TITLE_ID, title) self.AppendSeparator() font = item.GetFont() font.SetWeight(wx.BOLD) item.SetFont(wx.Font(font.GetPointSize(), font.GetFamily(), font.GetStyle(), wx.BOLD)) def SetTitle(self, title): self.SetLabel(self.TITLE_ID, title) else: wxGladePopupMenu = wx.Menu def check_wx_version(major, minor=0, release=0, revision=0): """\ returns True if the current wxPython version is at least major.minor.release """ #from wxPython import wx import wx #return wx.__version__ >= "%d.%d.%d.%d" % (major, minor, release, revision) return wx.VERSION[:-1] >= (major, minor, release, revision) if not check_wx_version(2, 3, 3): # the following is copied from wx.py of version 2.3.3, as 2.3.2 doesn't # have it _wxCallAfterId = None def wxCallAfter(callable, *args, **kw): """ Call the specified function after the current and pending event handlers have been completed. This is also good for making GUI method calls from non-GUI threads. """ app = wxGetApp() assert app, _('No wxApp created yet') global _wxCallAfterId if _wxCallAfterId is None: _wxCallAfterId = wxNewId() app.Connect(-1, -1, _wxCallAfterId, lambda event: apply(event.callable, event.args, event.kw) ) evt = wxPyEvent() evt.SetEventType(_wxCallAfterId) evt.callable = callable evt.args = args evt.kw = kw wxPostEvent(app, evt) else: wxCallAfter = wx.CallAfter #---------------------------------------------------------------------- use_menu_icons = None _item_bitmaps = {} def append_item(menu, id, text, xpm_file_or_artid=None): global use_menu_icons if use_menu_icons is None: import config use_menu_icons = config.preferences.use_menu_icons if wx.Platform == '__WXGTK__' and wx.VERSION == (2, 4, 1, 2, ''): use_menu_icons = 0 import common, os.path item = wx.MenuItem(menu, id, text) if wx.Platform == '__WXMSW__': path = 'icons/msw/' else: path = 'icons/gtk/' path = os.path.join(common.wxglade_path, path) if use_menu_icons and xpm_file_or_artid is not None: bmp = None if not xpm_file_or_artid.startswith('wxART_'): try: bmp = _item_bitmaps[xpm_file_or_artid] except KeyError: f = os.path.join(path, xpm_file_or_artid) if os.path.isfile(f): bmp = _item_bitmaps[xpm_file_or_artid] = \ wx.Bitmap(f, wx.BITMAP_TYPE_XPM) else: bmp = None else: # xpm_file_or_artid is an id for wx.ArtProvider bmp = wx.ArtProvider.GetBitmap( xpm_file_or_artid, wx.ART_MENU, (16, 16)) if bmp is not None: try: item.SetBitmap(bmp) except AttributeError: pass menu.AppendItem(item) #----------- 2002-11-01 ------------------------------------------------------ # if not None, this is the currently selected widget - This is different from # tree.WidgetTree.cur_widget because it takes into account also SizerSlot # objects # this is an implementation hack, used to handle keyboard shortcuts for # popup menus properly (for example, to ensure that the object to remove is # the currently highlighted one, ecc...) focused_widget = None def _remove(): global focused_widget if focused_widget is not None: focused_widget.remove() focused_widget = None def _cut(): global focused_widget if focused_widget is not None: try: focused_widget.clipboard_cut() except AttributeError: pass else: focused_widget = None def _copy(): if focused_widget is not None: try: focused_widget.clipboard_copy() except AttributeError: pass def _paste(): if focused_widget is not None: try: focused_widget.clipboard_paste() except AttributeError: pass # accelerator table to enable keyboard shortcuts for the popup menus of the # various widgets (remove, cut, copy, paste) accel_table = [ (0, wx.WXK_DELETE, _remove), (wx.ACCEL_CTRL, ord('C'), _copy), (wx.ACCEL_CTRL, ord('X'), _cut), (wx.ACCEL_CTRL, ord('V'), _paste), ] #----------------------------------------------------------------------------- def _reverse_dict(src): """\ Returns a dictionary whose keys are 'src' values and values 'src' keys. """ ret = {} for key, val in src.iteritems(): ret[val] = key return ret #----------------------------------------------------------------------------- def sizer_fixed_Insert(self, *args, **kw): """\ This function fixes a bug in wxPython 2.4.0.2, which fails to call InsertSizer when the 2nd argument is a Sizer """ if type(args[1]) == type(1): apply(self.InsertSpacer, args, kw) elif isinstance(args[1], wxSizerPtr): apply(self.InsertSizer, args, kw) else: apply(self.InsertWindow, args, kw) #----- # if not None, this is the SizerSlot wich has the "mouse focus": this is used # to restore the mouse cursor if the user cancelled the addition of a widget _currently_under_mouse = None #----------------------------------------------------------------------------- def get_geometry(win): x, y = win.GetPosition() w, h = win.GetSize() if 0 <= x <= wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) and \ 0 <= y <= wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y): return (x, y, w, h) return None def set_geometry(win, geometry): if geometry is None: return try: if len(geometry) == 4: win.SetDimensions(*[int(x) for x in geometry]) else: win.SetPosition([int(x) for x in geometry]) except Exception, e: print e #----------------------------------------------------------------------------- # snagged out of the Python cookbook def import_name(module_path, name): import imp, os path, mname = os.path.split(module_path) #print 'path, mname =', path, mname mname = os.path.splitext(mname)[0] #print 'mname:', mname try: mfile, pathname, description = imp.find_module(mname, [path]) try: module = imp.load_module(mname, mfile, pathname, description) finally: mfile.close() except ImportError: import traceback; traceback.print_exc() return None return vars(module)[name] #------------------------------------------------------------------------------ # helper functions to work with a Unicode-enabled wxPython #------------------------------------------------------------------------------ def streq(s1, s2): """\ Returns True if the strings or unicode objects s1 and s2 are equal, i.e. contain the same text. Appropriate encoding/decoding are performed to make the comparison """ try: return s1 == s2 except UnicodeError: if type(s1) == type(u''): s1 = s1.encode(common.app_tree.app.encoding) else: s2 = s2.encode(common.app_tree.app.encoding) return s1 == s2 def wxstr(s, encoding=None): """\ Converts the object s to str or unicode, according to what wxPython expects """ if encoding is None: if common.app_tree is None: return str(s) else: encoding = common.app_tree.app.encoding if wx.USE_UNICODE: if type(s) != type(u''): return unicode(str(s), encoding) else: return s else: if type(s) == type(u''): return s.encode(encoding) else: return str(s) #------------------------------------------------------------------------------ # wxPanel used to reparent the property-notebooks when they are hidden. This # has been added on 2003-06-22 to fix what seems to me a (wx)GTK2 bug #------------------------------------------------------------------------------ hidden_property_panel = None #------------------------------------------------------------------------------ try: enumerate = enumerate except NameError: class enumerate(object): """\ Python 2.2.x replacement for the `enumerate' builtin. """ def __init__(self, iterable): self.iterable = iterable self.index = -1 def __iter__(self): self.iterable = iter(self.iterable) return self def next(self): val = self.iterable.next() self.index += 1 return self.index, val # end of class enumerate def design_title(title): return _(' - ') + title import re _get_xpm_bitmap_re = re.compile(r'"(?:[^"]|\\")*"') del re def get_xpm_bitmap(path): import os bmp = wx.NullBitmap if not os.path.exists(path): if '.zip' in path: import zipfile archive, name = path.split('.zip', 1) archive += '.zip' if name.startswith(os.sep): name = name.split(os.sep, 1)[1] if zipfile.is_zipfile(archive): # extract the XPM lines... try: data = zipfile.ZipFile(archive).read(name) data = [d[1:-1] for d in _get_xpm_bitmap_re.findall(data)] ## print "DATA:" ## for d in data: print d bmp = wx.BitmapFromXPMData(data) except: import traceback; traceback.print_exc() bmp = wx.NullBitmap else: bmp = wx.Bitmap(path, wx.BITMAP_TYPE_XPM) return bmp def get_relative_path(path, for_preview=False): """\ Get an absolute path relative to the current output directory (where the code is generated). """ import os if os.path.isabs(path): return path p = common.app_tree.app.output_path if for_preview: p = getattr(common.app_tree.app, 'real_output_path', '') p = common._encode_from_xml(common._encode_to_xml(p)) d = os.path.dirname(p) if d: path = os.path.join(d, path) else: path = os.path.abspath(path) return path spe-0.8.4.h/_spe/plugins/wxGlade/xrc2wxg.py0000755000175000017500000004521210743421035017544 0ustar stanistani#!/usr/bin/env python # xrc2wxg.py: Converts an XRC resource file (in a format wxGlade likes, # i.e. all windows inside sizers, no widget unknown to wxGlade, ...) into a # WXG file # $Id: xrc2wxg.py,v 1.19 2007/03/27 07:02:07 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import xml.dom.minidom import sys, getopt, os.path, time __version__ = '0.0.3' _name = 'xrc2wxg' try: True, False except NameError: True, False = 1, 0 def get_child_elems(node): def ok(n): return n.nodeType == n.ELEMENT_NODE return filter(ok, node.childNodes) def get_text_elems(node): def ok(n): return n.nodeType == n.TEXT_NODE return filter(ok, node.childNodes) _counter_name = 1 def convert(input, output): global _counter_name, _doc_encoding _counter_name = 1 document = xml.dom.minidom.parse(input) fix_fake_panels(document) set_base_classes(document) fix_properties(document) fix_widgets(document) fix_encoding(input, document) if not hasattr(output, 'write'): output = open(output, 'w') write_output(document, output) output.close() else: write_output(document, output) def write_output(document, output): """\ This code has been adapted from XRCed 0.0.7-3. Many thanks to its author Roman Rolinsky. """ dom_copy = xml.dom.minidom.Document() def indent(node, level=0): # Copy child list because it will change soon children = node.childNodes[:] # Main node doesn't need to be indented if level: text = dom_copy.createTextNode('\n' + ' ' * level) node.parentNode.insertBefore(text, node) if children: # Append newline after last child, except for text nodes if children[-1].nodeType == xml.dom.minidom.Node.ELEMENT_NODE: text = dom_copy.createTextNode('\n' + ' ' * level) node.appendChild(text) # Indent children which are elements for n in children: if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE: indent(n, level + 1) comment = dom_copy.createComment(' generated by %s %s on %s ' % (_name, __version__, time.asctime())) dom_copy.appendChild(comment) main_node = dom_copy.appendChild(document.documentElement) indent(main_node) comment_done = False for line in dom_copy.toxml().encode('utf-8').splitlines(): if not comment_done and line.startswith('', '-->\n\n') comment_done = True if line.strip(): output.write(line) output.write('\n') dom_copy.unlink() def set_base_classes(document): for elem in document.getElementsByTagName('object'): klass = elem.getAttribute('class') if klass.startswith('wx'): elem.setAttribute('base', 'Edit' + klass[2:]) name = elem.getAttribute('name') if not name: global _counter_name elem.setAttribute('name', 'object_%s' % _counter_name) _counter_name += 1 _props = { 'bg': 'background', 'fg': 'foreground', 'content': 'choices', 'item': 'choice', 'growablerows': 'growable_rows', 'growablecols': 'growable_cols', 'enabled': 'disabled', 'sashpos': 'sash_pos', } def fix_properties(document): # special case... for elem in document.getElementsByTagName('disabled'): elem.tagName = 'disabled_bitmap' for prop in _props: for elem in document.getElementsByTagName(prop): elem.tagName = _props[prop] document.documentElement.tagName = 'application' if document.documentElement.hasAttribute('version'): document.documentElement.removeAttribute('version') def fix_widgets(document): fix_menubars(document) fix_toolbars(document) fix_custom_widgets(document) fix_sizeritems(document) fix_notebooks(document) fix_splitters(document) fix_spacers(document) fix_sliders(document) fix_toplevel_names(document) _widgets_list = [ 'wxFrame', 'wxDialog', 'wxPanel', 'wxSplitterWindow', 'wxNotebook', 'wxButton', 'wxToggleButton', 'wxBitmapButton', 'wxTextCtrl', 'wxSpinCtrl', 'wxSlider', 'wxGauge', 'wxStaticText', 'wxCheckBox', 'wxRadioButton', 'wxRadioBox', 'wxChoice', 'wxComboBox', 'wxListBox', 'wxStaticLine', 'wxStaticBitmap', 'wxGrid', 'wxMenuBar', 'wxStatusBar', 'wxBoxSizer', 'wxStaticBoxSizer', 'wxGridSizer', 'wxFlexGridSizer', 'wxTreeCtrl', 'wxListCtrl', 'wxToolBar', ] _widgets = dict(zip(_widgets_list, [1] * len(_widgets_list))) _special_class_names = [ 'notebookpage', 'sizeritem', 'separator', 'tool', 'spacer', ] _special_class_names = dict(zip(_special_class_names, [1] * len(_special_class_names))) def fix_custom_widgets(document): for elem in document.getElementsByTagName('object'): klass = elem.getAttribute('class') if klass not in _widgets and klass not in _special_class_names: elem.setAttribute('base', 'CustomWidget') args = document.createElement('arguments') for child in get_child_elems(elem): # if child is a 'simple' attribute, i.e # value, convert it to an 'argument' if len(child.childNodes) == 1 and \ child.firstChild.nodeType == child.TEXT_NODE: arg = document.createElement('argument') arg.appendChild(document.createTextNode( child.tagName + ': ' + child.firstChild.data)) args.appendChild(arg) # and remove it elem.removeChild(child) # otherwise, leave it where it is (it shouldn't hurt) elem.appendChild(args) def fix_sizeritems(document): def ok(node): return node.getAttribute('class') == 'sizeritem' def ok2(node): return node.tagName == 'object' for sitem in filter(ok, document.getElementsByTagName('object')): for child in filter(ok2, get_child_elems(sitem)): sitem.appendChild(sitem.removeChild(child)) fix_flag_property(document) def fix_flag_property(document): for elem in document.getElementsByTagName('flag'): tmp = elem.firstChild.data.replace('CENTRE', 'CENTER') elem.firstChild.data = tmp.replace('GROW', 'EXPAND') if elem.firstChild.data.find('wxALIGN_CENTER_HORIZONTAL') < 0 and \ elem.firstChild.data.find('wxALIGN_CENTER_VERTICAL') < 0: elem.firstChild.data = elem.firstChild.data.replace( 'wxALIGN_CENTER', 'wxALIGN_CENTER_HORIZONTAL|' 'wxALIGN_CENTER_VERTICAL') def fix_menubars(document): def ok(elem): return elem.getAttribute('class') == 'wxMenuBar' menubars = filter(ok, document.getElementsByTagName('object')) for mb in menubars: fix_menus(document, mb) if mb.parentNode is not document.documentElement: mb_prop = document.createElement('menubar') mb_prop.appendChild(document.createTextNode('1')) mb.parentNode.insertBefore(mb_prop, mb) def fix_menus(document, menubar): def ok(elem): return elem.getAttribute('class') == 'wxMenu' menus = filter(ok, get_child_elems(menubar)) menus_node = document.createElement('menus') for menu in menus: try: label = [ c for c in get_child_elems(menu) if c.tagName == 'label' ][0] label = label.firstChild.data except IndexError: label = '' new_menu = document.createElement('menu') new_menu.setAttribute('name', menu.getAttribute('name')) new_menu.setAttribute('label', label) fix_sub_menus(document, menu, new_menu) menus = document.createElement('menus') menus.appendChild(new_menu) menubar.removeChild(menu).unlink() menubar.appendChild(menus) def fix_sub_menus(document, menu, new_menu): for child in get_child_elems(menu): klass = child.getAttribute('class') elem = document.createElement('') if klass == 'wxMenuItem': elem.tagName = 'item' name = document.createElement('name') name.appendChild(document.createTextNode( child.getAttribute('name'))) elem.appendChild(name) for c in get_child_elems(child): elem.appendChild(c) elif klass == 'separator': elem.tagName = 'item' for name in 'label', 'id', 'name': e = document.createElement(name) e.appendChild(document.createTextNode('---')) elem.appendChild(e) elif klass == 'wxMenu': elem.tagName = 'menu' elem.setAttribute('name', child.getAttribute('name')) try: label = [ c for c in get_child_elems(child) if c.tagName == 'label' ][0] label = label.firstChild.data except IndexError: label = '' elem.setAttribute('label', label) fix_sub_menus(document, child, elem) if elem.tagName: new_menu.appendChild(elem) def fix_toolbars(document): def ok(elem): return elem.getAttribute('class') == 'wxToolBar' toolbars = filter(ok, document.getElementsByTagName('object')) for tb in toolbars: fix_tools(document, tb) if tb.parentNode is not document.documentElement: tb_prop = document.createElement('toolbar') tb_prop.appendChild(document.createTextNode('1')) tb.parentNode.insertBefore(tb_prop, tb) def fix_tools(document, toolbar): tools = document.createElement('tools') for tool in [c for c in get_child_elems(toolbar) if c.tagName == 'object']: if tool.getAttribute('class') == 'tool': new_tool = document.createElement('tool') id = document.createElement('id') id.appendChild(document.createTextNode( tool.getAttribute('name'))) new_tool.appendChild(id) for c in get_child_elems(tool): if c.tagName == 'bitmap': c.tagName = 'bitmap1' elif c.tagName == 'tooltip': c.tagName = 'short_help' elif c.tagName == 'longhelp': c.tagName = 'long_help' elif c.tagName == 'toggle': c.tagName = 'type' new_tool.appendChild(c) tools.appendChild(new_tool) toolbar.removeChild(tool).unlink() elif tool.getAttribute('class') == 'separator': new_tool = document.createElement('tool') id = document.createElement('id') id.appendChild(document.createTextNode('---')) new_tool.appendChild(id) tools.appendChild(new_tool) toolbar.removeChild(tool).unlink() else: # some kind of control, unsupported at the moment, just remove it toolbar.removeChild(tool).unlink() toolbar.appendChild(tools) def fix_notebooks(document): def ispage(node): return node.getAttribute('class') == 'notebookpage' def isnotebook(node): return node.getAttribute('class') == 'wxNotebook' for nb in filter(isnotebook, document.getElementsByTagName('object')): pages = filter(ispage, get_child_elems(nb)) tabs = document.createElement('tabs') try: us = filter(lambda n: n.tagName == 'usenotebooksizer', get_child_elems(nb))[0] nb.removeChild(us).unlink() except IndexError: pass for page in pages: tab = document.createElement('tab') obj = None for c in get_child_elems(page): if c.tagName == 'label': tab.appendChild(c.firstChild) elif c.tagName == 'object': tab.setAttribute('window', c.getAttribute('name')) c.setAttribute('base', 'NotebookPane') obj = c tabs.appendChild(tab) nb.replaceChild(obj, page) nb.insertBefore(tabs, nb.firstChild) def fix_splitters(document): def issplitter(node): return node.getAttribute('class') == 'wxSplitterWindow' def ispane(node): return node.tagName == 'object' for sp in filter(issplitter, document.getElementsByTagName('object')): panes = filter(ispane, get_child_elems(sp)) assert len(panes) <= 2, "Splitter window with more than 2 panes!" for i in range(len(panes)): e = document.createElement('window_%s' % (i+1)) e.appendChild(document.createTextNode( panes[i].getAttribute('name'))) sp.insertBefore(e, sp.firstChild) for orient in filter(lambda n: n.tagName == 'orientation', get_child_elems(sp)): if orient.firstChild.data == 'vertical': orient.firstChild.data = 'wxVERTICAL' elif orient.firstChild.data == 'horizontal': orient.firstChild.data = 'wxHORIZONTAL' def fix_fake_panels(document): def isframe(node): return node.getAttribute('class') == 'wxFrame' for frame in filter(isframe, document.getElementsByTagName('object')): for c in get_child_elems(frame): if c.tagName == 'object' and c.getAttribute('class') == 'wxPanel' \ and c.getAttribute('name') == '': elems = get_child_elems(c) if len(elems) == 1 and \ elems[0].getAttribute('class').find('Sizer') != -1: frame.replaceChild(elems[0], c) def fix_spacers(document): def isspacer(node): return node.getAttribute('class') == 'spacer' for spacer in filter(isspacer, document.getElementsByTagName('object')): spacer.setAttribute('name', 'spacer') spacer.setAttribute('base', 'EditSpacer') sizeritem = document.createElement('object') sizeritem.setAttribute('class', 'sizeritem') for child in get_child_elems(spacer): if child.tagName == 'size': w, h = [s.strip() for s in child.firstChild.data.split(',')] width = document.createElement('width') width.appendChild(document.createTextNode(w)) height = document.createElement('height') height.appendChild(document.createTextNode(h)) spacer.removeChild(child).unlink() spacer.appendChild(width) spacer.appendChild(height) else: sizeritem.appendChild(spacer.removeChild(child)) spacer.parentNode.replaceChild(sizeritem, spacer) sizeritem.appendChild(spacer) def fix_toplevel_names(document): names = {} for widget in get_child_elems(document.documentElement): klass = widget.getAttribute('class') if not klass: continue # don't add a new 'class' attribute if it doesn't exist if klass == 'wxPanel': widget.setAttribute('base', 'EditTopLevelPanel') klass_name = kn = klass.replace('wx', 'My') name = widget.getAttribute('name') i = 1 while names.has_key(klass_name) or klass_name == name: klass_name = kn + str(i) i += 1 widget.setAttribute('class', klass_name) def fix_sliders(document): def isslider(node): klass = node.getAttribute('class') return klass == 'wxSlider' or klass == 'wxSpinCtrl' for slider in filter(isslider, document.getElementsByTagName('object')): v1, v2 = 0, 100 for child in get_child_elems(slider): if child.tagName == 'min': v1 = child.firstChild.data.strip() slider.removeChild(child).unlink() elif child.tagName == 'max': v2 = child.firstChild.data.strip() slider.removeChild(child).unlink() rng = document.createElement('range') rng.appendChild(document.createTextNode('%s, %s' % (v1, v2))) slider.appendChild(rng) def fix_encoding(filename, document): # first try to find the encoding of the xml doc import re enc = re.compile(r'^\s*<\?xml\s+.*(encoding\s*=\s*"(.*?)").*\?>') tag = re.compile(r'<.+?>') for line in open(filename): match = re.match(enc, line) if match is not None: document.documentElement.setAttribute('encoding', match.group(2)) return elif re.match(tag, line) is not None: break # if it's not specified, try to find a child of the root called 'encoding': # I don't know why, but XRCed does this for child in document.documentElement.childNodes: if child.nodeType == child.ELEMENT_NODE and \ child.tagName == 'encoding': if child.firstChild is not None and \ child.firstChild.nodeType == child.TEXT_NODE: document.documentElement.setAttribute( 'encoding', child.firstChild.data) document.documentElement.removeChild(child) def usage(): msg = """\ usage: python %s OPTIONS [WXG_FILE] OPTIONS: -d, --debug: debug mode, i.e. you can see the whole traceback of each error If WXG_FILE is not given, it defaults to INPUT_FILE.wxg """ % _name print msg sys.exit(1) def print_exception(exc): msg = """\ An error occurred while trying to convert the XRC file. Here's the short error message: \t%s\n If you think this is a bug, or if you want to know more about the cause of the error, run this script again in debug mode (-d switch). If you find a bug, please report it to the mailing list (wxglade-general@lists.sourceforge.net), or enter a bug report at the SourceForge bug tracker. Please note that this doesn't handle ALL XRC files correctly, but only those which already are in a format which wxGlade likes (this basically means that every non-toplevel widget must be inside sizers, but there might be other cases). """ % str(exc) print >> sys.stderr, msg sys.exit(1) def main(): try: options, args = getopt.getopt(sys.argv[1:], "d", ['debug']) except getopt.GetoptError: usage() if not args: usage() input = args[0] try: output = args[1] except IndexError: output = os.path.splitext(input)[0] + '.wxg' if not options: try: convert(input, output) except Exception, e: # catch the exception and print a nice message print_exception(e) else: # if in debug mode, let the traceback be printed convert(input, output) if __name__ == '__main__': _name = os.path.basename(sys.argv[0]) main() spe-0.8.4.h/_spe/plugins/wxGlade/edit_widget.py0000755000175000017500000001030110743421035020417 0ustar stanistani# edit_widget.py: base class for EditFoo objects # # Copyright (c) 2002-2004 Richard Lawson # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc, config from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditWidget(ManagedBase): def __init__(self, name, klass, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxFoo objects """ self.label = label self.default = False ManagedBase.__init__(self, name, klass, parent, id, sizer, pos, property_window, show=show) # introspect subclass looking for properties # and widgets self.property_names = [] self.property_proportion = {} attrs = dir(self) for attr in attrs: prefix = attr[0:4] if prefix == 'get_': getter = attr #print 'found getter ', getter # extract the property name prefix, name = attr.split('_', 1) #print 'getter ', name # check for a setter setter = 'set_%s' % name if not hasattr(self, setter): #print 'no setter for %s, skipping ' % name continue # check for a get_name_widget getter_widget = 'get_%s_widget' % name if not hasattr(self, getter_widget): #print 'no widget getter for %s, skipping ' % name continue #print 'adding property: %s' % name self.property_names.append(name) self.access_functions[name] = (getattr(self, getter), getattr(self, setter)) prop = getattr(self, getter_widget)() try: prop, proportion = prop except TypeError: proportion = 0 self.properties[name] = prop self.property_proportion[name] = proportion def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) for name in self.property_names: self.properties[name].display(panel) szr.Add(self.properties[name].panel, self.property_proportion[name], wx.EXPAND) panel.SetAutoLayout(1) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, 'Widget') import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) # end of class EditWidget def increment_label(label, number=[1]): _label = '%s_%d' % (label, number[0]) while common.app_tree.has_name(_label): number[0] += 1 _label = '%s_%d' % (label, number[0]) return _label def add_widget_node(widget, sizer, pos, from_xml=False, option=0, flag=0, border=0): node = Tree.Node(widget) widget.node = node if not border and config.preferences.default_border: flag |= wx.ALL border = config.preferences.default_border_size if option: widget.set_option(option) if flag: widget.set_int_flag(flag) if border: widget.set_border(border) if not from_xml: widget.show_widget(True) sizer.set_item(widget.pos, option, flag, border) if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) def get_label_from_xml(attrs): from xml_parse import XmlParsingError try: return attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") def initialize(edit_klass, builder, xml_builder, icon_path): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets[edit_klass] = builder common.widgets_from_xml[edit_klass] = xml_builder return common.make_object_button(edit_klass, icon_path) spe-0.8.4.h/_spe/plugins/wxGlade/templates_ui.py0000755000175000017500000001642210743421035020634 0ustar stanistani#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # generated by wxGlade 0.6 on Thu Sep 6 09:18:32 2007 import wx # begin wxGlade: extracode try: ID_EDIT = wx.ID_EDIT except AttributeError: ID_EDIT = wx.NewId() # end wxGlade class TemplateInfoDialog(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: TemplateInfoDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.MAXIMIZE_BOX|wx.THICK_FRAME wx.Dialog.__init__(self, *args, **kwds) self.sizer_3_staticbox = wx.StaticBox(self, -1, _("Description")) self.sizer_3_copy_staticbox = wx.StaticBox(self, -1, _("Instructions")) self.sizer_2_staticbox = wx.StaticBox(self, -1, _("Author")) self.template_name = wx.TextCtrl(self, -1, "") self.author = wx.TextCtrl(self, -1, "") self.description = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE) self.instructions = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE) self.button_1 = wx.Button(self, wx.ID_OK, "") self.button_2 = wx.Button(self, wx.ID_CANCEL, "") self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: TemplateInfoDialog.__set_properties self.SetTitle(_("wxGlade template information")) self.SetSize(wx.DLG_SZE(self, (250, 265))) # end wxGlade def __do_layout(self): # begin wxGlade: TemplateInfoDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_4 = wx.BoxSizer(wx.HORIZONTAL) sizer_3_copy = wx.StaticBoxSizer(self.sizer_3_copy_staticbox, wx.HORIZONTAL) sizer_3 = wx.StaticBoxSizer(self.sizer_3_staticbox, wx.HORIZONTAL) sizer_2 = wx.StaticBoxSizer(self.sizer_2_staticbox, wx.HORIZONTAL) sizer_8 = wx.BoxSizer(wx.HORIZONTAL) template_name_copy = wx.StaticText(self, -1, _("wxGlade template: ")) template_name_copy.SetFont(wx.Font(-1, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) sizer_8.Add(template_name_copy, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 10) sizer_8.Add(self.template_name, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 10) sizer_1.Add(sizer_8, 0, wx.EXPAND, 0) sizer_2.Add(self.author, 1, 0, 0) sizer_1.Add(sizer_2, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.description, 1, wx.EXPAND, 0) sizer_1.Add(sizer_3, 1, wx.ALL|wx.EXPAND, 5) sizer_3_copy.Add(self.instructions, 1, wx.EXPAND, 0) sizer_1.Add(sizer_3_copy, 1, wx.ALL|wx.EXPAND, 5) sizer_4.Add(self.button_1, 0, 0, 0) sizer_4.Add(self.button_2, 0, wx.LEFT, 10) sizer_1.Add(sizer_4, 0, wx.ALL|wx.ALIGN_RIGHT, 10) self.SetSizer(sizer_1) self.Layout() self.Centre() # end wxGlade # end of class TemplateInfoDialog class TemplateListDialog(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: TemplateListDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.sizer_2_copy_staticbox = wx.StaticBox(self, -1, _("Author")) self.sizer_3_copy_1_staticbox = wx.StaticBox(self, -1, _("Description")) self.sizer_3_copy_copy_staticbox = wx.StaticBox(self, -1, _("Instructions")) self.sizer_7_staticbox = wx.StaticBox(self, -1, _("Available templates")) self.template_names = wx.ListBox(self, -1, choices=[]) self.template_name = wx.StaticText(self, -1, _("wxGlade template:\n")) self.author = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY) self.description = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY) self.instructions = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY) self.btn_open = wx.Button(self, wx.ID_OPEN, "") self.btn_edit = wx.Button(self, ID_EDIT, _("&Edit")) self.btn_delete = wx.Button(self, wx.ID_DELETE, "") self.btn_cancel = wx.Button(self, wx.ID_CANCEL, "") self.__set_properties() self.__do_layout() self.Bind(wx.EVT_LISTBOX_DCLICK, self.on_open, self.template_names) self.Bind(wx.EVT_LISTBOX, self.on_select_template, self.template_names) self.Bind(wx.EVT_BUTTON, self.on_open, self.btn_open) self.Bind(wx.EVT_BUTTON, self.on_edit, id=ID_EDIT) self.Bind(wx.EVT_BUTTON, self.on_delete, self.btn_delete) # end wxGlade def __set_properties(self): # begin wxGlade: TemplateListDialog.__set_properties self.SetTitle(_("wxGlade template list")) self.SetSize(wx.DLG_SZE(self, (300, 200))) self.template_name.SetFont(wx.Font(-1, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) # end wxGlade def __do_layout(self): # begin wxGlade: TemplateListDialog.__do_layout sizer_5 = wx.BoxSizer(wx.VERTICAL) sizer_4_copy = wx.BoxSizer(wx.HORIZONTAL) sizer_6 = wx.BoxSizer(wx.HORIZONTAL) sizer_1_copy = wx.BoxSizer(wx.VERTICAL) sizer_3_copy_copy = wx.StaticBoxSizer(self.sizer_3_copy_copy_staticbox, wx.HORIZONTAL) sizer_3_copy_1 = wx.StaticBoxSizer(self.sizer_3_copy_1_staticbox, wx.HORIZONTAL) sizer_2_copy = wx.StaticBoxSizer(self.sizer_2_copy_staticbox, wx.HORIZONTAL) sizer_7 = wx.StaticBoxSizer(self.sizer_7_staticbox, wx.VERTICAL) sizer_7.Add(self.template_names, 1, wx.ALL|wx.EXPAND, 3) sizer_6.Add(sizer_7, 1, wx.ALL|wx.EXPAND, 5) sizer_1_copy.Add(self.template_name, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 7) sizer_2_copy.Add(self.author, 1, 0, 0) sizer_1_copy.Add(sizer_2_copy, 0, wx.ALL|wx.EXPAND, 5) sizer_3_copy_1.Add(self.description, 1, wx.EXPAND, 0) sizer_1_copy.Add(sizer_3_copy_1, 1, wx.ALL|wx.EXPAND, 5) sizer_3_copy_copy.Add(self.instructions, 1, wx.EXPAND, 0) sizer_1_copy.Add(sizer_3_copy_copy, 1, wx.ALL|wx.EXPAND, 5) sizer_6.Add(sizer_1_copy, 2, wx.EXPAND, 0) sizer_5.Add(sizer_6, 1, wx.EXPAND, 0) sizer_4_copy.Add(self.btn_open, 0, 0, 0) sizer_4_copy.Add(self.btn_edit, 0, wx.LEFT, 10) sizer_4_copy.Add(self.btn_delete, 0, wx.LEFT, 10) sizer_4_copy.Add(self.btn_cancel, 0, wx.LEFT, 10) sizer_5.Add(sizer_4_copy, 0, wx.ALL|wx.ALIGN_RIGHT, 10) self.SetSizer(sizer_5) self.Layout() self.Centre() # end wxGlade def on_open(self, event): # wxGlade: TemplateListDialog. print _("Event handler `on_open' not implemented!") event.Skip() def on_select_template(self, event): # wxGlade: TemplateListDialog. print _("Event handler `on_select_template' not implemented!") event.Skip() def on_edit(self, event): # wxGlade: TemplateListDialog. print _("Event handler `on_edit' not implemented!") event.Skip() def on_delete(self, event): # wxGlade: TemplateListDialog. print _("Event handler `on_delete' not implemented!") event.Skip() # end of class TemplateListDialog if __name__ == "__main__": import gettext gettext.install("app") # replace with the appropriate catalog name app = wx.PySimpleApp(0) wx.InitAllImageHandlers() template_info_dialog = TemplateInfoDialog(None, -1, "") app.SetTopWindow(template_info_dialog) template_info_dialog.Show() app.MainLoop() spe-0.8.4.h/_spe/plugins/wxGlade/__init__.py0000644000175000017500000000037610743421035017676 0ustar stanistani# __init__.py: to turn wxGlade into a package # $Id: __init__.py,v 1.4 2007/03/27 07:02:07 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY spe-0.8.4.h/_spe/plugins/wxGlade/wxglade.py0000755000175000017500000001164510743421035017576 0ustar stanistani#!/usr/bin/env python # wxglade.py: entry point of wxGlade # $Id: wxglade.py,v 1.27 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import os, sys, gettext t = gettext.translation(domain="wxglade", localedir="locale", fallback=True) t.install("wxglade") # check to see if the Python release supports boolean identifiers # and bool built-in function (>= Python 2.2.1). try: True, False, bool except NameError: setattr(__builtins__, 'True', 1) setattr(__builtins__, 'False', not True) def bool(value): return not not value setattr(__builtins__, 'bool', bool) # and this is for Python <= 2.3 try: sorted except NameError: def sorted(l): l = list(l)[:] l.sort() return l setattr(__builtins__, 'sorted', sorted) def _fix_path(path): """\ Returns an absolute version of path, accroding to the invoking dir of wxglade (which can be different from '.' if it is invoked from a shell script) """ if not os.path.isabs(path): return os.path.join(os.getcwd(), path) #getenv('WXGLADE_INVOKING_DIR', '.'), path) return path def parse_command_line(): import getopt, common try: options, args = getopt.getopt(sys.argv[1:], "g:o:", ['generate-code=', 'output=']) except getopt.GetoptError: #import traceback; traceback.print_exc() usage() return options, args def command_line_code_generation(options, args): """\ starts a code generator without starting the GUI. """ import common if not options: usage() if not options[0]: usage() # a language for code generation must be provided if len(args) != 1: usage() # an input file name must be provided common.use_gui = False # don't import wxPython.wx # use_gui has to be set before importing config import config config.init_preferences() common.load_code_writers() common.load_widgets() common.load_sizers() try: from xml_parse import CodeWriter out_path = None language = '' for option, arg in options: if option == '-g' or option == '--generate-code': language = arg elif option == '-o' or option == '--output': out_path = _fix_path(arg) writer = common.code_writers[language] CodeWriter(writer, _fix_path(args[0]), out_path=out_path) except KeyError: print >> sys.stderr, \ _('Error: no writer for language "%s" available') % language sys.exit(1) except Exception, e: print >> sys.stderr, _("Error: %s") % e import traceback; traceback.print_exc() sys.exit(1) sys.exit(0) def usage(): """\ Prints a help message about the usage of wxGlade from the command line. """ msg = _("""\ wxGlade usage: - to start the GUI: python wxglade.py [WXG_FILE] - to generate code from the command line: python wxglade.py OPTIONS... FILE OPTIONS are the following: -g, --generate-code=LANGUAGE (required) give the output language -o, --output=PATH (optional) name of the output file (in single-file mode) or directory (in multi-file mode) """) print msg print _('Valid LANGUAGE values:'), import common common.use_gui = False common.load_code_writers() for value in common.code_writers: print value, print '\n' sys.exit(1) def determine_wxglade_path(): try: root = __file__ if os.path.islink(root): root = os.path.realpath(root) return os.path.dirname(os.path.abspath(root)) except: # __file__ is not defined when building an .exe with McMillan return os.path.dirname(sys.argv[0]) def run_main(): """\ This main procedure is started by calling either wxglade.py or wxglade.pyw on windows """ # prepend the widgets dir to the # app's search path wxglade_path = determine_wxglade_path() #sys.path = [os.getcwd(), os.path.join(os.getcwd(), 'widgets')] + sys.path sys.path = [wxglade_path, os.path.join(wxglade_path, 'widgets')] + sys.path # set the program's path import common common.wxglade_path = wxglade_path #os.getcwd() # before running the GUI, let's see if there are command line options for # code generation if len(sys.argv) == 1: # if there was no option, start the app in GUI mode import main main.main() else: options, args = parse_command_line() if not options: # start the app in GUI mode, opening the given file filename = _fix_path(args[0]) import main main.main(filename) else: command_line_code_generation(options, args) if __name__ == "__main__": run_main() spe-0.8.4.h/_spe/plugins/wxGlade/Makefile0000644000175000017500000000234710743421035017225 0ustar stanistaniDESTDIR= PACKAGE=python-wxglade PYVER=2.3 all: debian/wxglade.1 clean: find . -name "*.pyc" -exec rm -f {} \; find . -name "*~" -exec rm -f {} \; DB2MAN=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl XP=xsltproc --nonet debian/wxglade.1: debian/manpage.xml cd debian && $(XP) $(DB2MAN) manpage.xml install: all install-doc cp -a *.py codegen edit_sizers res widgets \ $(DESTDIR)/usr/lib/python$(PYVER)/site-packages/wxglade # fix executable flags for f in configUI.py zwxglade.py; do \ chmod 755 $(DESTDIR)/usr/lib/python$(PYVER)/site-packages/wxglade/$$f; \ done for f in edit_widget.py config.py; do \ chmod 644 $(DESTDIR)/usr/lib/python$(PYVER)/site-packages/wxglade/$$f; \ done cp -a icons $(DESTDIR)/usr/share/$(PACKAGE) # get rid of .xvpics subdirectories and .cvsignore files find $(DESTDIR)/usr/share/$(PACKAGE) -name '.xvpics' -type d | xargs rm -rf find $(DESTDIR) -name '.cvsignore' -type f | xargs rm -f ln -s /usr/share/$(PACKAGE)/icons \ $(DESTDIR)/usr/lib/python$(PYVER)/site-packages/wxglade install -m 755 wxglade $(DESTDIR)/usr/bin install-doc: debian/wxglade.1 gzip -c9 debian/wxglade.1 > $(DESTDIR)/usr/share/man/man1/wxglade.1.gz cp -a docs $(DESTDIR)/usr/share/doc/$(PACKAGE)/ spe-0.8.4.h/_spe/plugins/wxGlade/TODO.txt0000644000175000017500000000405610743421035017072 0ustar stanistaniwxGlade TODO list ----------------- Last update: 2003-07-28 The list is more or less sorted by priority Things Done: ------------ - Code generation on separate files - "tags" on the generated code, to detect the portions of code to replace and those to keep as is, when updating an existing file - Investigation of the many memory leaks - speedup of the xml loading - separation between window objects and sizer ones in the generated code - Code generation from the command line, witout starting the GUI - support wxWindows xml resources (XRC) through a code generator - support for C++ code generation - Possibility to change the type of a sizer after its creation - Possibility to change the position of a widget inside its sizer - Edit -> Preferences... to customize some aspects of wxGlade - International characters support - Grid - Auto saving/backup of wxg files (and possibly also of generated sources) - Import of "wxGlade-friendly" XRC files - Preview of toplevel widgets - Checks on the values of some properties (name, class,...) - More basic properties for widgets (enabled for example) - ScrolledWindow (as a `scrollable' property for panels) - widgets path, to let the user add new widget modules - support for Perl code generation Real TODO (# = Partially done): ------------------------------- - Undo/Redo - Better XRC support (custom classes, separate files, ...) (#: custom classes - see the tutorial) - Event handlers support - ListCtrl and TreeCtrl (#: need to add more properties) - ToolBar for frames (#: no controls yet) - complete MenuBar with icons and StatusBar messages support (#) - Less frequently used controls - on-line help (with wxHtmlHelpController) - test of the various modules with unittest (this might come earlier...) - gettext support (#: done for code generation, todo for wxGlade itself) - ``Templates'' for particular windows (for example, something as a dialog with an image, a centered label and a couple of buttons) - TabOrder property (this may be hard though) - (Maybe) Java code generator - ... spe-0.8.4.h/_spe/plugins/wxGlade/code_property.py0000644000175000017500000001570510743421035021017 0ustar stanistani# code_property.py: Property class for the 'code' property of toplevel widgets # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx, wx.grid import widget_properties from widget_properties import GridProperty from xml.sax.saxutils import escape, quoteattr class CodeProperty(widget_properties.TextProperty): def __init__(self, owner, name='extracode'): setattr(owner, name, "") def get(): return getattr(owner, name) def set(val): return setattr(owner, name, val) owner.access_functions[name] = (get, set) widget_properties.TextProperty.__init__(self, owner, name, None, True, multiline=True) def _show(self, notebook, label=_('Code')): panel, new = _find_or_create_page(notebook, label) self.display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.panel, 1, wx.EXPAND) if new: panel.SetSizerAndFit(szr) notebook.AddPage(panel, label) else: sizer = panel.GetSizer() sizer.Add(szr, 1, wx.EXPAND) panel.Layout() def display(self, parent): self.id = wx.NewId() val = self.get_value() val = val.replace('\\n', '\n') sb = wx.StaticBox(parent, -1, "") label = widget_properties.wxGenStaticText(parent, -1, _('Extra code for this widget')) self._enabler = wx.CheckBox(parent, self.id+1, '') tooltip = """\ You can use this property to add some extra code to that generated by wxGlade. Please note that you should use this ability only if you have the \ "Overwrite existing sources" option set. NOTE: at the moment, this property is supported only by the following code \ generators: Python C++ XRC""" style = wx.TE_MULTILINE|wx.HSCROLL self.text = wx.TextCtrl(parent, self.id, val, style=style, size=(1, -1)) font = wx.Font(12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) self.text.SetFont(font) label.SetToolTip(wx.ToolTip(tooltip)) wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda event: self.toggle_active(event.IsChecked())) self.text.Enable(self.is_active()) self._enabler.SetValue(self.is_active()) self._target = self.text szr = wx.BoxSizer(wx.HORIZONTAL) szr.Add(label, 1, wx.ALL|wx.EXPAND, 3) szr.Add(self._enabler, 0, wx.ALL|wx.EXPAND, 3) sizer = wx.StaticBoxSizer(sb, wx.VERTICAL) sizer.Add(szr, 0, wx.EXPAND) sizer.Add(self.text, 1, wx.ALL|wx.EXPAND, 3) h = self.text.GetCharHeight() sizer.SetItemMinSize(self.text, -1, h*3) self.panel = sizer self.bind_event(self.on_change_val) wx.EVT_CHAR(self.text, self.on_char) # end of class CodeProperty class ExtraPropertiesProperty(GridProperty): def __init__(self, owner): setattr(owner, 'extraproperties', []) def get(): return getattr(owner, 'extraproperties') def set(val): return setattr(owner, 'extraproperties', val) owner.access_functions['extraproperties'] = (get, set) cols = [(_('Property'), GridProperty.STRING), (_('Value'), GridProperty.STRING)] self.label = _('Extra properties for this widget') GridProperty.__init__(self, owner, 'extraproperties', None, cols, can_insert=False) def write(self, outfile, tabs): if self.getter: props = self.getter() else: props = self.owner[self.name][0]() if props: written = False write = outfile.write stab = ' ' * (tabs+1) for name, value in props: if value: if not written: written = True write(' ' * tabs + '\n') write('%s%s\n' % (stab, quoteattr(name), escape(value.strip()))) if written: write(' ' * tabs + '\n') def display(self, panel): GridProperty.display(self, panel) self.btn.Hide() wx.grid.EVT_GRID_CELL_CHANGE(self.grid, self.on_change_val) tooltip = """\ You can use this property to add some extra custom properties to this widget. For each property "prop" with value "val", wxGlade will generate a \ "widget.SetProp(val)" line (or a "val" line for XRC). NOTE: at the moment, this property is supported only by the following code \ generators: Python C++ XRC Perl""" self.grid.SetToolTip(wx.ToolTip(tooltip)) def add_row(self, event): GridProperty.add_row(self, event) self.on_change_val(event) def remove_row(self, event): GridProperty.remove_row(self, event) self.on_change_val(event) def set_value(self, val): if isinstance(val, dict): val = [[k, val[k]] for k in sorted(val.keys())] GridProperty.set_value(self, val) def _show(self, notebook, label=_('Code')): panel, new = _find_or_create_page(notebook, label) self.display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.panel, 1, wx.EXPAND) if new: panel.SetSizerAndFit(szr) notebook.AddPage(panel, _('Code')) else: sizer = panel.GetSizer() sizer.Add(szr, 1, wx.EXPAND) sizer.Layout() # end of class ExtraPropertiesProperty class ExtraPropertiesPropertyHandler(object): def __init__(self, owner): self.owner = owner self.props = {} self.prop_name = None self.curr_prop = [] def start_elem(self, name, attrs): if name == 'property': self.prop_name = attrs['name'] def end_elem(self, name): if name == 'property': if self.prop_name and self.curr_prop: self.props[self.prop_name] = ''.join(self.curr_prop) self.prop_name = None self.curr_prop = [] elif name == 'extraproperties': self.owner.properties['extraproperties'].set_value(self.props) val = [[k, self.props[k]] for k in sorted(self.props.keys())] self.owner.extraproperties = val return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_prop.append(data) # end of class ExtraPropertiesPropertyHandler def _find_or_create_page(notebook, label): """\ Searches the given notebook for a page whose label is "label". """ for i in xrange(notebook.GetPageCount()): if notebook.GetPageText(i) == label: return notebook.GetPage(i), False return wx.Panel(notebook, -1, style=wx.TAB_TRAVERSAL), True spe-0.8.4.h/_spe/plugins/wxGlade/config.py0000755000175000017500000003166110743421035017410 0ustar stanistanifrom ConfigParser import * import common, sys, os, os.path if common.use_gui: import wx import misc try: wx.FIXED_MINSIZE except NameError: import configUI configUI.wxFIXED_MINSIZE = 0 from configUI import * class wxGladePreferences(wxGladePreferencesUI): def __init__(self, preferences): wxGladePreferencesUI.__init__(self, None, -1, "") wx.EVT_BUTTON(self, self.choose_widget_path.GetId(), self.on_widget_path) self.preferences = preferences self.set_values() def set_values(self): try: self.use_menu_icons.SetValue(self.preferences.use_menu_icons) self.frame_tool_win.SetValue(self.preferences.frame_tool_win) self.open_save_path.SetValue(self.preferences.open_save_path) self.codegen_path.SetValue(self.preferences.codegen_path) self.use_dialog_units.SetValue( self.preferences.use_dialog_units) self.number_history.SetValue(self.preferences.number_history) self.show_progress.SetValue(self.preferences.show_progress) self.wxg_backup.SetValue(self.preferences.wxg_backup) self.codegen_backup.SetValue(self.preferences.codegen_backup) #MARCELLO self.default_border.SetValue(self.preferences.default_border) self.default_border_size.SetValue( self.preferences.default_border_size) if self.preferences.backup_suffix == '.bak': self.backup_suffix.SetSelection(1) self.buttons_per_row.SetValue(self.preferences.buttons_per_row) self.remember_geometry.SetValue( self.preferences.remember_geometry) self.local_widget_path.SetValue( self.preferences.local_widget_path) # ALB 2004-08-11 self.show_sizer_handle.SetValue( self.preferences.show_sizer_handle) self.allow_duplicate_names.SetValue( self.preferences.allow_duplicate_names) # ALB 2004-10-15 self.autosave.SetValue(self.preferences.autosave) self.autosave_delay.SetValue(self.preferences.autosave_delay) # ALB 2004-10-27 self.use_kde_dialogs.SetValue(self.preferences.use_kde_dialogs) self.write_timestamp.SetValue(self.preferences.write_timestamp) self.write_generated_from.SetValue( self.preferences.write_generated_from) self._fix_spin_ctrls() except Exception, e: wx.MessageBox(_('Error reading config file:\n%s') % e, 'Error', wx.OK|wx.CENTRE|wx.ICON_ERROR) def _fix_spin_ctrls(self): """\ Workaround to a wxGTK 2.8.4.2 bug in wx.SpinCtrl.GetValue """ done = {} for name in ('buttons_per_row', 'autosave_delay', 'number_history', 'default_border_size'): def fix(n): done[n] = False def update(e): done[n] = True e.Skip() def get_val(): if not done[n]: return getattr(self.preferences, n) else: return wx.SpinCtrl.GetValue(getattr(self, n)) return update, get_val spin = getattr(self, name) if spin.GetValue() != getattr(self.preferences, name): update, get_val = fix(name) spin.GetValue = get_val spin.Bind(wx.EVT_SPINCTRL, update) def set_preferences(self): prefs = self.preferences prefs['use_menu_icons'] = self.use_menu_icons.GetValue() prefs['frame_tool_win'] = self.frame_tool_win.GetValue() prefs['open_save_path'] = self.open_save_path.GetValue() prefs['codegen_path'] = self.codegen_path.GetValue() prefs['use_dialog_units'] = self.use_dialog_units.GetValue() prefs['number_history'] = self.number_history.GetValue() prefs['show_progress'] = self.show_progress.GetValue() prefs['wxg_backup'] = self.wxg_backup.GetValue() prefs['codegen_backup'] = self.codegen_backup.GetValue() #MARCELLO prefs['default_border'] = self.default_border.GetValue() prefs['default_border_size'] = self.default_border_size.GetValue() if self.backup_suffix.GetSelection(): prefs['backup_suffix'] = '.bak' else: prefs['backup_suffix'] = '~' prefs['buttons_per_row'] = self.buttons_per_row.GetValue() prefs['remember_geometry'] = self.remember_geometry.GetValue() prefs['local_widget_path'] = self.local_widget_path.GetValue() # ALB 2004-08-11 prefs['show_sizer_handle'] = self.show_sizer_handle.GetValue() prefs['allow_duplicate_names'] = self.allow_duplicate_names.\ GetValue() # ALB 2004-10-15 prefs['autosave'] = self.autosave.GetValue() prefs['autosave_delay'] = self.autosave_delay.GetValue() # ALB 2004-10-27 prefs['use_kde_dialogs'] = self.use_kde_dialogs.GetValue() prefs['write_timestamp'] = self.write_timestamp.GetValue() prefs['write_generated_from'] = self.write_generated_from.GetValue() def on_widget_path(self, event): # create a file choice dialog pth = misc.DirSelector(_("Choose a directory:"), os.getcwd(), style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) if pth: self.local_widget_path.SetValue(pth) # end of class wxGladePreferences def _get_home(default=common.wxglade_path): h = os.path.expanduser('~') if h not in ('~', '%USERPROFILE%'): return h if os.name == 'nt' and h == '%USERPROFILE%': return os.environ.get('USERPROFILE', default) return default def _get_appdatapath(default=common.wxglade_path): if os.name == 'nt': result = os.environ.get('APPDATA') if result: return result return _get_home(default) class Preferences(ConfigParser): _has_home = os.path.expanduser('~') != '~' _defaults = { 'use_menu_icons': common.use_gui and wx.Platform != '__WXGTK__', 'frame_tool_win': True, 'open_save_path': _get_home(), 'codegen_path': _get_home(), 'use_dialog_units': False, 'number_history': 4, 'show_progress': True, 'wxg_backup': True, 'codegen_backup': True, 'backup_suffix': sys.platform == 'win32' and '.bak' or '~', 'buttons_per_row': 5, 'remember_geometry': False, 'local_widget_path': (_get_appdatapath('') and \ os.path.join(_get_appdatapath(), '.wxglade', 'widgets') or ''), 'default_border' : False, 'default_border_size' : 3, 'show_sizer_handle': True, 'allow_duplicate_names': False, 'autosave': True, 'autosave_delay': 120, # in seconds 'use_kde_dialogs': False, 'write_timestamp': True, 'write_generated_from': False, } def __init__(self, defaults=None): self.def_vals = defaults if self.def_vals is None: self.def_vals = Preferences._defaults self.changed = False ConfigParser.__init__(self) #self.default_border_size = 3 def __getattr__(self, attr): val = self.def_vals.get(attr, "") # UGLY!!! cast = type(val) if cast is bool: cast = self._cast_to_bool # ...but I haven't found a better way: the problem is that # bool('0') == True, while int('0') == False, and we want the # latter behaviour try: return cast(self.get('wxglade', attr)) except (NoOptionError, ValueError): return val def __iter__(self): def do_iter(): for key in self.def_vals: yield key, self[key] return do_iter() def _cast_to_bool(self, val): try: return int(val) except ValueError: val = val.lower().strip() if val in ('true', 'on'): return 1 elif val in ('false', 'off'): return 0 else: raise def __getitem__(self, attr): return self.__getattr__(attr) def __setitem__(self, attr, val): self.set('wxglade', attr, str(val)) self.changed = True def set_geometry(self, name, geometry): if geometry is not None: section = 'geometry_%s' % name if not self.has_section(section): self.add_section(section) self.set(section, 'x', geometry[0]) self.set(section, 'y', geometry[1]) self.set(section, 'w', geometry[2]) self.set(section, 'h', geometry[3]) def get_geometry(self, name): section = 'geometry_%s' % name if self.has_section(section): x = self.get(section, 'x') y = self.get(section, 'y') w = self.get(section, 'w') h = self.get(section, 'h') return (x, y, w, h) else: return None # end of class Preferences preferences = None if sys.platform == 'win32': _rc_name = 'wxglade.ini' else: _rc_name = 'wxgladerc' _use_file_history = False if common.use_gui: import misc if misc.check_wx_version(2, 3, 3): _use_file_history = True def init_preferences(): global preferences if preferences is None: preferences = Preferences() h = _get_appdatapath('') search_path = [os.path.join(common.wxglade_path, _rc_name)] if h: search_path.append(os.path.join(h, '.wxglade', _rc_name)) if 'WXGLADE_CONFIG_PATH' in os.environ: search_path.append( os.path.expandvars('$WXGLADE_CONFIG_PATH/%s' % _rc_name)) preferences.read(search_path) if not preferences.has_section('wxglade'): preferences.add_section('wxglade') def edit_preferences(): dialog = wxGladePreferences(preferences) if dialog.ShowModal() == wx.ID_OK: wx.MessageBox(_('Changes will take effect after wxGlade is restarted'), _('Preferences saved'), wx.OK|wx.CENTRE|wx.ICON_INFORMATION) dialog.set_preferences() dialog.Destroy() def save_preferences(): # let the exception be raised if 'WXGLADE_CONFIG_PATH' in os.environ: path = os.path.expandvars('$WXGLADE_CONFIG_PATH') else: path = _get_appdatapath() if path != common.wxglade_path: path = os.path.join(path, '.wxglade') if not os.path.isdir(path): os.mkdir(path) # always save the file history if _use_file_history: fh = common.palette.file_history if misc.check_wx_version(2, 5): count = fh.GetCount() else: count = fh.GetNoHistoryFiles() encoding = 'utf-8' filenames = [common._encode_to_xml(fh.GetHistoryFile(i), encoding) for i in range(min(preferences.number_history, count))] outfile = open(os.path.join(path, 'file_history.txt'), 'w') print >> outfile, "# -*- coding: %s -*-" % encoding for filename in filenames: print >> outfile, filename outfile.close() if preferences.changed: outfile = open(os.path.join(path, _rc_name), 'w') # let the exception be raised to signal abnormal behaviour preferences.write(outfile) outfile.close() def load_history(): """\ Loads the file history and returns a list of paths """ if 'WXGLADE_CONFIG_PATH' in os.environ: path = os.path.expandvars('$WXGLADE_CONFIG_PATH') else: path = _get_appdatapath() if path != common.wxglade_path: path = os.path.join(path, '.wxglade') try: history = open(os.path.join(path, 'file_history.txt')) l = history.readlines() if l and l[0].startswith('# -*- coding:'): try: encoding = 'utf-8' #l = [common._encode_from_xml(e, encoding) for e in l[1:]] l = [e.decode(encoding) for e in l[1:]] except Exception, e: print _("ERR:"), e l = l[1:] history.close() if common.use_gui: l = [misc.wxstr(e, 'utf-8') for e in l] return l except IOError: # don't consider this an error return [] spe-0.8.4.h/_spe/plugins/wxGlade/edit_windows.py0000644000175000017500000013436110743421035020640 0ustar stanistani# edit_windows.py: base classes for windows used by wxGlade # $Id: edit_windows.py,v 1.90 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from widget_properties import * from tree import Tree, WidgetTree import math, misc, common, sys, config import os, re # ALB 2004-12-05: event handling support from events_mixin import EventsMixin class EditBase(EventsMixin): """\ Base class of every window available in the builder. """ def __init__(self, name, klass, parent, id, property_window, show=True, custom_class=True): # property_window: widget inside which Properties of this object # are displayed # name: name of the object # klass: name of the object's class # custom_class: if true, the user can chage the value of the 'class' # property # dictionary of properties relative to this object; the properties that # control the layout (i.e. the behaviour when inside a sizer) are not # contained here, but in a separate list (see ManagedBase) # the keys of the dict are the names of the properties self.properties = {} self.parent = parent # id used for internal purpose events self.id = id self.name = name self.klass = klass self.base = klass self.custom_class = custom_class self._dont_destroy = False self.access_functions = { 'name' : (lambda : self.name, self.set_name), 'class' : (lambda : self.klass, self.set_klass) } # these two properties are special and are not listed in # 'self.properties' self.name_prop = TextProperty(self, 'name', None, label=_("name")) self.klass_prop = TextProperty(self, 'class', None, readonly=not custom_class, label=_("class")) if custom_class: self.klass_prop.tooltip = _("If you change the default value, " \ "it will be interpreted as the name " \ "of the subclass of the widget. " \ "How this name affects code generation "\ "depends on the kind (i.e. language) " \ "of output. See the docs for " \ "more details.") # ALB 2007-08-31: custom base classes support if getattr(self, '_custom_base_classes', False): self.custom_base = "" def get_custom_base(): return self.custom_base def set_custom_base(val): self.custom_base = val self.access_functions['custom_base'] = (get_custom_base, set_custom_base) p = self.properties['custom_base'] = TextProperty( self, 'custom_base', can_disable=True, enabled=False) p.label = _('Base class(es)') p.tooltip = _("""\ A comma-separated list of custom base classes. The first will be invoked \ with the same parameters as this class, while for the others the default \ constructor will be used. You should probably not use this if \ "overwrite existing sources" is not set.""") self.notebook = None self.property_window = property_window # popup menu self._rmenu = None # this is the reference to the actual wxWindow widget; it is created # only if needed, i.e. when it should become visible self.widget = None if show: self.show_widget(True) property_window.SetSize((250, 340)) property_window.Show(True) # ALB 2004-12-05 EventsMixin.__init__(self) # code property import code_property self.properties['extracode'] = code_property.CodeProperty(self) self.properties['extraproperties'] = code_property.ExtraPropertiesProperty(self) def show_widget(self, yes): if yes and self.widget is None: self.create_widget() self.finish_widget_creation() if self.widget: self.widget.Show(yes) def create_widget(self): """\ Initializes self.widget and shows it """ raise NotImplementedError def finish_widget_creation(self, *args, **kwds): """\ Creates the popup menu and connects some event handlers to self.widgets """ wx.EVT_RIGHT_DOWN(self.widget, self.popup_menu) def delete(self): """\ Destructor. Deallocates the popup menu, the notebook and all the properties. Why we need explicit deallocation? Well, basically because otherwise we get a lot of memory leaks... :) """ # first, destroy the popup menu... if wx.Platform != '__WXMAC__': if self._rmenu: self._rmenu.Destroy() # ...then, destroy the property notebook... if self.notebook: nb_szr = self.notebook.sizer self.notebook.DeleteAllPages() self.notebook.Destroy() if nb_szr is not None: nb_szr.Destroy() # ...finally, destroy our widget (if needed) if self.widget and not self._dont_destroy: self.widget.Destroy() if misc.focused_widget is self: misc.focused_widget = None def create_properties(self): """\ Creates the notebook with the properties of self """ self.notebook = wx.Notebook(self.property_window, -1) if not misc.check_wx_version(2, 5, 2): nb_sizer = wx.NotebookSizer(self.notebook) self.notebook.sizer = nb_sizer else: self.notebook.sizer = None self.notebook.SetAutoLayout(True) self.notebook.Hide() self._common_panel = panel = wx.ScrolledWindow( self.notebook, -1, style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE) self.name_prop.display(panel) self.klass_prop.display(panel) if getattr(self, '_custom_base_classes', False): self.properties['custom_base'].display(panel) def __getitem__(self, value): return self.access_functions[value] def set_name(self, value): value = "%s" % value if not config.preferences.allow_duplicate_names and \ (self.widget and common.app_tree.has_name(value, self.node)): misc.wxCallAfter( wx.MessageBox, _('Name "%s" is already in use.\n' 'Please enter a different one.') % value, _("Error"), wx.OK|wx.ICON_ERROR) self.name_prop.set_value(self.name) return if not re.match(self.set_name_pattern, value): self.name_prop.set_value(self.name) else: oldname = self.name self.name = value if self._rmenu: self._rmenu.SetTitle(self.name) try: common.app_tree.refresh_name(self.node, oldname) #, self.name) except AttributeError: pass self.property_window.SetTitle(_('Properties - <%s>') % self.name) set_name_pattern = re.compile(r'^[a-zA-Z_]+[\w-]*(\[\w*\])*$') def set_klass(self, value): value = "%s" % value if not re.match(self.set_klass_pattern, value): self.klass_prop.set_value(self.klass) else: self.klass = value try: common.app_tree.refresh_name(self.node) #, self.name) except AttributeError: pass set_klass_pattern = re.compile('^[a-zA-Z_]+[\w:.0-9-]*$') def popup_menu(self, event): if self.widget: if not self._rmenu: COPY_ID, REMOVE_ID, CUT_ID = [wx.NewId() for i in range(3)] self._rmenu = misc.wxGladePopupMenu(self.name) misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self._rmenu, COPY_ID, _('Copy\tCtrl+C'), wx.ART_COPY) misc.append_item(self._rmenu, CUT_ID, _('Cut\tCtrl+X'), wx.ART_CUT) self._rmenu.AppendSeparator() PREVIEW_ID = wx.NewId() misc.append_item(self._rmenu, PREVIEW_ID, _('Preview')) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, COPY_ID, bind(self.clipboard_copy)) wx.EVT_MENU(self.widget, CUT_ID, bind(self.clipboard_cut)) wx.EVT_MENU(self.widget, PREVIEW_ID, bind(self.preview_parent)) self.setup_preview_menu() self.widget.PopupMenu(self._rmenu, event.GetPosition()) def remove(self, *args): self._dont_destroy = False # always destroy when explicitly asked common.app_tree.remove(self.node) def setup_preview_menu(self): p = misc.get_toplevel_widget(self) if p is not None: item = list(self._rmenu.GetMenuItems())[-1] if p.preview_is_visible(): item.SetText(_('Close preview') + ' (%s)\tCtrl+P' % p.name) else: item.SetText(_('Preview') + ' (%s)\tCtrl+P' % p.name) def preview_parent(self): widget = misc.get_toplevel_widget(self) if widget is not None: widget.preview(None) def show_properties(self, *args): """\ Updates property_window to display the properties of self """ # Begin Marcello 13 oct. 2005 if self.klass == 'wxPanel': # am I a wxPanel under a wxNotebook? if self.parent and self.parent.klass == 'wxNotebook': #pdb.set_trace() nb = self.parent if nb.widget: i = 0 for tn, ep in nb.tabs: # tn=tabname, ep = editpanel try: if ep and self.name == ep.name: # If I am under this tab... nb.widget.SetSelection(i) # ...Show that tab. except AttributeError: pass i = i + 1 if self.parent and self.parent.klass == 'wxPanel': # am I a widget under a wxPanel under a wxNotebook? if self.parent.parent and self.parent.parent.klass == 'wxNotebook': #pdb.set_trace() nb = self.parent.parent if nb.widget: i = 0 for tn, ep in nb.tabs: # tn=tabname, ep = editpanel try: if ep and self.parent.name == ep.name: nb.widget.SetSelection(i) except AttributeError: pass i = i + 1 # End Marcello 13 oct. 2005 if not self.is_visible(): return # don't do anything if self is hidden # create the notebook the first time the function is called: this # allows us to create only the notebooks we really need if self.notebook is None: self.create_properties() # ALB 2004-12-05 self.create_events_property() self.create_extracode_property() sizer_tmp = self.property_window.GetSizer() #sizer_tmp = wxPyTypeCast(sizer_tmp, "wxBoxSizer") #child = wxPyTypeCast(sizer_tmp.GetChildren()[0], "wxSizerItem") child = sizer_tmp.GetChildren()[0] w = child.GetWindow() if w is self.notebook: return try: index = -1 title = w.GetPageText(w.GetSelection()) for i in range(self.notebook.GetPageCount()): if self.notebook.GetPageText(i) == title: index = i break except AttributeError, e: #print e index = -1 w.Hide() if 0 <= index < self.notebook.GetPageCount(): self.notebook.SetSelection(index) self.notebook.Reparent(self.property_window) child.SetWindow(self.notebook) w.Reparent(misc.hidden_property_panel) # ALB moved this before Layout, it seems to be needed for wx2.6... self.notebook.Show() self.notebook.SetSize(self.property_window.GetClientSize()) self.property_window.Layout() self.property_window.SetTitle(_('Properties - <%s>') % self.name) try: common.app_tree.select_item(self.node) except AttributeError: pass self.widget.SetFocus() def on_set_focus(self, event): """\ Event handler called when a window receives the focus: this in fact is connected to a EVT_LEFT_DOWN and not to an EVT_FOCUS, but the effect is the same """ self.show_properties() misc.focused_widget = self #if wxPlatform != '__WXMSW__': event.Skip() def get_property_handler(self, prop_name): """\ returns a custom handler function for the property 'prop_name', used when loading this object from an xml file. handler must provide three methods: 'start_elem', 'end_elem' and 'char_data' """ # ALB 2004-12-05 return EventsMixin.get_property_handler(self, prop_name) def clipboard_copy(self, *args): """\ returns a copy of self to be inserted in the clipboard """ import clipboard clipboard.copy(self) def clipboard_cut(self, *args): import clipboard clipboard.cut(self) def is_visible(self): if not self.widget: return False if not self.widget.IsShown(): return False if self.widget.IsTopLevel(): return self.widget.IsShown() parent = self.parent if parent: return parent.is_visible() return self.widget.IsShown() def update_view(self, selected): """\ updates the widget's view to reflect its state, i.e. shows which widget is currently selected; the default implementation does nothing. """ pass def post_load(self): """\ Called after the loading of an app from an XML file, before showing the hierarchy of widget for the first time. The default implementation does nothing. """ pass def create_extracode_property(self): try: self.properties['extracode']._show(self.notebook) self.properties['extraproperties']._show(self.notebook) except KeyError: pass # end of class EditBase class WindowBase(EditBase): """\ Extends EditBase with the addition of the common properties available to almost every window: size, background and foreground colors, and font """ def __init__(self, name, klass, parent, id, property_window, show=True): EditBase.__init__(self, name, klass, parent, id, property_window, show=False) # 'property' id (editable by the user) self.window_id = -1 def set_id(value): self.window_id = value self.access_functions['id'] = (lambda s=self: s.window_id, set_id) self.size = '-1, -1' self.access_functions['size'] = (self.get_size, self.set_size) self.background = '' self.access_functions['background'] = (self.get_background, self.set_background) self.foreground = '' self.access_functions['foreground'] = (self.get_foreground, self.set_foreground) # this is True if the user has selected a custom font self._font_changed = False self.font = self._build_from_font(wx.SystemSettings_GetFont( wx.SYS_DEFAULT_GUI_FONT)) self.font[1] = 'default' self.access_functions['font'] = (self.get_font, self.set_font) # properties added 2002-08-15 self.tooltip = '' self.access_functions['tooltip'] = (self.get_tooltip, self.set_tooltip) min_x = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_X) min_y = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_Y) max_x = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) max_y = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) self._original = {'background': None, 'foreground': None, 'font': None} prop = self.properties prop['id'] = TextProperty(self, 'id', None, can_disable=True) prop['size'] = TextProperty(self, 'size', None, can_disable=True, label=_("size")) prop['background'] = ColorDialogProperty(self, "background", None, label=_("background")) prop['foreground'] = ColorDialogProperty(self, "foreground", None, label=_("foreground")) prop['font'] = FontDialogProperty(self, "font", None, label=_("font")) # properties added 2002-08-15 prop['tooltip'] = TextProperty(self, 'tooltip', None, can_disable=True, label=_('tooltip')) # properties added 2003-05-15 self.disabled_p = False self.access_functions['disabled'] = (self.get_disabled, self.set_disabled) prop['disabled'] = CheckBoxProperty(self, 'disabled', None, _('disabled')) self.focused_p = False self.access_functions['focused'] = (self.get_focused, self.set_focused) prop['focused'] = CheckBoxProperty(self, 'focused', None, _('focused')) self.hidden_p = False self.access_functions['hidden'] = (self.get_hidden, self.set_hidden) prop['hidden'] = CheckBoxProperty(self, 'hidden', None, _('hidden')) def finish_widget_creation(self, *args, **kwds): self._original['background'] = self.widget.GetBackgroundColour() self._original['foreground'] = self.widget.GetForegroundColour() fnt = self.widget.GetFont() if not fnt.Ok(): fnt = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._original['font'] = fnt prop = self.properties size = prop['size'].get_value() if size: #self.widget.SetSize([int(s) for s in size.split(',')]) self.set_size(size) else: prop['size'].set_value('%s, %s' % tuple(self.widget.GetSize())) if prop['background'].is_active(): self.set_background(prop['background'].get_value()) else: color = misc.color_to_string(self.widget.GetBackgroundColour()) self.background = color prop['background'].set_value(color) if prop['foreground'].is_active(): self.set_foreground(prop['foreground'].get_value()) else: color = misc.color_to_string(self.widget.GetForegroundColour()) self.foreground = color prop['foreground'].set_value(color) if prop['font'].is_active(): self.set_font(prop['font'].get_value()) EditBase.finish_widget_creation(self) wx.EVT_SIZE(self.widget, self.on_size) # after setting various Properties, we must Refresh widget in order to # see changes self.widget.Refresh() def on_key_down(event): evt_flags = 0 if event.ControlDown(): evt_flags = wx.ACCEL_CTRL evt_key = event.GetKeyCode() done = False for flags, key, function in misc.accel_table: if evt_flags == flags and evt_key == key: misc.wxCallAfter(function) done = True break if not done: event.Skip() wx.EVT_KEY_DOWN(self.widget, on_key_down) def create_properties(self): EditBase.create_properties(self) min_x = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_X) min_y = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_Y) max_x = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) max_y = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) panel = self._common_panel prop = self.properties prop['id'].display(panel) prop['size'].display(panel) prop['background'].display(panel) prop['foreground'].display(panel) try: prop['font'].display(panel) except KeyError: pass # new properties 2002-08-15 prop['tooltip'].display(panel) # new properties 2003-05-15 prop['disabled'].display(panel) prop['focused'].display(panel) prop['hidden'].display(panel) sizer_tmp = wx.BoxSizer(wx.VERTICAL) sizer_tmp.Add(self.name_prop.panel, 0, wx.EXPAND) sizer_tmp.Add(self.klass_prop.panel, 0, wx.EXPAND) if getattr(self, '_custom_base_classes', False): sizer_tmp.Add(prop['custom_base'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['id'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['size'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['background'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['foreground'].panel, 0, wx.EXPAND) try: sizer_tmp.Add(prop['font'].panel, 0, wx.EXPAND) except KeyError: pass sizer_tmp.Add(prop['tooltip'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['disabled'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['focused'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['hidden'].panel, 0, wx.EXPAND) panel.SetAutoLayout(1) panel.SetSizer(sizer_tmp) sizer_tmp.Layout() sizer_tmp.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, _("Common")) self.property_window.Layout() panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def on_size(self, event): """\ update the value of the 'size' property """ try: w_1, h_1 = 0, 0 sz = self.properties['size'] if sz.is_active(): # try to preserve the user's choice try: use_dialog_units = (sz.get_value().strip()[-1] == 'd') except IndexError: use_dialog_units = False val = sz.get_value() if use_dialog_units: val = val[:-1] w_1, h_1 = [int(t) for t in val.split(',')] else: use_dialog_units = config.preferences.use_dialog_units #False if use_dialog_units: w, h = self.widget.ConvertPixelSizeToDialog( self.widget.GetSize()) else: w, h = self.widget.GetSize() if w_1 == -1: w = -1 if h_1 == -1: h = -1 size = "%s, %s" % (w, h) if use_dialog_units: size += "d" self.size = size self.properties['size'].set_value(size) except KeyError: pass event.Skip() def get_tooltip(self): return self.tooltip def set_tooltip(self, value): self.tooltip = misc.wxstr(value) def get_background(self): return self.background def get_foreground(self): return self.foreground def set_background(self, value): oldval = self.background self.background = value if not self.widget: return value = value.strip() if value in ColorDialogProperty.str_to_colors: self.widget.SetBackgroundColour(wx.SystemSettings_GetColour( ColorDialogProperty.str_to_colors[value])) else: try: color = misc.string_to_color(value) self.widget.SetBackgroundColour(color) except: self.background = oldval self.properties['background'].set_value(self.get_background()) return self.widget.Refresh() def set_foreground(self, value): oldval = self.foreground self.foreground = value if not self.widget: return value = value.strip() if value in ColorDialogProperty.str_to_colors: self.widget.SetForegroundColour(wx.SystemSettings_GetColour( ColorDialogProperty.str_to_colors[value])) else: try: color = misc.string_to_color(value) self.widget.SetForegroundColour(color) except: self.foreground = oldval self.properties['foreground'].set_value(self.get_foreground()) return self.foreground = value self.widget.Refresh() def get_font(self): return str(self.font) def _build_from_font(self, font): families = FontDialogProperty.font_families_from styles = FontDialogProperty.font_styles_from weights = FontDialogProperty.font_weights_from return [ str(font.GetPointSize()), families.get(font.GetFamily(), 'default'), styles.get(font.GetStyle(), 'normal'), weights.get(font.GetWeight(), 'normal'), str(int(font.GetUnderlined())), font.GetFaceName() ] def set_font(self, value): #if not self.widget: return families = FontDialogProperty.font_families_to styles = FontDialogProperty.font_styles_to weights = FontDialogProperty.font_weights_to try: value = eval(value) f = wx.Font(int(value[0]), families[value[1]], styles[value[2]], weights[value[3]], int(value[4]), value[5]) except: #import traceback; traceback.print_exc() self.properties['font'].set_value(self.get_font()) else: self.font = value if self.widget: old_size = self.widget.GetSize() self.widget.SetFont(f) size = self.widget.GetSize() if size != old_size: self.sizer.set_item(self.pos, size=size) def set_width(self, value): self.set_size((int(value), -1)) def set_height(self, value): self.set_size((-1, int(value))) def set_size(self, value): #if not self.widget: return if self.properties['size'].is_active(): v = self.properties['size'].get_value().strip() use_dialog_units = v and v[-1] == 'd' else: use_dialog_units = config.preferences.use_dialog_units #False try: "" + value except TypeError: pass else: # value is a string-like object if value and value.strip()[-1] == 'd': use_dialog_units = True value = value[:-1] try: size = [int(t.strip()) for t in value.split(',', 1)] except: self.properties['size'].set_value(self.size) else: if use_dialog_units and value[-1] != 'd': value += 'd' self.size = value if self.widget: if use_dialog_units: size = wx.DLG_SZE(self.widget, size) if misc.check_wx_version(2, 5): self.widget.SetMinSize(size) self.widget.SetSize(size) try: #self.sizer.set_item(self.pos, size=self.widget.GetSize()) self.sizer.set_item(self.pos, size=size) except AttributeError: pass def get_size(self): return self.size def get_property_handler(self, name): if name == 'font': class FontHandler: def __init__(self, owner): self.owner = owner self.props = [ '' for i in range(6) ] self.index = 0 def start_elem(self, name, attrs): index = { 'size': 0, 'family': 1, 'style': 2, 'weight': 3, 'underlined': 4, 'face': 5 } self.index = index.get(name, 5) def end_elem(self, name): if name == 'font': self.owner.properties['font'].set_value( repr(self.props)) self.owner.properties['font'].toggle_active(True) self.owner.set_font(repr(self.props)) return True # to remove this handler def char_data(self, data): self.props[self.index] = str(data.strip()) # end of class FontHandler return FontHandler(self) elif name == 'extraproperties': import code_property return code_property.ExtraPropertiesPropertyHandler(self) return EditBase.get_property_handler(self, name) def get_disabled(self): return self.disabled_p def set_disabled(self, value): try: self.disabled_p = bool(int(value)) except ValueError: pass def get_focused(self): return self.focused_p def set_focused(self, value): try: self.focused_p = bool(int(value)) except ValueError: pass def get_hidden(self): return self.hidden_p def set_hidden(self, value): try: self.hidden_p = bool(int(value)) except ValueError: pass # end of class WindowBase class ManagedBase(WindowBase): """\ Base class for every managed window used by the builder: extends WindowBase with the addition of properties relative to the layout of the window: option, flag, and border """ def __init__(self, name, klass, parent, id, sizer, pos, property_window, show=True): WindowBase.__init__(self, name, klass, parent, id, property_window, show=show) # if True, the user is able to control the layout of the widget # inside the sizer (proportion, borders, alignment...) self._has_layout = not sizer.is_virtual() # selection markers self.sel_marker = None # dictionary of properties relative to the sizer which # controls this window self.sizer_properties = {} # attributes to keep the values of the sizer_properties self.option = 0 self.flag = 0 self.border = 0 self.sizer = sizer self.pos = pos self.access_functions['option'] = (self.get_option, self.set_option) self.access_functions['flag'] = (self.get_flag, self.set_flag) self.access_functions['border'] = (self.get_border, self.set_border) self.access_functions['pos'] = (self.get_pos, self.set_pos) self.flags_pos = (wx.ALL, wx.LEFT, wx.RIGHT, wx.TOP, wx.BOTTOM, wx.EXPAND, wx.ALIGN_RIGHT, wx.ALIGN_BOTTOM, wx.ALIGN_CENTER_HORIZONTAL, wx.ALIGN_CENTER_VERTICAL, wx.SHAPED, wx.ADJUST_MINSIZE) flag_labels = (u'#section#' + _('Border'), 'wxALL', 'wxLEFT', 'wxRIGHT', 'wxTOP', 'wxBOTTOM', u'#section#' + _('Alignment'), 'wxEXPAND', 'wxALIGN_RIGHT', 'wxALIGN_BOTTOM', 'wxALIGN_CENTER_HORIZONTAL', 'wxALIGN_CENTER_VERTICAL', 'wxSHAPED', 'wxADJUST_MINSIZE') # ALB 2004-08-16 - see the "wxPython migration guide" for details... if misc.check_wx_version(2, 5, 2): self.flag = wx.ADJUST_MINSIZE #wxFIXED_MINSIZE self.flags_pos += (wx.FIXED_MINSIZE, ) flag_labels += ('wxFIXED_MINSIZE', ) sizer.add_item(self, pos) szprop = self.sizer_properties #szprop['option'] = SpinProperty(self, _("option"), None, 0, (0, 1000)) from layout_option_property import LayoutOptionProperty, \ LayoutPosProperty szprop['option'] = LayoutOptionProperty(self, sizer) szprop['flag'] = CheckListProperty(self, 'flag', None, flag_labels) szprop['border'] = SpinProperty(self, 'border', None, 0, (0, 1000), label=_('border')) ## pos_p = szprop['pos'] = SpinProperty(self, 'pos', None, 0, (0, 1000)) ## def write(*args, **kwds): pass ## pos_p.write = write # no need to save the position szprop['pos'] = LayoutPosProperty(self, sizer) def finish_widget_creation(self, sel_marker_parent=None): if sel_marker_parent is None: sel_marker_parent = self.parent.widget self.sel_marker = misc.SelectionMarker(self.widget, sel_marker_parent) WindowBase.finish_widget_creation(self) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) wx.EVT_MOVE(self.widget, self.on_move) # re-add the item to update it self.sizer.add_item(self, self.pos, self.option, self.flag, self.border, self.widget.GetSize()) # set the value of the properties szp = self.sizer_properties szp['option'].set_value(self.get_option()) szp['flag'].set_value(self.get_flag()) szp['border'].set_value(self.get_border()) szp['pos'].set_value(self.pos-1) ## if self.properties['size'].is_active(): ## self.sizer.set_item(self.pos, size=self.widget.GetSize()) def create_properties(self): WindowBase.create_properties(self) if not self._has_layout: return panel = wx.ScrolledWindow( self.notebook, -1, style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE) min_x = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_X) min_y = wx.SystemSettings_GetMetric(wx.SYS_WINDOWMIN_Y) max_x = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) max_y = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) szprop = self.sizer_properties szprop['pos'].display(panel) szprop['option'].display(panel) szprop['border'].display(panel) szprop['flag'].display(panel) sizer_tmp = wx.BoxSizer(wx.VERTICAL) sizer_tmp.Add(szprop['pos'].panel, 0, wx.EXPAND) sizer_tmp.Add(szprop['option'].panel, 0, wx.EXPAND) sizer_tmp.Add(szprop['border'].panel, 0, wx.EXPAND) sizer_tmp.Add(szprop['flag'].panel, 0, wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(sizer_tmp) sizer_tmp.Layout() sizer_tmp.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, _("Layout")) panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def update_view(self, selected): if self.sel_marker: self.sel_marker.Show(selected) def on_move(self, event): self.sel_marker.update() def on_size(self, event): old = self.size WindowBase.on_size(self, event) sz = self.properties['size'] if (sz.is_active() and (int(self.get_option()) != 0 or self.get_int_flag() & wx.EXPAND)): self.properties['size'].set_value(old) self.size = old self.sel_marker.update() def set_option(self, value): self.option = value = int(value) if not self.widget: return try: sz = self.properties['size'] if value or sz.is_active(): size = sz.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(self.widget, (w, h)) if value: w, h = 1, 1 else: w, h = self.widget.GetBestSize() self.sizer.set_item(self.pos, option=value, size=(w, h)) except AttributeError, e: print e def set_flag(self, value): value = self.sizer_properties['flag'].prepare_value(value) flags = 0 for v in range(len(value)): if value[v]: flags |= self.flags_pos[v] self.set_int_flag(flags) def set_int_flag(self, flags): self.flag = flags if not self.widget: return try: try: sp = self.properties['size'] size = sp.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(self.widget, (w, h)) size = [w, h] except ValueError: size = None if not (flags & wx.EXPAND) and \ not self.properties['size'].is_active(): size = list(self.widget.GetBestSize()) self.sizer.set_item(self.pos, flag=flags, size=size) except AttributeError, e: import traceback; traceback.print_exc() def set_border(self, value): self.border = int(value) if not self.widget: return try: sp = self.properties['size'] size = sp.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(self.widget, (w, h)) if w == -1: w = self.widget.GetSize()[0] if h == -1: h = self.widget.GetSize()[1] self.sizer.set_item(self.pos, border=int(value), size=(w, h)) except AttributeError, e: import traceback; traceback.print_exc() def get_option(self): return self.option def get_flag(self): retval = [0] * len(self.flags_pos) try: for i in range(len(self.flags_pos)): if self.flag & self.flags_pos[i]: retval[i] = 1 # patch to make wxALL work if retval[1:5] == [1, 1, 1, 1]: retval[0] = 1; retval[1:5] = [0, 0, 0, 0] else: retval[0] = 0 except AttributeError: pass return retval def get_int_flag(self): return self.flag def get_border(self): return self.border def delete(self): if self.sel_marker: self.sel_marker.Destroy() # destroy the selection markers WindowBase.delete(self) def remove(self, *args): self.sizer.free_slot(self.pos) WindowBase.remove(self) def get_pos(self): return self.pos-1 def set_pos(self, value): """setter for the 'pos' property: calls self.sizer.change_item_pos""" self.sizer.change_item_pos(self, min(value + 1, len(self.sizer.children) - 1)) def update_pos(self, value): """\ called by self.sizer.change_item_pos to update the item's position when another widget is moved """ #print 'update pos', self.name, value self.sizer_properties['pos'].set_value(value-1) self.pos = value # end of class ManagedBase class PreviewMixin: """Mixin class used to add preview to a widget""" def __init__(self): self.preview_button = None self.preview_widget = None def create_properties(self): panel = self.notebook.GetPage(0) sizer_tmp = panel.GetSizer() # add a preview button to the Common panel for top-levels self.preview_button = btn = wx.Button(panel, -1, _('Preview')) wx.EVT_BUTTON(btn, -1, self.preview) sizer_tmp.Add(btn, 0, wx.ALL|wx.EXPAND, 5) sizer_tmp.Layout() sizer_tmp.Fit(panel) w, h = panel.GetClientSize() self.property_window.Layout() import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def preview(self, event): #print 'frame class _> ', self.klass if self.preview_widget is None: self.preview_widget = common.app_tree.app.preview(self) self.preview_button.SetLabel(_('Close Preview')) else: # Close triggers the EVT_CLOSE that does the real work # (see application.py -> preview) self.preview_widget.Close() def preview_is_visible(self): return self.preview_widget is not None # end of class PreviewMixin class TopLevelBase(WindowBase, PreviewMixin): """\ Base class for every non-managed window (i.e. Frames and Dialogs). """ _is_toplevel = True _custom_base_classes = True def __init__(self, name, klass, parent, id, property_window, show=True, has_title=True, title=None): WindowBase.__init__(self, name, klass, parent, id, property_window, show=show) self.has_title = has_title if self.has_title: if title is None: title = self.name self.title = title self.access_functions['title'] = (self.get_title, self.set_title) self.properties['title'] = TextProperty(self, 'title', None, label=_("title")) self.sizer = None # sizer that controls the layout of the children # of the window PreviewMixin.__init__(self) def finish_widget_creation(self, *args, **kwds): WindowBase.finish_widget_creation(self) self.widget.SetMinSize = self.widget.SetSize if self.has_title: self.widget.SetTitle(misc.design_title( self.properties['title'].get_value())) elif hasattr(self.widget, 'SetTitle'): self.widget.SetTitle(misc.design_title(self.name)) wx.EVT_LEFT_DOWN(self.widget, self.drop_sizer) wx.EVT_ENTER_WINDOW(self.widget, self.on_enter) wx.EVT_CLOSE(self.widget, self.hide_widget) if wx.Platform == '__WXMSW__': # MSW isn't smart enough to avoid overlapping windows, so # at least move it away from the 3 wxGlade frames self.widget.Center() # ALB 2004-10-15 self.widget.SetAcceleratorTable(common.palette.accel_table) def show_widget(self, yes): WindowBase.show_widget(self, yes) if yes and wx.Platform == '__WXMSW__': # more than ugly, but effective hack to properly layout the window # on Win32 if self.properties['size'].is_active(): w, h = self.widget.GetSize() self.widget.SetSize((-1, h+1)) self.widget.SetSize((-1, h)) elif self.sizer: self.sizer.fit_parent() def popup_menu(self, event): if self.widget: if not self._rmenu: REMOVE_ID, HIDE_ID = [wx.NewId() for i in range(2)] self._rmenu = misc.wxGladePopupMenu(self.name) misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self._rmenu, HIDE_ID, _('Hide')) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, HIDE_ID, bind(self.hide_widget)) # paste PASTE_ID = wx.NewId() misc.append_item(self._rmenu, PASTE_ID, _('Paste\tCtrl+V'), wx.ART_PASTE) wx.EVT_MENU(self.widget, PASTE_ID, bind(self.clipboard_paste)) PREVIEW_ID = wx.NewId() self._rmenu.AppendSeparator() misc.append_item(self._rmenu, PREVIEW_ID, _('Preview')) wx.EVT_MENU(self.widget, PREVIEW_ID, bind(self.preview_parent)) self.setup_preview_menu() self.widget.PopupMenu(self._rmenu, event.GetPosition()) def clipboard_paste(self, *args): if self.sizer is not None: print _('\nwxGlade-WARNING: sizer already set for this window') return import clipboard, xml_parse size = self.widget.GetSize() try: if clipboard.paste(self, None, 0): common.app_tree.app.saved = False self.widget.SetSize(size) except xml_parse.XmlParsingError, e: print _('\nwxGlade-WARNING: only sizers can be pasted here') def create_properties(self): WindowBase.create_properties(self) # don't display the title ourselves anymore, now it's a # duty of the subclass! ## if self.has_title: ## panel = self.notebook.GetPage(0) ## sizer_tmp = panel.GetSizer() ## self.properties['title'].display(panel) ## sizer_tmp.Add(self.properties['title'].panel, 0, wxEXPAND) PreviewMixin.create_properties(self) def get_title(self): return self.title def set_title(self, value): self.title = misc.wxstr(value) if self.widget: self.widget.SetTitle(misc.design_title(value)) def set_sizer(self, sizer): self.sizer = sizer if self.sizer and self.sizer.widget and self.widget: self.widget.SetAutoLayout(True) self.widget.SetSizer(self.sizer.widget) self.widget.Layout() def on_enter(self, event): if not self.sizer and common.adding_sizer: self.widget.SetCursor(wx.CROSS_CURSOR) else: self.widget.SetCursor(wx.STANDARD_CURSOR) def drop_sizer(self, event): if self.sizer or not common.adding_sizer: self.on_set_focus(event) # default behaviour: call show_properties return common.adding_widget = common.adding_sizer = False self.widget.SetCursor(wx.STANDARD_CURSOR) common.widgets[common.widget_to_add](self, None, None) common.widget_to_add = None def hide_widget(self, *args): self.widget.Hide() common.app_tree.expand(self.node, False) common.app_tree.select_item(self.node.parent) common.app_tree.app.show_properties() def on_size(self, event): WindowBase.on_size(self, event) if self.sizer and self.widget: self.sizer.refresh() def set_name(self, name): if not misc.streq(self.name, name): common.app_tree.app.update_top_window_name(self.name, name) WindowBase.set_name(self, name) def delete(self, *args): if self.preview_widget is not None: self.preview_widget.Destroy() self.preview_widget = None WindowBase.delete(self, *args) # end of class TopLevelBase spe-0.8.4.h/_spe/plugins/wxGlade/.hgtags0000644000175000017500000000030510743421035017033 0ustar stanistani6a8223539dd8c3a32ef187cb840f90ced1cc0574 v0.5 c4316ac0d906c717db03b4afa456340588c6339d rel_0.6 58d181f6df32da5629e2d4547d4b15f2a1c73405 rel_0.6.1 0ca2ea7b12e8e0c8c450350cf7e2a7492e008633 rel_0.6.2 spe-0.8.4.h/_spe/plugins/wxGlade/events_mixin.py0000644000175000017500000001165510743421035020651 0ustar stanistani# events_mixin.py: mixin class for 'events' property # $Id: events_mixin.py,v 1.7 2007/01/29 19:50:35 dinogen Exp $ # # Copyright (c) 2002-2004 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * #from wxPython.grid import * import wx import wx.grid import re from widget_properties import GridProperty from misc import enumerate from xml.sax.saxutils import escape, quoteattr class EventsProperty(GridProperty): def __init__(self, owner): cols = [(_('Event'), GridProperty.STRING), (_('Handler'), GridProperty.STRING)] GridProperty.__init__(self, owner, 'events', None, cols, len(owner.events), False, False, False, label=_('events')) self._pos = {} for index, name in enumerate(owner.events): self._pos[name] = index self.validator_re = re.compile(r'^\s*[\w-]+\s*$') self.set_value([[name, ''] for name in owner.events]) def display(self, parent): GridProperty.display(self, parent) attr = wx.grid.GridCellAttr() attr.SetReadOnly(True) self.grid.SetColAttr(0, attr) self.grid.AutoSizeColumn(0, False) self.grid.AutoSizeColumn(1, False) wx.grid.EVT_GRID_CELL_CHANGE(self.grid, self.on_change_val) szr = self.panel.GetSizer() szr.Show(self.btn_sizer, False) szr.Layout() def set_value_dict(self, values_dict): val = self.get_value() for row in val: row[1] = values_dict.get(row[0], "") self.set_value(val) def write(self, outfile, tabs): if self.getter: handlers = self.getter() else: handlers = self.owner[self.name][0]() if handlers: written = False write = outfile.write #write(' ' * tabs + '\n') stab = ' ' * (tabs+1) for event, handler in handlers: if handler: if not written: written = True write(' ' * tabs + '\n') write('%s%s\n' % (stab, quoteattr(event), escape(handler.strip()))) if written: write(' ' * tabs + '\n') def on_change_val(self, event): val = self.get_value() for i in range(len(val)): handler = val[i][1].strip() if handler and self.validator_re.match(handler) is None: self.set_value(self.val) return event.Skip() GridProperty.on_change_val(self, event) # end of class EventsProperty class EventsPropertyHandler(object): def __init__(self, owner): #print 'EventsPropertyHandler', owner.name self.owner = owner self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': self.owner.properties['events'].set_value_dict(self.handlers) self.owner.set_events_dict(self.handlers) return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler default_events = [] class EventsMixin: def __init__(self): if not hasattr(self, 'events'): self.events = default_events self.handlers = {} if self.events: self.access_functions['events'] = self.get_events, self.set_events self.properties['events'] = EventsProperty(self) def get_events(self): ret = [] for e in self.events: ret.append([e, self.handlers.get(e, '')]) return ret def set_events(self, handlers_list): self.handlers = {} for event, val in handlers_list: if val.strip(): self.handlers[event] = val def set_events_dict(self, handlers): self.handlers = handlers def create_events_property(self): if not self.events: return panel = wx.Panel(self.notebook, -1) self.properties['events'].display(panel) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.properties['events'].panel, 1, wx.ALL|wx.EXPAND, 5) panel.SetSizerAndFit(sizer) self.notebook.AddPage(panel, _('Events')) def get_property_handler(self, name): if name == 'events': return EventsPropertyHandler(self) return None # end of class EventsMixin spe-0.8.4.h/_spe/plugins/wxGlade/README.txt0000644000175000017500000000302110743421035017251 0ustar stanistaniwxGlade: a GUI builder for wxPython/wxWindows version: 0.5 license: MIT (see license.txt) THIS PROGRAM COMES WITH NO WARRANTY * Requirements: --------------- Python >= 2.3 wxPython >= 2.6 * Installation: --------------- If you are reding this file, you already did all the necessary :-) To start the program, enter ``python wxglade.py'' in your shell * Documentation: ---------------- In the docs/ subdir there's a short introductory tutorial. In the examples/ subdir there are some sample wxGlade apps (in xml format, .wxg file extension). * Known Bugs/Issues: -------------------- - If you have PyXML installed, be sure to use at least version 0.8.1, as otherwise you will not be able to generate code and load saved wxg files. This seems to be a PyXML bug, see http://sourceforge.net/tracker/?func=detail&atid=106473&aid=573011&group_id=6473 - On Windows, selection tags may not be shown properly in some cases. - On GTK, if your last operation before exiting is a paste from the clipboard, wxGlade exits with a segfault. - On GTK, menubars give troubles: they produce a lot of Gtk-WARNING and Gtk-FATAL messages and may cause segfaults. - On GTK, notebooks can cause some Gtk-WARNING messages, but they seem to work anyway. For any kind of question, there's a mailing list at https://lists.sourceforge.net/lists/listinfo/wxglade-general If you don't want to follow the list, you can reach me at agriggio@users.sourceforge.net Enjoy! Alberto Griggio $Id: README.txt,v 1.14 2007/03/27 07:02:07 agriggio Exp $ spe-0.8.4.h/_spe/plugins/wxGlade/widget_properties.py0000644000175000017500000012612510743421035021677 0ustar stanistani# widget_properties.py: classes to handle the various properties of the widgets # (name, size, color, etc.) # $Id: widget_properties.py,v 1.65 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # this is needed for wx >= 2.3.4 to clip the label showing the name of the # property, otherwise on the properties tabs horizontal scrollbars are shown _label_initial_width = 5 #from wxPython.wx import * #from wxPython.grid import * import wx import wx.grid from xml.sax.saxutils import escape import common, misc try: #from wxPython.lib.stattext import * import wx.lib.stattext wxGenStaticText = wx.lib.stattext.GenStaticText except ImportError: # wxGenStaticText has been added in wx 2.3.3, so it may not be available #wxGenStaticText = wxStaticText wxGenStaticText = wx.StaticText def _mangle(label): """\ returns a mangled version of the str label, suitable for displaying the name of a property """ return misc.wxstr(label.capitalize().replace('_', ' ')) import common _encode = common._encode_to_xml class Property: """\ A class to handle a single property of a widget. """ def __init__(self, owner, name, parent, getter=None, setter=None, label=None): # owner: the widget this property belongs to # parent: the widget inside which the property is displayed """\ Access to the property is made through the getter and setter functions, which are invoked also in the default event handler. If they are None, they default to owner[name][0] and owner[name][1] """ self.val = None self.parent = parent self.owner = owner self.getter = getter self.setter = setter self.name = name if label: self.dispName = label else: self.dispName = name def on_change_val(self, event, first=[True]): """\ Event handler called to notify owner that the value of the Property has changed """ val = self.get_value() if not misc.streq(self.val, val): common.app_tree.app.saved = False # update the status of the app if self.setter: self.setter(val) else: self.owner[self.name][1](val) self.val = self.get_value() first[0] = False event.Skip() def write(self, outfile=None, tabs=0): """\ Writes the xml code for this property onto the given file. """ if self.getter: value = self.getter() else: value = self.owner[self.name][0]() if not misc.streq(value, ''): fwrite = outfile.write fwrite(' ' * tabs + '<%s>' % self.name) fwrite(escape(_encode(value))) fwrite('\n' % self.name) def bind_event(self, function): """\ sets the default event handler for this property. """ raise NotImplementedError def get_value(self): raise NotImplementedError def set_value(self, value): raise NotImplementedError # end of class Property class HiddenProperty(Property): """\ Properties not associated to any control, i.e. not editable by the user. """ def __init__(self, owner, name, value=None, label=None): try: getter, setter = owner[name] except KeyError: import traceback; traceback.print_exc() if callable(value): getter = value else: def getter(): return value def setter(v): pass self.panel = None # this is needed to provide an uniform treatment, # but is always None Property.__init__(self, owner, name, None, getter, setter, label=label) if value is not None: if callable(value): self.value = value() else: self.value = value def bind_event(self, function): pass def get_value(self): return self.value def set_value(self, val): self.value = val # end of class HiddenProperty class _activator: """\ a utility class which provides a method, toggle_active, to activate or deactivate a Property of a widget """ def __init__(self, target=None, enabler=None): # target: name of the object to Enable/Disable # enabler: check box which provides the ability to Enable/Disable the # Property self._target = target self._enabler = enabler if self._target: self._active = self._target.IsEnabled() else: self._active = True def toggle_active(self, active): self._active = active if not self._target: return self._target.Enable(active) import common try: common.app_tree.app.saved = False except AttributeError: pass # why does this happen on win at startup? try: self._enabler.SetValue(active) except AttributeError: pass def is_active(self): if self._target: return self._target.IsEnabled() return self._active # end of class _activator class TextProperty(Property, _activator): """\ Properties associated to a text control. """ def __init__(self, owner, name, parent=None, can_disable=False, enabled=False, readonly=False, multiline=False, label=None): Property.__init__(self, owner, name, parent, label=label) self.val = misc.wxstr(owner[name][0]()) self.can_disable = can_disable self.readonly = readonly self.multiline = multiline _activator.__init__(self) if can_disable: self.toggle_active(enabled) self.panel = None if parent is not None: self.display(parent) def display(self, parent): """\ Actually builds the text control to set the value of the property interactively """ self.id = wx.NewId() #self.panel = wxPanel(parent, -1) #self.panel = parent if self.readonly: style = wx.TE_READONLY else: style = 0 if self.multiline: style |= wx.TE_MULTILINE val = self.get_value() if self.multiline: val = val.replace('\\n', '\n') lbl = getattr(self, 'label', None) if lbl is None: lbl = _mangle(self.dispName) #label = wxStaticText(self.panel, -1, _mangle(self.dispName)) label = wxGenStaticText(parent, -1, lbl, size=(_label_initial_width, -1)) if self.can_disable: self._enabler = wx.CheckBox(parent, self.id+1, '', size=(1, -1)) self.text = wx.TextCtrl(parent, self.id, val, style=style, size=(1, -1)) if hasattr(self, 'tooltip'): label.SetToolTip(wx.ToolTip(self.tooltip)) else: label.SetToolTip(wx.ToolTip(_mangle(self.dispName))) if self.can_disable: wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda event: self.toggle_active(event.IsChecked())) self.text.Enable(self.is_active()) self._enabler.SetValue(self.is_active()) self._target = self.text sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) if getattr(self, '_enabler', None) is not None: sizer.Add(self._enabler, 1, wx.ALL|wx.ALIGN_CENTER, 3) option = 4 else: option = 5 sizer.Add(self.text, option, wx.ALL|wx.ALIGN_CENTER, 3) if self.multiline: h = self.text.GetCharHeight() sizer.SetItemMinSize(self.text, -1, h*3) self.panel = sizer self.bind_event(self.on_change_val) wx.EVT_CHAR(self.text, self.on_char) def on_char(self, event): if event.GetKeyCode() == wx.WXK_ESCAPE: self.text.SetValue(self.val) self.text.SetInsertionPointEnd() event.Skip() def bind_event(self, function): def func_2(event): if self.text.IsEnabled(): #misc.wxCallAfter(function, event) function(event) event.Skip() wx.EVT_KILL_FOCUS(self.text, func_2) def get_value(self): try: val = self.text.GetValue() if self.multiline: return val.replace('\n', '\\n') return val except AttributeError: return self.val def set_value(self, value): value = misc.wxstr(value) if self.multiline: self.val = value.replace('\n', '\\n') value = value.replace('\\n', '\n') else: self.val = value try: self.text.SetValue(value) except AttributeError: pass def write(self, outfile, tabs): if self.is_active(): Property.write(self, outfile, tabs) # end of class TextProperty class CheckBoxProperty(Property): """\ Properties whose values can be changed by one checkbox. """ def __init__(self, owner, name, parent=None, label=None, write_always=False): Property.__init__(self, owner, name, parent, label=label) self.val = int(owner[name][0]()) if label is None or label == name: label = _mangle(name) self.label = label self.panel = None self.write_always = write_always if parent is not None: self.display(parent) def display(self, parent): """\ Actually builds the check box to set the value of the property interactively """ self.id = wx.NewId() #self.panel = wxPanel(parent, -1) self.cb = wx.CheckBox(parent, self.id, '') self.cb.SetValue(self.val) label = wxGenStaticText(parent, -1, self.label) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 5, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3) sizer.Add(self.cb, 0, wx.ALIGN_CENTER|wx.ALL, 3) ## self.panel.SetAutoLayout(True) ## self.panel.SetSizer(sizer) ## self.panel.SetSize(sizer.GetMinSize()) self.panel = sizer self.bind_event(self.on_change_val) def bind_event(self, function): wx.EVT_CHECKBOX(self.cb, self.id, function) def get_value(self): try: return int(self.cb.GetValue()) except AttributeError: return int(self.val) def set_value(self, val): self.val = int(val) try: self.cb.SetValue(self.val) except AttributeError: pass def write(self, outfile, tabs): if self.write_always or self.get_value(): if self.getter: value = int(self.getter()) else: value = int(self.owner[self.name][0]()) fwrite = outfile.write fwrite(' ' * tabs + '<%s>' % self.name) fwrite(escape(_encode(value))) fwrite('\n' % self.name) # end of class CheckBoxProperty class CheckListProperty(Property): """\ Properties whose values can be changed by a list of checkboxes. """ def __init__(self, owner, name, parent=None, labels=None, writer=None, tooltips=None): """ @type labels: list of strings @param labels: list of names of the labels of the checkboxes; a label that begins with the string "#section#" is used as the title of a static box that encloses the checkboxes that follow @type tooltips: tuple of strings @param tooltips: a list of strings to be displayed as the tool-tips for the properties """ #" # ALB - fix for emacs's syntax highlight, don't remove please! Property.__init__(self, owner, name, parent, label=None) self.values = owner[name][0]() self.labels = labels self.tooltips = tooltips # the writer param is a function to customize the generation of the xml # for this property self.writer = writer self.panel = None if parent is not None: self.display(parent) def display(self, parent): """\ Actually builds the list of checkboxes to set the value of the property interactively """ self.id = wx.NewId() #self.panel = wxPanel(parent, -1) self.choices = [] tmp_sizer = wx.BoxSizer(wx.VERTICAL) #self.panel.SetAutoLayout(True) i = j = 0 tmp = tmp_sizer while 1: if i >= len(self.labels): break if self.labels[i].startswith('#section#'): if tmp != tmp_sizer: tmp_sizer.Add(tmp, 1, wx.ALL|wx.EXPAND, 5) lbl = _mangle(self.labels[i].replace(u'#section#', '')) s = wx.FULL_REPAINT_ON_RESIZE tmp = wx.StaticBoxSizer(wx.StaticBox(parent, -1, lbl, style=s), wx.VERTICAL) else: c = wx.CheckBox(parent, self.id+j, self.labels[i]) self.choices.append(c) tmp.Add(c) j += 1 i += 1 if tmp != tmp_sizer: tmp_sizer.Add(tmp, 0, wx.ALL|wx.EXPAND, 5) for i in range(len(self.values)): self.choices[i].SetValue(self.values[i]) #Set the tool-tips for the properties if self.tooltips is not None: for i in range(len(self.tooltips)): if i >= len(self.choices): break self.choices[i].SetToolTip(wx.ToolTip(self.tooltips[i])) ## self.panel.SetSizer(tmp_sizer) ## self.panel.SetSize(tmp_sizer.GetMinSize()) self.panel = tmp_sizer self.bind_event(self.on_change_val) def bind_event(self, function): for i in range(len(self.choices)): wx.EVT_CHECKBOX(self.choices[i], self.id+i, function) def get_value(self): try: return [c.GetValue() for c in self.choices] except AttributeError: return self.values def set_value(self, value): self.values = self.prepare_value(value) try: for i in range(len(self.values)): self.choices[i].SetValue(self.values[i]) except AttributeError: pass def write(self, outfile, tabs): if self.writer is not None: return self.writer(outfile, tabs) val = self.owner[self.name][0]() #self.getter() def filter_func(label): return not label.startswith('#section#') labels = filter(filter_func, self.labels) tmp = '|'.join([ labels[c] for c in range(len(labels)) if val[c] ]) if tmp: fwrite = outfile.write fwrite(' ' * tabs + '<%s>' % self.name) fwrite(escape(_encode(tmp))) fwrite('\n' % self.name) def prepare_value(self, old_val): """\ turns a string of tokens separated by '|' into a list of boolean values """ try: old_val = old_val.split("|") except AttributeError: return list(old_val) ret = [] for l in self.labels: if l in old_val: ret.append(1) elif not l.startswith('#section#'): ret.append(0) return ret # end of class CheckListProperty class SpinProperty(Property, _activator): """\ Properties associated to a spin control. """ def __init__(self, owner, name, parent=None, can_disable=False, r=None, enabled=False, immediate=False, label=None): # r = range of the spin (min, max) Property.__init__(self, owner, name, parent, label=label) self.can_disable = can_disable self.immediate = immediate # if true, changes to this property have an # immediate effect (instead of waiting the # focus change...) _activator.__init__(self) if can_disable: self.toggle_active(enabled) if r is not None: self.val_range = (r[0], max(r[0], r[1])) else: self.val_range = None self.panel = None if parent is not None: self.display(parent) self.val = owner[name][0]() def display(self, parent): """\ Actually builds the spin control to set the value of the property interactively """ self.id = wx.NewId() if self.val_range is None: self.val_range = (0, 1000) lbl = getattr(self, 'label', None) if lbl is None: lbl = _mangle(self.dispName) label = wxGenStaticText(parent, -1, lbl, size=(_label_initial_width, -1)) tip = getattr(self, 'tooltip', None) if tip is None: tip = lbl label.SetToolTip(wx.ToolTip(tip)) if self.can_disable: self._enabler = wx.CheckBox(parent, self.id+1, '', size=(1, -1)) self.spin = wx.SpinCtrl(parent, self.id, min=self.val_range[0], max=self.val_range[1]) val = int(self.owner[self.name][0]()) if not val: self.spin.SetValue(1) # needed for GTK to display a '0' self.spin.SetValue(val) #int(self.owner[self.name][0]())) if self.can_disable: #self._enabler = wxCheckBox(parent, self.id+1, '', size=(1, -1)) wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda event: self.toggle_active(event.IsChecked())) self.spin.Enable(self.is_active()) self._enabler.SetValue(self.is_active()) self._target = self.spin sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) if getattr(self, '_enabler', None) is not None: sizer.Add(self._enabler, 1, wx.ALL|wx.ALIGN_CENTER, 3) option = 4 else: option = 5 sizer.Add(self.spin, option, wx.ALL|wx.ALIGN_CENTER, 3) self.panel = sizer self.bind_event(self.on_change_val) def bind_event(self, function): def func_2(event): if self.is_active(): function(event) event.Skip() wx.EVT_KILL_FOCUS(self.spin, func_2) if wx.Platform == '__WXMAC__' or self.immediate: wx.EVT_TEXT(self.spin, self.spin.GetId(), func_2) wx.EVT_SPINCTRL(self.spin, self.spin.GetId(), func_2) def get_value(self): try: return self.spin.GetValue() except AttributeError: return self.val def set_value(self, value): self.val = int(value) try: self.spin.SetValue(int(value)) except AttributeError: pass def set_range(self, min_v, max_v): self.val_range = (min_v, max(min_v, max_v)) try: self.spin.SetRange(min_v, max_v) except AttributeError: pass def write(self, outfile, tabs): if self.is_active(): Property.write(self, outfile, tabs) # end of class SpinProperty class DialogProperty(Property, _activator): """\ Property which selection is made through a dialog, which must provide a get_value method. """ def __init__(self, owner, name, parent, dialog, can_disable=False, enabled=False, label=None): Property.__init__(self, owner, name, parent, label=label) self.dialog = dialog self.panel = None self.can_disable = can_disable _activator.__init__(self) if can_disable: self.toggle_active(enabled) if parent is not None: self.display(parent) self.val = "%s" % owner[name][0]() def display(self, parent): """\ Actually builds the panel (with the text ctrl and the button to display the dialog) to set the value of the property interactively """ self.id = wx.NewId() val = misc.wxstr(self.owner[self.name][0]()) label = wxGenStaticText(parent, -1, _mangle(self.dispName), size=(_label_initial_width, -1)) label.SetToolTip(wx.ToolTip(_mangle(self.dispName))) if self.can_disable: self._enabler = wx.CheckBox(parent, self.id+1, '', size=(1, -1)) self.text = wx.TextCtrl(parent, self.id, val, size=(1, -1)) self.btn = wx.Button(parent, self.id+1, " ... ", size=(_label_initial_width, -1)) if self.can_disable: #self._enabler = wxCheckBox(parent, self.id+1, '', size=(1, -1)) wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda event: self.toggle_active(event.IsChecked())) self.text.Enable(self.is_active()) self.btn.Enable(self.is_active()) self._enabler.SetValue(self.is_active()) self._target = self.text wx.EVT_BUTTON(self.btn, self.id+1, self.display_dialog) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) if getattr(self, '_enabler', None) is not None: sizer.Add(self._enabler, 1, wx.ALL|wx.ALIGN_CENTER, 3) option = 3 else: option = 4 sizer.Add(self.text, option, wx.ALL|wx.ALIGN_CENTER, 3) sizer.Add(self.btn, 1, wx.ALL|wx.ALIGN_CENTER, 3) self.panel = sizer self.bind_event(self.on_change_val) wx.EVT_CHAR(self.text, self.on_char) def on_char(self, event): if event.GetKeyCode() == wx.WXK_ESCAPE: self.text.SetValue(self.val) self.text.SetInsertionPointEnd() event.Skip() def display_dialog(self, event): if self.dialog.ShowModal() == wx.ID_OK: self.text.SetValue(misc.wxstr(self.dialog.get_value())) self.text.ProcessEvent(wx.FocusEvent(wx.wxEVT_KILL_FOCUS, self.id)) def bind_event(self, function): wx.EVT_KILL_FOCUS(self.text, function) def get_value(self): try: return self.text.GetValue() except AttributeError: return self.val def set_value(self, value): self.val = misc.wxstr(value) try: self.text.SetValue(self.val) except AttributeError: pass def write(self, dest_file=None, tabs=0): if self.is_active(): Property.write(self, dest_file, tabs) def toggle_active(self, active): _activator.toggle_active(self, active) try: self.btn.Enable(active) except AttributeError: pass # end of class DialogProperty class FileDialogProperty(DialogProperty): dialog = [None] class FileDialog: def __init__(self, parent, message, wildcard, style, label=None): self.parent = parent self.message = message self.wildcard = wildcard self.style = style self.value = None def ShowModal(self): self.value = misc.FileSelector( self.message, wildcard=self.wildcard, flags=self.style) if self.value: return wx.ID_OK def get_value(self): return self.value # end of class FileDialog def __init__(self, owner, name, parent=None, wildcard=_("All Files|*"), message=_("Choose a file"), can_disable=True, style=0, label=None): if not self.dialog[0]: ## self.dialog[0] = wxFileDialog(parent, message, ## wildcard=wildcard, style=style) ## self.dialog[0].get_value = self.dialog[0].GetPath self.dialog[0] = self.FileDialog( parent, message, wildcard, style) DialogProperty.__init__(self, owner, name, parent, self.dialog[0], can_disable, label=label) # end of class FileDialogProperty from misc import _reverse_dict class ColorDialogProperty(DialogProperty): str_to_colors = { 'wxSYS_COLOUR_SCROLLBAR': wx.SYS_COLOUR_SCROLLBAR, 'wxSYS_COLOUR_BACKGROUND': wx.SYS_COLOUR_BACKGROUND, 'wxSYS_COLOUR_ACTIVECAPTION': wx.SYS_COLOUR_ACTIVECAPTION, 'wxSYS_COLOUR_INACTIVECAPTION': wx.SYS_COLOUR_INACTIVECAPTION, 'wxSYS_COLOUR_MENU': wx.SYS_COLOUR_MENU, 'wxSYS_COLOUR_WINDOW': wx.SYS_COLOUR_WINDOW, 'wxSYS_COLOUR_WINDOWFRAME': wx.SYS_COLOUR_WINDOWFRAME, 'wxSYS_COLOUR_MENUTEXT': wx.SYS_COLOUR_MENUTEXT, 'wxSYS_COLOUR_WINDOWTEXT': wx.SYS_COLOUR_WINDOWTEXT, 'wxSYS_COLOUR_CAPTIONTEXT': wx.SYS_COLOUR_CAPTIONTEXT, 'wxSYS_COLOUR_ACTIVEBORDER': wx.SYS_COLOUR_ACTIVEBORDER, 'wxSYS_COLOUR_INACTIVEBORDER': wx.SYS_COLOUR_INACTIVEBORDER, 'wxSYS_COLOUR_APPWORKSPACE': wx.SYS_COLOUR_APPWORKSPACE, 'wxSYS_COLOUR_HIGHLIGHT': wx.SYS_COLOUR_HIGHLIGHT, 'wxSYS_COLOUR_HIGHLIGHTTEXT': wx.SYS_COLOUR_HIGHLIGHTTEXT, 'wxSYS_COLOUR_BTNFACE': wx.SYS_COLOUR_BTNFACE, 'wxSYS_COLOUR_BTNSHADOW': wx.SYS_COLOUR_BTNSHADOW, 'wxSYS_COLOUR_GRAYTEXT': wx.SYS_COLOUR_GRAYTEXT, 'wxSYS_COLOUR_BTNTEXT': wx.SYS_COLOUR_BTNTEXT, 'wxSYS_COLOUR_INACTIVECAPTIONTEXT': wx.SYS_COLOUR_INACTIVECAPTIONTEXT, 'wxSYS_COLOUR_BTNHIGHLIGHT': wx.SYS_COLOUR_BTNHIGHLIGHT, 'wxSYS_COLOUR_3DDKSHADOW': wx.SYS_COLOUR_3DDKSHADOW, 'wxSYS_COLOUR_3DLIGHT': wx.SYS_COLOUR_3DLIGHT, 'wxSYS_COLOUR_INFOTEXT': wx.SYS_COLOUR_INFOTEXT, 'wxSYS_COLOUR_INFOBK': wx.SYS_COLOUR_INFOBK, 'wxSYS_COLOUR_DESKTOP': wx.SYS_COLOUR_DESKTOP, 'wxSYS_COLOUR_3DFACE': wx.SYS_COLOUR_3DFACE, 'wxSYS_COLOUR_3DSHADOW': wx.SYS_COLOUR_3DSHADOW, 'wxSYS_COLOUR_3DHIGHLIGHT': wx.SYS_COLOUR_3DHIGHLIGHT, 'wxSYS_COLOUR_3DHILIGHT': wx.SYS_COLOUR_3DHILIGHT, 'wxSYS_COLOUR_BTNHILIGHT': wx.SYS_COLOUR_BTNHILIGHT } colors_to_str = _reverse_dict(str_to_colors) dialog = [None] def __init__(self, owner, name, parent=None, can_disable=True, label=None): if not self.dialog[0]: from color_dialog import wxGladeColorDialog self.dialog[0] = wxGladeColorDialog(self.str_to_colors) DialogProperty.__init__(self, owner, name, parent, self.dialog[0], can_disable, label=label) def display_dialog(self, event): self.dialog.set_value(self.get_value()) DialogProperty.display_dialog(self, event) def toggle_active(self, active): DialogProperty.toggle_active(self, active) if not active: # restore the original value if toggled off color = self.owner._original.get(self.name, None) if color is not None and self.owner.widget is not None: which = 'Set%sColour' % self.name.capitalize() func = getattr(self.owner.widget, which, lambda c: None) func(color) self.owner.widget.Refresh() else: # restore the saved value getval, setval = self.owner[self.name] setval(getval()) # end of class ColorDialogProperty class FontDialogProperty(DialogProperty): font_families_to = { 'default': wx.DEFAULT, 'decorative': wx.DECORATIVE, 'roman': wx.ROMAN, 'swiss': wx.SWISS, 'script':wx.SCRIPT, 'modern': wx.MODERN } font_families_from = _reverse_dict(font_families_to) font_styles_to = { 'normal': wx.NORMAL, 'slant': wx.SLANT, 'italic': wx.ITALIC } font_styles_from = _reverse_dict(font_styles_to) font_weights_to = {'normal': wx.NORMAL, 'light': wx.LIGHT, 'bold': wx.BOLD } font_weights_from = _reverse_dict(font_weights_to) if misc.check_wx_version(2, 3, 3): font_families_to['teletype'] = wx.TELETYPE font_families_from[wx.TELETYPE] = 'teletype' dialog = [None] def __init__(self, owner, name, parent=None, can_disable=True, label=None): if not self.dialog[0]: import font_dialog self.dialog[0] = font_dialog.wxGladeFontDialog(parent, -1, "") DialogProperty.__init__(self, owner, name, parent, self.dialog[0], can_disable, label=label) def display_dialog(self, event): try: props = eval(self.get_value()) except: import traceback; traceback.print_exc() else: if len(props) == 6: self.dialog.set_value(props) DialogProperty.display_dialog(self, event) def write(self, outfile=None, tabs=0): if self.is_active(): try: props = [_encode(s) for s in eval(self.get_value().strip())] except: import traceback traceback.print_exc() return if len(props) < 6: print _('error in the value of the property "%s"') % self.name return fwrite = outfile.write fwrite(' ' * tabs + '<%s>\n' % self.name) tstr = ' ' * (tabs+1) fwrite('%s%s\n' % (tstr, escape(props[0]))) fwrite('%s%s\n' % (tstr, escape(props[1]))) fwrite('%s\n' % (tstr, escape(props[2]))) fwrite('%s%s\n' % (tstr, escape(props[3]))) fwrite('%s%s\n' % (tstr, escape(props[4]))) fwrite('%s%s\n' % (tstr, escape(props[5]))) fwrite(' ' * tabs + '\n' % self.name) def toggle_active(self, active): DialogProperty.toggle_active(self, active) if not active: # restore the original value if toggled off font = self.owner._original['font'] if font is not None and self.owner.widget is not None: self.owner.widget.SetFont(font) self.owner.widget.Refresh() else: # restore the saved value getval, setval = self.owner[self.name] setval(getval()) # end of class FontDialogProperty class RadioProperty(Property, _activator): """\ properties controlled by a series of radio buttons. """ def __init__(self, owner, name, parent, choices, can_disable=False, enabled=False, columns=1, label=None): Property.__init__(self, owner, name, parent, label=label) self.can_disable = can_disable _activator.__init__(self) if can_disable: self.toggle_active(enabled) self.choices = choices self.columns = columns self.panel = None self.label = label if label is None: self.label = _mangle(name) if parent is not None: self.display(parent) self.val = owner[name][0]() def display(self, parent): """\ Actually builds the radio box to set the value of the property interactively """ self.id = wx.NewId() style = wx.RA_SPECIFY_COLS|wx.NO_BORDER|wx.CLIP_CHILDREN if not self.can_disable: szr = wx.BoxSizer(wx.HORIZONTAL) style=wx.RA_SPECIFY_COLS else: szr = wx.StaticBoxSizer(wx.StaticBox(parent, -1, self.label), wx.HORIZONTAL) self.options = wx.RadioBox(parent, self.id, self.label, choices=self.choices, majorDimension=self.columns, style=style) try: self.options.SetSelection(int(self.val)) except: pass if self.can_disable: self._enabler = wx.CheckBox(parent, self.id+1, "") szr.Add(self._enabler) wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda e: self.toggle_active(e.IsChecked())) self.options.Enable(self.is_active()) self.options.SetLabel("") self._enabler.SetValue(self.is_active()) szr.Add(self.options, 1, wx.EXPAND) self.panel = szr self.bind_event(self.on_change_val) def bind_event(self, function): def func_2(event, function=function, self=self): if self.options.IsEnabled(): function(event) wx.EVT_RADIOBOX(self.options, self.id, func_2) def get_value(self): try: return self.options.GetSelection() except AttributeError: return self.val def get_str_value(self): try: return self.options.GetStringSelection() except AttributeError: if 0 <= self.val < len(self.choices): return self.choices[self.val] else: return '' def set_value(self, value): try: self.val = int(value) except ValueError: self.val = self.choices.index(value) try: self.options.SetSelection(self.val) except AttributeError: pass def set_str_value(self, value): try: self.val = self.choices.index(value) self.options.SetSelection(self.val) except (AttributeError, ValueError): pass def write(self, outfile, tabs): if self.is_active(): outfile.write(' ' * tabs + '<%s>%s\n' % (self.name, escape(_encode(self.get_str_value())), self.name)) # end of class RadioProperty class GridProperty(Property): """\ Property whose values are modified through a wxGrid table. """ STRING, INT, FLOAT, BOOL = 0, 1, 2, 3 col_format = [lambda g, c: None, lambda g, c: g.SetColFormatNumber(c), lambda g, c: g.SetColFormatFloat(c), lambda g, c: g.SetColFormatBool(c)] def __init__(self, owner, name, parent, cols, rows=1, can_add=True, can_remove=True, can_insert=True, label=None): # cols: list of 2-tuples with these fields: # - label for the column # - type: GridProperty.STRING, GridProperty.INT, GridProperty.FLOAT # rows: number of rows Property.__init__(self, owner, name, parent, label=label) self.val = owner[name][0]() self.set_value(self.val) self.rows, self.cols = rows, cols self.can_add = can_add self.can_remove = can_remove self.can_insert = can_insert self.panel = None self.cur_row = 0 if parent is not None: self.display(parent) def display(self, parent): """\ Actually builds the grid to set the value of the property interactively """ self.panel = wx.Panel(parent, -1) # why if the grid is not on this # panel it is not displayed??? label = getattr(self, 'label', _mangle(self.dispName)) sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label), wx.VERTICAL) self.btn_id = wx.NewId() self.btn = wx.Button(self.panel, self.btn_id, _(" Apply "), style=wx.BU_EXACTFIT) if self.can_add: self.add_btn = wx.Button(self.panel, self.btn_id+1, _(" Add "), style=wx.BU_EXACTFIT) if self.can_insert: self.insert_btn = wx.Button(self.panel, self.btn_id+3, _(" Insert "), style=wx.BU_EXACTFIT) if self.can_remove: self.remove_btn = wx.Button(self.panel, self.btn_id+2, _(" Remove "), style=wx.BU_EXACTFIT) self.grid = wx.grid.Grid(self.panel, -1) self.grid.CreateGrid(self.rows, len(self.cols)) if misc.check_wx_version(2, 3, 3): self.grid.SetMargins(0, 0) else: # wx 2.3.2 seems to have some problems with grid scrollbars... self.grid.SetMargins(0, self.grid.GetDefaultRowSize()) for i in range(len(self.cols)): self.grid.SetColLabelValue(i, misc.wxstr(self.cols[i][0])) GridProperty.col_format[self.cols[i][1]](self.grid, i) self.cols = len(self.cols) self.grid.SetRowLabelSize(0) self.grid.SetColLabelSize(20) self.btn_sizer = wx.BoxSizer(wx.HORIZONTAL) _w = self.btn.GetTextExtent(self.btn.GetLabel())[0] if misc.check_wx_version(2, 5, 2): extra_flag = wx.FIXED_MINSIZE else: extra_flag = 0 #self.btn.SetSize((_w, -1)) self.btn_sizer.Add(self.btn, 0, extra_flag) if self.can_add: _w = self.add_btn.GetTextExtent(self.add_btn.GetLabel())[0] #self.add_btn.SetSize((_w, -1)) self.btn_sizer.Add(self.add_btn, 0, wx.LEFT|wx.RIGHT|extra_flag, 4) wx.EVT_BUTTON(self.add_btn, self.btn_id+1, self.add_row) if self.can_insert: _w = self.insert_btn.GetTextExtent(self.insert_btn.GetLabel())[0] #self.insert_btn.SetSize((_w, -1)) self.btn_sizer.Add( self.insert_btn, 0, wx.LEFT|wx.RIGHT|extra_flag, 4) wx.EVT_BUTTON(self.insert_btn, self.btn_id+3, self.insert_row) if self.can_remove: _w = self.remove_btn.GetTextExtent(self.remove_btn.GetLabel())[0] #self.remove_btn.SetSize((_w, -1)) self.btn_sizer.Add(self.remove_btn, 0, extra_flag) wx.EVT_BUTTON(self.remove_btn, self.btn_id+2, self.remove_row) sizer.Add(self.btn_sizer, 0, wx.BOTTOM|wx.EXPAND, 2) sizer.Add(self.grid, 1, wx.EXPAND) self.panel.SetAutoLayout(1) self.panel.SetSizer(sizer) self.panel.SetSize(sizer.GetMinSize()) wx.grid.EVT_GRID_SELECT_CELL(self.grid, self.on_select_cell) self.bind_event(self.on_change_val) self.set_value(self.val) def on_select_cell(self, event): self.cur_row = event.GetRow() event.Skip() def bind_event(self, function): def func(event): self.grid.SaveEditControlValue() function(event) wx.EVT_BUTTON(self.btn, self.btn_id, func) def get_value(self): if not hasattr(self, 'grid'): return self.val l = [] for i in range(self.rows): l2 = [] for j in range(self.cols): l2.append(self.grid.GetCellValue(i, j)) l.append(l2) return l def on_change_val(self, event, first=[True]): """\ Event handler called to notify owner that the value of the Property has changed """ val = self.get_value() def ok(): if len(self.val) != len(val): return True for i in range(len(val)): for j in range(len(val[i])): if not misc.streq(val[i][j], self.val[i][j]): return True return False if ok(): common.app_tree.app.saved = False # update the status of the app if self.setter: self.setter(val) else: self.owner[self.name][1](val) self.val = val first[0] = False event.Skip() def set_value(self, values): #self.val = values self.val = [[misc.wxstr(v) for v in val] for val in values] if not hasattr(self, 'grid'): return # values is a list of lists with the values of the cells size = len(values) if self.rows < size: self.grid.AppendRows(size-self.rows) self.rows = size elif self.rows != size: self.grid.DeleteRows(size, self.rows-size) for i in range(len(self.val)): for j in range(len(self.val[i])): self.grid.SetCellValue(i, j, self.val[i][j]) def add_row(self, event): self.grid.AppendRows() self.grid.MakeCellVisible(self.rows, 0) self.grid.ForceRefresh() self.rows += 1 def remove_row(self, event): if self.rows > 0: #1: self.grid.DeleteRows(self.cur_row) self.rows -= 1 def insert_row(self, event): self.grid.InsertRows(self.cur_row) self.grid.MakeCellVisible(self.cur_row, 0) self.grid.ForceRefresh() self.rows += 1 def set_col_sizes(self, sizes): """\ sets the width of the columns. sizes is a list of integers with the size of each column: a value of 0 stands for a default size, while -1 means to expand the column to fit the available space (at most one column can have size -1) """ col_to_expand = -1 total_w = 0 for i in range(self.grid.GetNumberCols()): try: w = sizes[i] except IndexError: return if not w: self.grid.AutoSizeColumn(i) total_w += self.grid.GetColSize(i) elif w < 0: col_to_expand = i else: self.grid.SetColSize(i, w) total_w += w if col_to_expand >= 0: self.grid.AutoSizeColumn(col_to_expand) w = self.grid.GetSize()[0] - total_w if w >= self.grid.GetColSize(col_to_expand): self.grid.SetColSize(col_to_expand, w) # end of class GridProperty class ComboBoxProperty(Property, _activator): """\ Properties whose values can be changed with a combobox. """ def __init__(self, owner, name, choices, parent=None, label=None, can_disable=False, enabled=False, write_always=False): Property.__init__(self, owner, name, parent, label=label) self.val = misc.wxstr(owner[name][0]()) if label is None: label = _mangle(name) self.label = label self.panel = None self.write_always = write_always self.choices = choices self.can_disable = can_disable _activator.__init__(self) if can_disable: self.toggle_active(enabled) if parent is not None: self.display(parent) def display(self, parent): """\ Actually builds the check box to set the value of the property interactively """ self.id = wx.NewId() self.cb = wx.ComboBox(parent, self.id, choices=self.choices, style=wx.CB_DROPDOWN|wx.CB_READONLY) self.cb.SetValue(self.val) if self.can_disable: self._enabler = wx.CheckBox(parent, self.id+1, '', size=(1, -1)) label = wx.StaticText(parent, -1, self.label) if self.can_disable: wx.EVT_CHECKBOX(self._enabler, self.id+1, lambda event: self.toggle_active(event.IsChecked())) self.cb.Enable(self.is_active()) self._enabler.SetValue(self.is_active()) self._target = self.cb sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 2, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3) if getattr(self, '_enabler', None) is not None: sizer.Add(self._enabler, 1, wx.ALL|wx.ALIGN_CENTER, 3) option = 4 else: option = 5 sizer.Add(self.cb, option, wx.ALIGN_CENTER|wx.ALL, 3) self.panel = sizer self.bind_event(self.on_change_val) def bind_event(self, function): wx.EVT_COMBOBOX(self.cb, self.id, function) def get_value(self): try: return misc.wxstr(self.cb.GetValue()) except AttributeError: return misc.wxstr(self.val) def set_value(self, val): self.val = misc.wxstr(val) try: self.cb.SetValue(self.val) except AttributeError: pass def write(self, outfile, tabs): if self.write_always or self.get_value(): if self.getter: value = misc.wxstr(self.getter()) else: value = misc.wxstr(self.owner[self.name][0]()) if value != 'None': fwrite = outfile.write fwrite(' ' * tabs + '<%s>' % self.name) fwrite(escape(_encode(value))) fwrite('\n' % self.name) # end of class ComboBoxProperty spe-0.8.4.h/_spe/plugins/wxGlade/color_dialog.py0000644000175000017500000001031710743421035020570 0ustar stanistani# generated by wxGlade 0.2 on Sat Dec 7 14:30:59 2002 # $Id: color_dialog.py,v 1.11 2007/01/27 19:59:29 dinogen Exp $ #from wxPython.wx import * #from wxPyColourChooser import wxPyColourChooser #from wxPython.lib.colourchooser import wxPyColourChooser import wx from wx.lib.colourchooser import PyColourChooser import misc class wxGladeColorDialog(wx.Dialog): def __init__(self, colors_dict): wx.Dialog.__init__(self, None, -1, "") self.colors_dict = colors_dict choices = self.colors_dict.keys() choices.sort() # begin wxGlade: wxGladeColorDialog.__init__ self.panel_1 = wx.Panel(self, -1) self.use_sys_color = wx.RadioButton(self.panel_1, -1, _("System colour"), style=wx.RB_SINGLE) self.sys_color = wx.ComboBox(self.panel_1, -1, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY) self.use_chooser = wx.RadioButton(self.panel_1, -1, _("Custom colour"), style=wx.RB_SINGLE) self.color_chooser = PyColourChooser(self, -1) self.ok = wx.Button(self, wx.ID_OK, _("OK")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.__set_properties() self.__do_layout() # end wxGlade wx.EVT_RADIOBUTTON(self, self.use_sys_color.GetId(), self.on_use_sys_color) wx.EVT_RADIOBUTTON(self, self.use_chooser.GetId(), self.on_use_chooser) def on_use_sys_color(self, event): self.sys_color.Enable(True) self.color_chooser.Enable(False) self.use_chooser.SetValue(0) def on_use_chooser(self, event): self.sys_color.Enable(False) self.color_chooser.Enable(True) self.use_sys_color.SetValue(0) def get_value(self): if self.use_sys_color.GetValue(): return self.sys_color.GetStringSelection() else: return misc.color_to_string(self.color_chooser.GetValue()) def set_value(self, value): value = value.strip() if value in self.colors_dict: self.use_sys_color.SetValue(1) self.use_chooser.SetValue(0) self.sys_color.SetValue(value) self.sys_color.Enable(True) self.color_chooser.Enable(False) else: self.use_chooser.SetValue(1) self.use_sys_color.SetValue(0) try: self.color_chooser.SetValue(misc.string_to_color(value)) except: pass self.sys_color.Enable(False) self.color_chooser.Enable(True) def __set_properties(self): # begin wxGlade: wxGladeColorDialog.__set_properties self.SetTitle(_("Select widget colour")) self.use_sys_color.SetValue(1) self.sys_color.SetSelection(0) self.ok.SetDefault() # end wxGlade self.use_chooser.SetValue(0) self.color_chooser.Enable(False) def __do_layout(self): # begin wxGlade: wxGladeColorDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.VERTICAL) sizer_2.Add(self.use_sys_color, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, 5) sizer_2.Add(self.sys_color, 0, wx.ALL|wx.EXPAND, 5) static_line_1 = wx.StaticLine(self.panel_1, -1) sizer_2.Add(static_line_1, 0, wx.ALL|wx.EXPAND, 5) sizer_2.Add(self.use_chooser, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, 5) self.panel_1.SetAutoLayout(1) self.panel_1.SetSizer(sizer_2) sizer_2.Fit(self.panel_1) sizer_2.SetSizeHints(self.panel_1) sizer_1.Add(self.panel_1, 0, wx.EXPAND, 0) sizer_1.Add(self.color_chooser, 0, wx.ALL, 5) static_line_1_copy = wx.StaticLine(self, -1) sizer_1.Add(static_line_1_copy, 0, wx.ALL|wx.EXPAND, 5) sizer_3.Add(self.ok, 0, wx.RIGHT, 13) sizer_3.Add(self.cancel, 0, 0, 5) sizer_1.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 10) self.SetAutoLayout(1) self.SetSizer(sizer_1) sizer_1.Fit(self) sizer_1.SetSizeHints(self) self.Layout() # end wxGlade self.CenterOnScreen() # end of class wxGladeColorDialog spe-0.8.4.h/_spe/plugins/wxGlade/msgdialog.py0000755000175000017500000000401710743421035020104 0ustar stanistani#!/usr/bin/env python # -*- coding: iso-8859-1 -*- # generated by wxGlade 0.6 on Sat Sep 1 01:40:08 2007 import wx # begin wxGlade: extracode # end wxGlade class MessageDialog(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: MessageDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.msg_title = wx.StaticText(self, -1, _("wxGlade message")) self.msg_image = wx.StaticBitmap(self, -1, (wx.ArtProvider_GetBitmap(wx.ART_TIP, wx.ART_MESSAGE_BOX, (48, 48)))) self.msg_list = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.LC_NO_HEADER|wx.LC_SINGLE_SEL|wx.SUNKEN_BORDER) self.OK = wx.Button(self, wx.ID_OK, "") self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: MessageDialog.__set_properties self.SetTitle(_("wxGlade message")) self.SetSize(wx.DLG_SZE(self, (250, 112))) self.msg_title.SetFont(wx.Font(-1, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) self.msg_image.SetMinSize((48, 48)) # end wxGlade def __do_layout(self): # begin wxGlade: MessageDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_1.Add(self.msg_title, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5) sizer_2.Add(self.msg_image, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) sizer_2.Add(self.msg_list, 1, wx.LEFT|wx.EXPAND, 10) sizer_1.Add(sizer_2, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) sizer_1.Add(self.OK, 0, wx.ALL|wx.ALIGN_RIGHT, 10) self.SetSizer(sizer_1) self.Layout() self.Centre() # end wxGlade # end of class MessageDialog if __name__ == "__main__": import gettext gettext.install("app") # replace with the appropriate catalog name app = wx.PySimpleApp(0) wx.InitAllImageHandlers() dialog_1 = MessageDialog(None, -1, "") app.SetTopWindow(dialog_1) dialog_1.Show() app.MainLoop() spe-0.8.4.h/_spe/plugins/wxGlade/layout_option_property.py0000644000175000017500000001263510743421035023011 0ustar stanistani# layout_option_property.py: Property class for the 'option' layout property of # widgets and non-toplevel sizers # $Id: layout_option_property.py,v 1.5 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * import wx import widget_properties #from edit_sizers import EditGridBagSizer def _is_gridbag(sizer): return False class LayoutOptionProperty(widget_properties.Property): def __init__(self, owner, sizer, parent=None): self.is_gridbag = _is_gridbag(sizer) widget_properties.Property.__init__(self, owner, 'option', parent) self.panel = None if parent is not None: self.display(parent) self.val = owner['option'][0]() def display(self, parent): if not self.is_gridbag: self._display_spin(parent) def _display_spin(self, parent): """\ Actually builds the spin control to set the value of the property interactively """ self.id = wx.NewId() self.val_range = (0, 1000) size = (widget_properties._label_initial_width, -1) label = widget_properties.wxGenStaticText(parent, -1, _('Proportion'), size=size) label.SetToolTip(wx.ToolTip(_('Proportion'))) self.spin = wx.SpinCtrl(parent, self.id, min=self.val_range[0], max=self.val_range[1]) val = int(self.owner[self.name][0]()) if not val: self.spin.SetValue(1) # needed for GTK to display a '0' self.spin.SetValue(val) #int(self.owner[self.name][0]())) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) option = 5 sizer.Add(self.spin, option, wx.ALL|wx.ALIGN_CENTER, 3) self.panel = sizer self.bind_event(self.on_change_val) def _display_gridbag(self, parent): sizer = wx.BoxSizer(wx.VERTICAL) size = (widget_properties._label_initial_width, -1) val = self.owner[self.name][0]() szr = wx.BoxSizer(wx.HORIZONTAL) label = widget_properties.wxGenStaticText(parent, -1, _('Position'), size=size) label.SetToolTip(wx.ToolTip(_('Position'))) szr.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) self.position = wx.TextCtrl(parent, -1) self.position.SetValue(val[:2]) szr.Add(self.position, 5, wx.ALL|wx.ALIGN_CENTER, 3) sizer.Add(szr, 0, wx.EXPAND) szr = wx.BoxSizer(wx.HORIZONTAL) label = widget_properties.wxGenStaticText(parent, -1, _('Span'), size=size) label.SetToolTip(wx.ToolTip(_('Span'))) szr.Add(label, 2, wx.ALL|wx.ALIGN_CENTER, 3) self.span = wx.TextCtrl(parent, -1) self.span.SetValue(val[2:]) szr.Add(self.span, 5, wx.ALL|wx.ALIGN_CENTER, 3) sizer.Add(szr, 0, wx.EXPAND) self.panel = sizer self.bind_event(self.on_change_val) def bind_event(self, function): if not self.is_gridbag: self._bind_event_spin(function) else: self._bind_event_gridbag(function) def _bind_event_spin(self, function): wx.EVT_KILL_FOCUS(self.spin, function) if wx.Platform == '__WXMAC__': wx.EVT_TEXT(self.spin, self.spin.GetId(), function) wx.EVT_SPINCTRL(self.spin, self.spin.GetId(), function) def _bind_event_gridbag(self, function): wx.EVT_KILL_FOCUS(self.position, function) wx.EVT_KILL_FOCUS(self.span, function) def get_value(self): if not self.is_gridbag: try: return self.spin.GetValue() except AttributeError: return self.val else: try: return ", ".join([self.position.GetValue(), self.span.GetValue()]) except AttributeError: return self.val def set_value(self, value): if not self.is_gridbag: self.val = int(value) try: self.spin.SetValue(int(value)) except AttributeError: pass else: self.val = value try: self.position.SetValue(value[:2]) self.span.SetValue(value[2:]) except AttributeError: pass def set_range(self, min_v, max_v): if not self.is_gridbag: self.val_range = (min_v, max_v) try: self.spin.SetRange(min_v, max_v) except AttributeError: pass def set_sizer(self, sizer): self.is_gridbag = _is_gridbag(sizer) # end of class LayoutOptionProperty class LayoutPosProperty(widget_properties.SpinProperty): def __init__(self, owner, sizer, parent=None): self.is_gridbag = _is_gridbag(sizer) widget_properties.SpinProperty.__init__( self, owner, 'pos', parent, 0, (0, 1000))#, immediate=True) self.label = _('Position') def set_sizer(self, sizer): self.is_gridbag = _is_gridbag(sizer) def display(self, parent): if not self.is_gridbag: widget_properties.SpinProperty.display(self, parent) else: self.panel = (0, 0) def write(self, *args, **kwds): pass # end of class LayoutPosProperty spe-0.8.4.h/_spe/plugins/wxGlade/main.py0000644000175000017500000011333610743421035017064 0ustar stanistani# main.py: Main wxGlade module: defines wxGladeFrame which contains the buttons # to add widgets and initializes all the stuff (tree, property_frame, etc.) # $Id: main.py,v 1.84 2007/08/07 12:21:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wxversion wxversion.ensureMinimal("2.6") #from wxPython.wx import * import wx from widget_properties import * from tree import Tree, WidgetTree import edit_sizers import common, os, os.path, misc, config import clipboard import xml_parse import template class wxGladePropertyPanel(wx.Panel): """\ Panel used to display the Properties of the various widgets """ def SetTitle(self, title): try: self.GetParent().SetTitle(title) except AttributeError: pass def Layout(self): if self.is_visible(): wx.Panel.Layout(self) self.GetParent().Layout() def is_visible(self): return self.GetParent().IsShown() # end of class wxGladePropertyPanel TOGGLE_BOX_EVENT = wx.NewEventType() def EVT_TOGGLE_BOX(win, id, func): win.Connect(id, -1, TOGGLE_BOX_EVENT, func) class ToggleBoxEvent(wx.PyCommandEvent): def __init__(self, id, value, strval): wx.PyCommandEvent.__init__(self) self.SetId(id) self.SetEventType(TOGGLE_BOX_EVENT) self.value = value self.strval = strval def GetValue(self): return self.value def GetStringValue(self): return self.strval # end of class ToggleBoxEvent class ToggleButtonBox(wx.Panel): def __init__(self, parent, id, choices=[], value=0): wx.Panel.__init__(self, parent, id) self.buttons = [wx.ToggleButton(self, -1, c) for c in choices] self.selected = None self.SetValue(value) for b in self.buttons: def handler(event, b=b): self.on_toggle(b, event) wx.EVT_TOGGLEBUTTON(self, b.GetId(), handler) sizer = wx.BoxSizer(wx.VERTICAL) for b in self.buttons: sizer.Add(b, 0, wx.ALL|wx.EXPAND, 1) self.SetAutoLayout(True) self.SetSizer(sizer) sizer.Fit(self) sizer.SetSizeHints(self) def on_toggle(self, button, event): if self.selected is button: self.selected.SetValue(True) return if self.selected is not None: self.selected.SetValue(False) self.selected = button wx.PostEvent(self, ToggleBoxEvent(self.GetId(), self.GetValue(), self.GetStringValue())) def GetValue(self): if self.selected is not None: return self.buttons.index(self.selected) return -1 def GetStringValue(self): if self.selected is None: return None return self.selected.GetLabel() def SetValue(self, index): if self.selected is not None: self.selected.SetValue(False) if -1 < index < len(self.buttons): self.selected = self.buttons[index] self.selected.SetValue(True) def SetStringValue(self, strval): index = -1 for i in range(len(self.buttons)): if self.buttons[i].GetLabel() == strval: index = i break self.SetValue(index) # end of class ToggleButtonBox class wxGladeArtProvider(wx.ArtProvider): def CreateBitmap(self, artid, client, size): if wx.Platform == '__WXGTK__' and artid == wx.ART_FOLDER: return wx.Bitmap(os.path.join(common.wxglade_path, 'icons', 'closed_folder.xpm'), wx.BITMAP_TYPE_XPM) return wx.NullBitmap # end of class wxGladeArtProvider class wxGladeFrame(wx.Frame): """\ Main frame of wxGlade (palette) """ def __init__(self, parent=None): style = wx.SYSTEM_MENU|wx.CAPTION|wx.MINIMIZE_BOX|wx.RESIZE_BORDER if misc.check_wx_version(2, 5): style |= wx.CLOSE_BOX wx.Frame.__init__(self, parent, -1, "wxGlade v%s" % common.version, style=style) self.CreateStatusBar(1) if parent is None: parent = self common.palette = self # to provide a reference accessible # by the various widget classes icon = wx.EmptyIcon() bmp = wx.Bitmap(os.path.join(common.wxglade_path, "icons/icon.xpm"), wx.BITMAP_TYPE_XPM) icon.CopyFromBitmap(bmp) self.SetIcon(icon) self.SetBackgroundColour(wx.SystemSettings_GetColour( wx.SYS_COLOUR_BTNFACE)) menu_bar = wx.MenuBar() file_menu = wx.Menu(style=wx.MENU_TEAROFF) view_menu = wx.Menu(style=wx.MENU_TEAROFF) help_menu = wx.Menu(style=wx.MENU_TEAROFF) wx.ToolTip_SetDelay(1000) # load the available code generators common.load_code_writers() # load the available widgets and sizers core_btns, custom_btns = common.load_widgets() sizer_btns = common.load_sizers() append_item = misc.append_item self.TREE_ID = TREE_ID = wx.NewId() append_item(view_menu, TREE_ID, _("Show &Tree\tF2")) self.PROPS_ID = PROPS_ID = wx.NewId() self.RAISE_ID = RAISE_ID = wx.NewId() append_item(view_menu, PROPS_ID, _("Show &Properties\tF3")) append_item(view_menu, RAISE_ID, _("&Raise All\tF4")) NEW_ID = wx.NewId() append_item(file_menu, NEW_ID, _("&New\tCtrl+N"), wx.ART_NEW) NEW_FROM_TEMPLATE_ID = wx.NewId() append_item(file_menu, NEW_FROM_TEMPLATE_ID, _("New from &Template...\tShift+Ctrl+N")) OPEN_ID = wx.NewId() append_item(file_menu, OPEN_ID, _("&Open...\tCtrl+O"), wx.ART_FILE_OPEN) SAVE_ID = wx.NewId() append_item(file_menu, SAVE_ID, _("&Save\tCtrl+S"), wx.ART_FILE_SAVE) SAVE_AS_ID = wx.NewId() append_item(file_menu, SAVE_AS_ID, _("Save As...\tShift+Ctrl+S"), wx.ART_FILE_SAVE_AS) SAVE_TEMPLATE_ID = wx.NewId() append_item(file_menu, SAVE_TEMPLATE_ID, _("Save As Template...")) file_menu.AppendSeparator() RELOAD_ID = wx.ID_REFRESH #wx.NewId() append_item(file_menu, RELOAD_ID, _("&Refresh\tf5")) #, wx.ART_REDO) GENERATE_CODE_ID = wx.NewId() append_item(file_menu, GENERATE_CODE_ID, _("&Generate Code\tCtrl+G"), wx.ART_EXECUTABLE_FILE) file_menu.AppendSeparator() IMPORT_ID = wx.NewId() append_item(file_menu, IMPORT_ID, _("&Import from XRC...\tCtrl+I")) EXIT_ID = wx.NewId() file_menu.AppendSeparator() append_item(file_menu, EXIT_ID, _('E&xit\tCtrl+Q'), wx.ART_QUIT) PREFS_ID = wx.ID_PREFERENCES #NewId() view_menu.AppendSeparator() MANAGE_TEMPLATES_ID = wx.NewId() append_item(view_menu, MANAGE_TEMPLATES_ID, _('Templates Manager...')) view_menu.AppendSeparator() append_item(view_menu, PREFS_ID, _('Preferences...')) #wx.ART_HELP_SETTINGS) menu_bar.Append(file_menu, _("&File")) menu_bar.Append(view_menu, _("&View")) TUT_ID = wx.NewId() append_item(help_menu, TUT_ID, _('Contents\tF1'), wx.ART_HELP) ABOUT_ID = wx.ID_ABOUT #wx.NewId() append_item(help_menu, ABOUT_ID, _('About...'))#, wx.ART_QUESTION) menu_bar.Append(help_menu, _('&Help')) parent.SetMenuBar(menu_bar) # Mac tweaks... if wx.Platform == "__WXMAC__": wx.App_SetMacAboutMenuItemId(ABOUT_ID) wx.App_SetMacPreferencesMenuItemId(PREFS_ID) wx.App_SetMacExitMenuItemId(EXIT_ID) wx.App_SetMacHelpMenuTitleName(_('&Help')) # file history support if misc.check_wx_version(2, 3, 3): self.file_history = wx.FileHistory( config.preferences.number_history) self.file_history.UseMenu(file_menu) files = config.load_history() files.reverse() for path in files: self.file_history.AddFileToHistory(path.strip()) def open_from_history(event): if not self.ask_save(): return infile = self.file_history.GetHistoryFile( event.GetId() - wx.ID_FILE1) # ALB 2004-10-15 try to restore possible autosave content... if common.check_autosaved(infile) and \ wx.MessageBox(_("There seems to be auto saved data for " "this file: do you want to restore it?"), _("Auto save detected"), style=wx.ICON_QUESTION|wx.YES_NO) == wx.YES: common.restore_from_autosaved(infile) else: common.remove_autosaved(infile) self._open_app(infile) wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, open_from_history) wx.EVT_MENU(self, TREE_ID, self.show_tree) wx.EVT_MENU(self, PROPS_ID, self.show_props_window) wx.EVT_MENU(self, RAISE_ID, self.raise_all) wx.EVT_MENU(self, NEW_ID, self.new_app) wx.EVT_MENU(self, NEW_FROM_TEMPLATE_ID, self.new_app_from_template) wx.EVT_MENU(self, OPEN_ID, self.open_app) wx.EVT_MENU(self, SAVE_ID, self.save_app) wx.EVT_MENU(self, SAVE_AS_ID, self.save_app_as) wx.EVT_MENU(self, SAVE_TEMPLATE_ID, self.save_app_as_template) def generate_code(event): common.app_tree.app.generate_code() wx.EVT_MENU(self, GENERATE_CODE_ID, generate_code) wx.EVT_MENU(self, EXIT_ID, lambda e: self.Close()) wx.EVT_MENU(self, TUT_ID, self.show_tutorial) wx.EVT_MENU(self, ABOUT_ID, self.show_about_box) wx.EVT_MENU(self, PREFS_ID, self.edit_preferences) wx.EVT_MENU(self, MANAGE_TEMPLATES_ID, self.manage_templates) wx.EVT_MENU(self, IMPORT_ID, self.import_xrc) wx.EVT_MENU(self, RELOAD_ID, self.reload_app) PREVIEW_ID = wx.NewId() def preview(event): if common.app_tree.cur_widget is not None: p = misc.get_toplevel_widget(common.app_tree.cur_widget) if p is not None: p.preview(None) wx.EVT_MENU(self, PREVIEW_ID, preview) self.accel_table = wx.AcceleratorTable([ (wx.ACCEL_CTRL, ord('N'), NEW_ID), (wx.ACCEL_CTRL, ord('O'), OPEN_ID), (wx.ACCEL_CTRL, ord('S'), SAVE_ID), (wx.ACCEL_CTRL|wx.ACCEL_SHIFT, ord('S'), SAVE_AS_ID), (wx.ACCEL_CTRL, ord('G'), GENERATE_CODE_ID), (wx.ACCEL_CTRL, ord('I'), IMPORT_ID), (0, wx.WXK_F1, TUT_ID), (wx.ACCEL_CTRL, ord('Q'), EXIT_ID), (0, wx.WXK_F5, RELOAD_ID), (0, wx.WXK_F2, TREE_ID), (0, wx.WXK_F3, PROPS_ID), (0, wx.WXK_F4, RAISE_ID), (wx.ACCEL_CTRL, ord('P'), PREVIEW_ID), ]) # Tutorial window ## self.tut_frame = None # layout # if there are custom components, add the toggle box... if custom_btns: main_sizer = wx.BoxSizer(wx.VERTICAL) show_core_custom = ToggleButtonBox( self, -1, [_("Core components"), _("Custom components")], 0) if misc.check_wx_version(2, 5): core_sizer = wx.FlexGridSizer( 0, config.preferences.buttons_per_row) custom_sizer = wx.FlexGridSizer( 0, config.preferences.buttons_per_row) else: core_sizer = wx.GridSizer( 0, config.preferences.buttons_per_row) custom_sizer = wx.GridSizer( 0, config.preferences.buttons_per_row) self.SetAutoLayout(True) # core components for b in core_btns: core_sizer.Add(b) for sb in sizer_btns: core_sizer.Add(sb) # custom components for b in custom_btns: custom_sizer.Add(b) if misc.check_wx_version(2, 5): custom_sizer.Show(b, False) custom_sizer.Layout() main_sizer.Add(show_core_custom, 0, wx.EXPAND) main_sizer.Add(core_sizer, 0, wx.EXPAND) main_sizer.Add(custom_sizer, 0, wx.EXPAND) self.SetSizer(main_sizer) if not misc.check_wx_version(2, 5): main_sizer.Show(custom_sizer, False) #main_sizer.Show(1, False) main_sizer.Fit(self) # events to display core/custom components if misc.check_wx_version(2, 5): def on_show_core_custom(event): show_core = True show_custom = False if event.GetValue() == 1: show_core = False show_custom = True for b in custom_btns: custom_sizer.Show(b, show_custom) for b in core_btns: core_sizer.Show(b, show_core) for b in sizer_btns: core_sizer.Show(b, show_core) core_sizer.Layout() custom_sizer.Layout() main_sizer.Layout() else: def on_show_core_custom(event): to_show = core_sizer to_hide = custom_sizer if event.GetValue() == 1: to_show, to_hide = to_hide, to_show main_sizer.Show(to_show, True) main_sizer.Show(to_hide, False) main_sizer.Layout() EVT_TOGGLE_BOX(self, show_core_custom.GetId(), on_show_core_custom) # ... otherwise (the common case), just add the palette of core buttons else: sizer = wx.GridSizer(0, config.preferences.buttons_per_row) self.SetAutoLayout(True) # core components for b in core_btns: sizer.Add(b) for sb in sizer_btns: sizer.Add(sb) self.SetSizer(sizer) sizer.Fit(self) # Properties window frame_style = wx.DEFAULT_FRAME_STYLE frame_tool_win = config.preferences.frame_tool_win if frame_tool_win: frame_style |= wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT frame_style &= ~wx.MINIMIZE_BOX if wx.Platform != '__WXGTK__': frame_style |= wx.FRAME_TOOL_WINDOW self.frame2 = wx.Frame(self, -1, _('Properties - '), style=frame_style) self.frame2.SetBackgroundColour(wx.SystemSettings_GetColour( wx.SYS_COLOUR_BTNFACE)) self.frame2.SetIcon(icon) sizer_tmp = wx.BoxSizer(wx.VERTICAL) property_panel = wxGladePropertyPanel(self.frame2, -1) #---- 2003-06-22 Fix for what seems to be a GTK2 bug (notebooks) misc.hidden_property_panel = wx.Panel(self.frame2, -1) sz = wx.BoxSizer(wx.VERTICAL) sz.Add(property_panel, 1, wx.EXPAND) sz.Add(misc.hidden_property_panel, 1, wx.EXPAND) self.frame2.SetSizer(sz) sz.Show(misc.hidden_property_panel, False) self.property_frame = self.frame2 #-------------------------------------------------------- property_panel.SetAutoLayout(True) self.hidden_frame = wx.Frame(self, -1, "") self.hidden_frame.Hide() sizer_tmp.Add(property_panel, 1, wx.EXPAND) self.frame2.SetAutoLayout(True) self.frame2.SetSizer(sizer_tmp) sizer_tmp = wx.BoxSizer(wx.VERTICAL) def hide_frame2(event): #menu_bar.Check(PROPS_ID, False) self.frame2.Hide() wx.EVT_CLOSE(self.frame2, hide_frame2) wx.EVT_CLOSE(self, self.cleanup) common.property_panel = property_panel # Tree of widgets self.tree_frame = wx.Frame(self, -1, _('wxGlade: Tree'), style=frame_style) self.tree_frame.SetIcon(icon) import application app = application.Application(common.property_panel) common.app_tree = WidgetTree(self.tree_frame, app) self.tree_frame.SetSize((300, 300)) app.notebook.Show() sizer_tmp.Add(app.notebook, 1, wx.EXPAND) property_panel.SetSizer(sizer_tmp) sizer_tmp.Fit(property_panel) def on_tree_frame_close(event): #menu_bar.Check(TREE_ID, False) self.tree_frame.Hide() wx.EVT_CLOSE(self.tree_frame, on_tree_frame_close) # check to see if there are some remembered values prefs = config.preferences if prefs.remember_geometry: #print 'initializing geometry' try: x, y, w, h = prefs.get_geometry('main') misc.set_geometry(self, (x, y)) except Exception, e: pass misc.set_geometry(self.frame2, prefs.get_geometry('properties')) misc.set_geometry(self.tree_frame, prefs.get_geometry('tree')) else: if wx.Platform == '__WXMAC__': self.frame2.SetSize((345, 384)) # I've been told this is OK... self.SetPosition((0, 45)) # to avoid the OS X menubar else: self.frame2.SetSize((max(self.GetSize()[0], 250), 350)) self.SetPosition((0, 0)) x, y = self.GetPosition() h = self.GetSize()[1] w = self.frame2.GetSize()[0] if wx.Platform != '__WXMSW__': # under X, IceWM (and Sawfish, too), GetSize seems to ignore # window decorations h += 60 w += 10 self.frame2.SetPosition((x, y+h)) self.tree_frame.SetPosition((x+w, y)) self.Show() self.tree_frame.Show() self.frame2.Show() #self._skip_activate = False ## if frame_tool_win: ## def on_iconize(event): ## if event.Iconized(): ## self.hide_all() ## else: ## self.show_and_raise() ## event.Skip() ## wx.EVT_ICONIZE(self, on_iconize) if wx.Platform == '__WXMSW__': import about # I'll pay a beer to anyone who can explain to me why this prevents # a segfault on Win32 when you exit without doing anything!! self.about_box = about.wxGladeAboutBox(self.GetParent()) else: self.about_box = None # last visited directory, used on GTK for wxFileDialog self.cur_dir = config.preferences.open_save_path # set a drop target for us... self._droptarget = clipboard.FileDropTarget(self) self.SetDropTarget(self._droptarget) #self.tree_frame.SetDropTarget(self._droptarget) #self.frame2.SetDropTarget(self._droptarget) # ALB 2004-10-15, autosave support... self.autosave_timer = None if config.preferences.autosave: TIMER_ID = wx.NewId() self.autosave_timer = wx.Timer(self, TIMER_ID) wx.EVT_TIMER(self, TIMER_ID, self.on_autosave_timer) self.autosave_timer.Start( int(config.preferences.autosave_delay) * 1000) # ALB 2004-10-15 CLEAR_SB_TIMER_ID = wx.NewId() self.clear_sb_timer = wx.Timer(self, CLEAR_SB_TIMER_ID) wx.EVT_TIMER(self, CLEAR_SB_TIMER_ID, self.on_clear_sb_timer) self.frame2.SetAcceleratorTable(self.accel_table) self.tree_frame.SetAcceleratorTable(self.accel_table) self.Raise() # ALB 2004-10-16 if common.check_autosaved(None) and \ wx.MessageBox(_("There seems to be auto saved data " "from last wxGlade session: " "do you want to restore it?"), _("Auto save detected"), style=wx.ICON_QUESTION|wx.YES_NO) == wx.YES: if self._open_app(common.get_name_for_autosave(), add_to_history=False): common.app_tree.app.saved = False common.app_tree.app.filename = None self.user_message(_("Recovery from auto save complete")) common.remove_autosaved() else: common.remove_autosaved() def on_autosave_timer(self, event): if common.autosave_current(): self.user_message(_("Auto saving... done")) def edit_preferences(self, event): config.edit_preferences() def show_tree(self, event): self.tree_frame.Show() self.tree_frame.Raise() common.app_tree.SetFocus() def show_props_window(self, event): self.frame2.Show() self.frame2.Raise() try: c = self.frame2.GetSizer().GetChildren() if c: c[0].GetWindow().SetFocus() except (AttributeError, TypeError): self.frame2.SetFocus() def raise_all(self, event): children = self.GetChildren() for child in children: child = misc.get_toplevel_parent(child) if child.IsShown() and child.GetTitle(): child.Raise() self.Raise() def user_message(self, msg): sb = self.GetStatusBar() if sb: sb.SetStatusText(msg) self.clear_sb_timer.Start(5000, True) def on_clear_sb_timer(self, event): sb = self.GetStatusBar() if sb: sb.SetStatusText("") def ask_save(self): """\ checks whether the current app has changed and needs to be saved: if so, prompts the user; returns False if the operation has been cancelled """ if not common.app_tree.app.saved: ok = wx.MessageBox(_("Save changes to the current app?"), _("Confirm"), wx.YES_NO|wx.CANCEL|wx.CENTRE|wx.ICON_QUESTION) if ok == wx.YES: self.save_app(None) return ok != wx.CANCEL return True def new_app(self, event): """\ creates a new wxGlade project """ if self.ask_save(): common.app_tree.clear() common.app_tree.app.filename = None common.app_tree.app.saved = True self.user_message("") # ALB 2004-10-15 common.remove_autosaved() if config.preferences.autosave and self.autosave_timer is not None: self.autosave_timer.Start() def new_app_from_template(self, event): """\ creates a new wxGlade project from an existing template file """ if not self.ask_save(): return infile = template.select_template() if infile: self._open_app(infile, add_to_history=False) common.app_tree.app.template_data = None def reload_app(self, event): self.ask_save() if not common.app_tree.app.filename: wx.MessageBox(_("Impossible to reload an unsaved application"), _("Alert"), style=wx.OK|wx.ICON_INFORMATION) return path = common.app_tree.get_selected_path() #print 'path:', path self._open_app(common.app_tree.app.filename, add_to_history=False) common.app_tree.select_path(path) def open_app(self, event_unused): """\ loads a wxGlade project from an xml file NOTE: this is very slow and needs optimisation efforts NOTE2: the note above should not be True anymore :) """ if not self.ask_save(): return from xml_parse import XmlWidgetBuilder, ProgressXmlWidgetBuilder infile = misc.FileSelector(_("Open file"), wildcard="wxGlade files (*.wxg)|*.wxg|" "wxGlade Template files (*.wgt)|*.wgt|" "XML files (*.xml)|*.xml|All files|*", flags=wx.OPEN|wx.FILE_MUST_EXIST, default_path=self.cur_dir) if infile: # ALB 2004-10-15 try to restore possible autosave content... if common.check_autosaved(infile) and \ wx.MessageBox(_("There seems to be auto saved data for " "this file: do you want to restore it?"), _("Auto save detected"), style=wx.ICON_QUESTION|wx.YES_NO) == wx.YES: common.restore_from_autosaved(infile) else: common.remove_autosaved(infile) self._open_app(infile) self.cur_dir = os.path.dirname(infile) def _open_app(self, infilename, use_progress_dialog=True, is_filelike=False, add_to_history=True): import time from xml_parse import XmlWidgetBuilder, ProgressXmlWidgetBuilder, \ XmlParsingError from xml.sax import SAXParseException start = time.clock() common.app_tree.clear() if not is_filelike: common.app_tree.app.filename = infilename else: common.app_tree.filename = getattr(infilename, 'name', None) common.property_panel.Reparent(self.hidden_frame) # prevent the auto-expansion of nodes common.app_tree.auto_expand = False old_dir = os.getcwd() try: if not is_filelike: os.chdir(os.path.dirname(infilename)) infile = open(infilename) else: infile = infilename infilename = getattr(infile, 'name', None) if use_progress_dialog and config.preferences.show_progress: p = ProgressXmlWidgetBuilder(input_file=infile) else: p = XmlWidgetBuilder() p.parse(infile) except (IOError, OSError, SAXParseException, XmlParsingError), msg: if locals().has_key('infile') and not is_filelike: infile.close() common.app_tree.clear() common.property_panel.Reparent(self.frame2) common.app_tree.app.saved = True wx.MessageBox(_("Error loading file %s: %s") % \ (misc.wxstr(infilename), misc.wxstr(msg)), _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) # reset the auto-expansion of nodes common.app_tree.auto_expand = True os.chdir(old_dir) return False except Exception, msg: import traceback; traceback.print_exc() if locals().has_key('infile') and not is_filelike: infile.close() common.app_tree.clear() common.property_panel.Reparent(self.frame2) common.app_tree.app.saved = True wx.MessageBox(_("An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback " "on the console.\n" "If you think this is a wxGlade bug," " please report it.") % \ (misc.wxstr(infilename), misc.wxstr(msg)), _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) # reset the auto-expansion of nodes common.app_tree.auto_expand = True os.chdir(old_dir) return False if not is_filelike: infile.close() common.app_tree.select_item(common.app_tree.root) common.app_tree.root.widget.show_properties() common.property_panel.Reparent(self.frame2) # reset the auto-expansion of nodes common.app_tree.auto_expand = True common.app_tree.expand() if common.app_tree.app.is_template: print _("Loaded template") common.app_tree.app.template_data = template.Template(infilename) common.app_tree.app.filename = None end = time.clock() print _('Loading time: %.5f') % (end-start) common.app_tree.app.saved = True if hasattr(self, 'file_history') and infilename is not None and \ add_to_history and (not common.app_tree.app.is_template): self.file_history.AddFileToHistory(misc.wxstr(infilename)) # ALB 2004-10-15 if config.preferences.autosave and self.autosave_timer is not None: self.autosave_timer.Start() self.user_message(_("Loaded %s (%.2f seconds)") % \ (misc.wxstr(common.app_tree.app.filename), end-start)) return True def save_app(self, event): """\ saves a wxGlade project onto an xml file """ if not common.app_tree.app.filename or common.app_tree.app.is_template: self.save_app_as(event) else: # check whether we are saving a template if os.path.splitext(common.app_tree.app.filename)[1] == ".wgt": common.app_tree.app.is_template = True self._save_app(common.app_tree.app.filename) def _save_app(self, filename): try: from cStringIO import StringIO buffer = StringIO() common.app_tree.write(buffer) common.save_file(filename, buffer.getvalue(), 'wxg') except (IOError, OSError), msg: common.app_tree.app.saved = False fn = filename wx.MessageBox(_("Error saving app:\n%s") % msg, _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) except Exception, msg: import traceback; traceback.print_exc() common.app_tree.app.saved = False fn = filename wx.MessageBox(_("An exception occurred while saving file " "\"%s\".\n" "This is the error message associated with it:" "\n %s\n" "For more details, look at the full traceback " "on the console.\nIf you think this is a " "wxGlade bug," " please report it.") % (fn, msg), _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) else: common.app_tree.app.saved = True common.remove_autosaved() # ALB 2004-10-15 # ALB 2004-10-15 if config.preferences.autosave and \ self.autosave_timer is not None: self.autosave_timer.Start() self.user_message(_("Saved %s") % filename) def save_app_as(self, event): """\ saves a wxGlade project onto an xml file chosen by the user """ fn = misc.FileSelector(_("Save project as..."), wildcard="wxGlade files (*.wxg)|*.wxg|" "wxGlade Template files (*.wgt) |*.wgt|" "XML files (*.xml)|*.xml|All files|*", flags=wx.SAVE|wx.OVERWRITE_PROMPT, default_path=self.cur_dir) if fn: common.app_tree.app.filename = fn #remove the template flag so we can save the file. common.app_tree.app.is_template = False self.save_app(event) self.cur_dir = os.path.dirname(fn) if misc.check_wx_version(2, 3, 3): self.file_history.AddFileToHistory(fn) def save_app_as_template(self, event): data = getattr(common.app_tree.app, 'template_data', None) outfile, data = template.save_template(data) if outfile: common.app_tree.app.is_template = True common.app_tree.app.template_data = data self._save_app(outfile) def cleanup(self, event): if self.ask_save(): # first, let's see if we have to save the geometry... prefs = config.preferences if prefs.remember_geometry: prefs.set_geometry('main', misc.get_geometry(self)) prefs.set_geometry('tree', misc.get_geometry(self.tree_frame)) prefs.set_geometry('properties', misc.get_geometry(self.frame2)) prefs.changed = True common.app_tree.clear() if self.about_box: self.about_box.Destroy() try: config.save_preferences() except Exception, e: wx.MessageBox(_('Error saving preferences:\n%s') % e, _('Error'), wx.OK|wx.CENTRE|wx.ICON_ERROR) #self._skip_activate = True self.frame2.Destroy() self.tree_frame.Destroy() self.Destroy() common.remove_autosaved() # ALB 2004-10-15 misc.wxCallAfter(wx.GetApp().ExitMainLoop) def show_about_box(self, event): if self.about_box is None: import about self.about_box = about.wxGladeAboutBox(None) self.about_box.ShowModal() def show_tutorial(self, event): docs_path = os.path.join(common.wxglade_path, 'docs', 'index.html') if wx.Platform == "__WXMAC__": os.system('open -a Help\ Viewer.app %s' % docs_path) else: import webbrowser, threading # ALB 2004-08-15: why did this block the program????? # (at least on linux - GTK) def go(): webbrowser.open_new(docs_path) t = threading.Thread(target=go) t.setDaemon(True) t.start() def show_and_raise(self): self.frame2.Show()#self.GetMenuBar().IsChecked(self.PROPS_ID)) self.tree_frame.Show()#self.GetMenuBar().IsChecked(self.TREE_ID)) self.frame2.Raise() self.tree_frame.Raise() self.Raise() def hide_all(self): self.tree_frame.Hide() self.frame2.Hide() def import_xrc(self, event): import xrc2wxg, cStringIO if not self.ask_save(): return infile = misc.FileSelector(_("Import file"), wildcard="XRC files (*.xrc)" "|*.xrc|All files|*", flags=wx.OPEN|wx.FILE_MUST_EXIST, default_path=self.cur_dir) if infile: buf = cStringIO.StringIO() try: xrc2wxg.convert(infile, buf) buf.seek(0) self._open_app(buf, is_filelike=True) common.app_tree.app.saved = False except Exception, msg: import traceback; traceback.print_exc() wx.MessageBox(_("An exception occurred while importing file " "\"%s\".\nThis is the error message associated " "with it:\n %s\n" "For more details, look at the full traceback " "on the console.\nIf you think this is a " "wxGlade bug, please report it.") % \ (infile, msg), _("Error"), wx.OK|wx.CENTRE|wx.ICON_ERROR) def manage_templates(self, event): to_edit = template.manage_templates() if to_edit is not None and self.ask_save(): # edit the template # TODO, you still need to save it manually... self._open_app(to_edit, add_to_history=False) wx.MessageBox(_("To save the changes to the template, edit the " "GUI as usual,\nand then click " "File->Save as Template..."), _("Information"), style=wx.OK|wx.ICON_INFORMATION) # end of class wxGladeFrame class wxGlade(wx.App): def OnInit(self): import sys sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ # needed for wx >= 2.3.4 to disable wxPyAssertionError exceptions if misc.check_wx_version(2, 3, 4): self.SetAssertMode(0) wx.InitAllImageHandlers() config.init_preferences() # ALB 2004-10-27 if wx.Platform == '__WXGTK__' and config.preferences.use_kde_dialogs: import kdefiledialog if kdefiledialog.test_kde(): misc.FileSelector = kdefiledialog.kde_file_selector misc.DirSelector = kdefiledialog.kde_dir_selector wx.ArtProvider.PushProvider(wxGladeArtProvider()) frame = wxGladeFrame() ## if wx.Platform == '__WXMSW__': ## def on_activate(event): ## if event.GetActive() and not frame.IsIconized(): ## frame.show_and_raise() ## event.Skip() ## wx.EVT_ACTIVATE_APP(self, on_activate) self.SetTopWindow(frame) self.SetExitOnFrameDelete(True) wx.EVT_IDLE(self, self.on_idle) return True def on_idle(self, event): common.message.flush() event.Skip() # end of class wxGlade def main(filename=None): """\ if filename is not None, loads it """ # first thing to do, patch wxSizerPtr's Insert if needed... ## from wxPython import wx ## if wx.__version__ == '2.4.0.2': ## wxSizerPtr.Insert = misc.sizer_fixed_Insert # now, silence a deprecation warining for py2.3 import warnings warnings.filterwarnings("ignore", "integer", DeprecationWarning, "wxPython.gdi") app = wxGlade() if filename is not None: app.GetTopWindow()._open_app(filename, False) app.MainLoop() spe-0.8.4.h/_spe/plugins/wxGlade/about.py0000644000175000017500000001164410743421035017251 0ustar stanistani# about.py: about box with general info # $Id: about.py,v 1.24 2007/03/27 07:02:07 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY #from wxPython.wx import * import wx #from wxPython.html import * import wx.html #import wxPython.lib.wxpTag import wx.lib.wxpTag import common, misc, os.path, sys,gettext class wxGladeAboutBox(wx.Dialog): text = '''
Version %s on Python %s and wxPython %s

License: MIT (see license.txt)

Home page: http://wxglade.sourceforge.net

For credits, see credits.txt.

''' def __init__(self, parent=None): wx.Dialog.__init__(self, parent, -1, _('About wxGlade')) class HtmlWin(wx.html.HtmlWindow): def OnLinkClicked(self, linkinfo): href = linkinfo.GetHref() if href == 'show_license': from wx.lib.dialogs import ScrolledMessageDialog try: license = open(os.path.join(common.wxglade_path, 'license.txt')) dlg = ScrolledMessageDialog(self, license.read(), _("wxGlade - License")) license.close() dlg.ShowModal() dlg.Destroy() except IOError: wx.MessageBox(_("Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/" "mit-license.php"), _("Error"), wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION) elif href == 'show_credits': from wx.lib.dialogs import ScrolledMessageDialog try: credits = open(os.path.join(common.wxglade_path, 'credits.txt')) dlg = ScrolledMessageDialog(self, credits.read(), _("wxGlade - Credits")) credits.close() dlg.ShowModal() dlg.Destroy() except IOError: wx.MessageBox(_("Can't find the credits file!\n"), _("Oops!"), wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION) else: import webbrowser webbrowser.open(linkinfo.GetHref(), new=True) html = HtmlWin(self, -1, size=(400, -1)) if misc.check_wx_version(2, 5, 3): try: html.SetStandardFonts() except AttributeError: pass py_version = sys.version.split()[0] bgcolor = misc.color_to_string(self.GetBackgroundColour()) icon_path = os.path.join(common.wxglade_path, 'icons/wxglade_small.png') html.SetPage(self.text % (bgcolor, icon_path, common.version, py_version, wx.__version__)) ir = html.GetInternalRepresentation() ir.SetIndent(0, wx.html.HTML_INDENT_ALL) html.SetSize((ir.GetWidth(), ir.GetHeight())) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(html, 0, wx.TOP|wx.ALIGN_CENTER, 10) szr.Add(wx.StaticLine(self, -1), 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 20) szr2 = wx.BoxSizer(wx.HORIZONTAL) btn = wx.Button(self, wx.ID_OK, _("OK")) btn.SetDefault() szr2.Add(btn) if wx.Platform == '__WXGTK__': extra_border = 5 # border around a default button else: extra_border = 0 szr.Add(szr2, 0, wx.ALL|wx.ALIGN_RIGHT, 20 + extra_border) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.Layout() if parent: self.CenterOnParent() else: self.CenterOnScreen() # end of class wxGladeAboutBox if __name__ == '__main__': wx.InitAllImageHandlers() app = wx.PySimpleApp() d = wxGladeAboutBox() app.SetTopWindow(d) d.ShowModal() spe-0.8.4.h/_spe/plugins/wxGlade/credits.txt0000644000175000017500000000361010743421035017755 0ustar stanistani Main Developer: --------------------------------------------------------------------------- - Alberto Griggio Other Developers: --------------------------------------------------------------------------- - Marcello Semboli - Guy Rutenberg - D.H. (Perl code generation) - Georges Khaznadar (debian package maintainer) Former Developers: --------------------------------------------------------------------------- - Marco Barisione - Kevin Walzer (OSX app bundle maintainer) Contributors: --------------------------------------------------------------------------- - Johan Vromans - Richard Lawson - Alex Thuering : general virtual sizers support and porting of the SplitterWindow to this new model - Brendan Oakley : editor of the new user's manual - Jack Thomasson : assist with port to wx namespace Many thanks to: --------------------------------------------------------------------------- - Guido van Rossum and all the people at PSF for the excellent language - Robin Dunn, Julian Smart, Vadim Zeitlin, Robert Roebling and the wxWidgets team for their great libary - Glade developers for the inspiration they gave me and for the icons - Boa-constructor developers for some of the icons - Vaclav Slavik for the suggestions about XRC - Michael Gilfix for his wxPyColorChooser, used in the color dialog - ... and, of course, all the people who provided feedback, comments, critics and support (John Dubery in particular for his huge amount of bug reports). (We apologize with all the people that should be mentioned here but in fact aren't: if you think you are one of them, tell us and your name will be added ASAP) spe-0.8.4.h/_spe/plugins/wxGlade/template.py0000644000175000017500000001716710743421035017760 0ustar stanistani# template.py: handles the template tags and description # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # # Author: Guy Rutenberg, Alberto Griggio from xml.dom import minidom from xml.sax import saxutils import config import templates_ui import common, misc import os, glob import wx class Template: """ \ A class that handles the specific aspects of template files. """ def __init__(self, filename=None): self.author = '' self.description = '' self.instructions = '' self.filename = filename if filename is not None: filexml = minidom.parse(filename) # we have no use for all the xml data in the file. We only care # about what is between the "description" tags templatedata = filexml.getElementsByTagName('templatedata') if len(templatedata): desc_xml = templatedata[0] try: self.author = saxutils.unescape( desc_xml.getElementsByTagName( 'author')[0].firstChild.data) except (IndexError, AttributeError): self.author = '' try: self.description = saxutils.unescape( desc_xml.getElementsByTagName( 'description')[0].firstChild.data) except (IndexError, AttributeError): self.description = '' try: self.instructions = saxutils.unescape( desc_xml.getElementsByTagName( 'instructions')[0].firstChild.data) except (IndexError, AttributeError): self.instructions = '' else: self.author = '' self.description='' self.instructions='' def write(self, outfile, tabs): fwrite = outfile.write t1 = ' ' * tabs t2 = ' ' * (tabs+1) fwrite(t1 + '\n') fwrite(t2 + '%s\n' % \ saxutils.escape(common._encode_to_xml(self.author))) fwrite(t2 + '%s\n' % \ saxutils.escape(common._encode_to_xml(self.description))) fwrite(t2 + '%s\n' % \ saxutils.escape(common._encode_to_xml(self.instructions))) fwrite(t1 + '\n') # end of class Template class TemplateListDialog(templates_ui.TemplateListDialog): def __init__(self): templates_ui.TemplateListDialog.__init__(self, None, -1, "") self.templates = [] self.fill_template_list() self.selected_template = None def get_selected(self): index = self.template_names.GetSelection() if index >= 0: return self.templates[index] else: return None def on_open(self, event): self.selected_template = self.get_selected() self.EndModal(wx.ID_OPEN) def on_select_template(self, event): self.selected_template = self.get_selected() if self.selected_template is not None: t = Template(self.selected_template) self.set_template_name(self.template_names.GetStringSelection()) self.author.SetValue(misc.wxstr(t.author)) self.description.SetValue(misc.wxstr(t.description)) self.instructions.SetValue(misc.wxstr(t.instructions)) wxglade_templates = os.path.join(common.wxglade_path, 'templates') if os.path.dirname(self.selected_template) == wxglade_templates: self.btn_delete.Disable() self.btn_edit.Disable() else: self.btn_delete.Enable() self.btn_edit.Enable() else: self.set_template_name("") self.author.SetValue("") self.description.SetValue("") self.instructions.SetValue("") event.Skip() def set_template_name(self, name): self.template_name.SetLabel(_("wxGlade template:\n") + misc.wxstr(name)) def on_edit(self, event): self.selected_template = self.get_selected() self.EndModal(wx.ID_EDIT) def on_delete(self, event): self.selected_template = self.get_selected() if self.selected_template is not None: name = self.template_names.GetStringSelection() if wx.MessageBox(_("Delete template '%s'?") % misc.wxstr(name), _("Are you sure?"), style=wx.YES|wx.NO|wx.CENTRE) == wx.YES: try: os.unlink(self.selected_template) except Exception, e: print e self.fill_template_list() self.selected_template = None def fill_template_list(self): self.templates = load_templates() self.template_names.Clear() for n in self.templates: self.template_names.Append(os.path.splitext(os.path.basename(n))[0]) # end of class TemplateListDialog def load_templates(): """\ Finds all the available templates. """ d = os.path.join(config._get_appdatapath(), '.wxglade') if d != common.wxglade_path: extra = glob.glob(os.path.join(d, "templates", "*.wgt")) else: extra = [] return sorted(glob.glob(os.path.join( common.wxglade_path, "templates", "*.wgt"))) + sorted(extra) def select_template(): """\ Returns the filename of a template to load """ dlg = TemplateListDialog() dlg.btn_delete.Hide() dlg.btn_edit.Hide() if dlg.ShowModal() == wx.ID_OPEN: ret = dlg.selected_template else: ret = None dlg.Destroy() return ret def save_template(data=None): """\ Returns an out file name and template description for saving a template """ dlg = templates_ui.TemplateInfoDialog(None, -1, "") if data is not None: dlg.template_name.SetValue( misc.wxstr(os.path.basename(os.path.splitext(data.filename)[0]))) dlg.author.SetValue(misc.wxstr(data.author)) dlg.description.SetValue(misc.wxstr(data.description)) dlg.instructions.SetValue(misc.wxstr(data.instructions)) ret = None retdata = Template() if dlg.ShowModal() == wx.ID_OK: ret = dlg.template_name.GetValue().strip() retdata.author = dlg.author.GetValue() retdata.description = dlg.description.GetValue() retdata.instructions = dlg.instructions.GetValue() if not ret: wx.MessageBox(_("Can't save a template with an empty name"), _("Error"), wx.OK|wx.ICON_ERROR) dlg.Destroy() name = ret if ret: d = os.path.join(config._get_appdatapath(), '.wxglade', 'templates') if not os.path.exists(d): try: os.mkdir(d) except (OSError, IOError), e: print _("ERROR creating %s: %s") % (d, e) return None, retdata ret = os.path.join(d, ret + '.wgt') if ret and os.path.exists(ret) and \ wx.MessageBox(_("A template called '%s' already exists:\ndo you want to" " overwrite it?") % name, _("Question"), wx.YES|wx.NO|wx.ICON_QUESTION) != wx.YES: ret = None return ret, retdata def manage_templates(): dlg = TemplateListDialog() dlg.btn_open.Hide() #dlg.btn_edit.Hide() ret = None if dlg.ShowModal() == templates_ui.ID_EDIT: ret = dlg.selected_template dlg.Destroy() return ret spe-0.8.4.h/_spe/plugins/wxGlade/kdefiledialog.py0000644000175000017500000001462510743421035020724 0ustar stanistani# kdefiledialog.py: support for native KDE file and dir dialog (using kdialog) # $Id: kdefiledialog.py,v 1.5 2007/03/27 07:02:07 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import signal, os, sys import misc __all__ = ['test_kde', 'kde_file_selector', 'kde_dir_selector'] def _check_for_kdialog(): pth = os.environ.get('PATH', os.defpath).split(os.pathsep) for p in pth: name = os.path.join(p, 'kdialog') if os.access(name, os.X_OK): return True return False _kdialog_ok = _check_for_kdialog() def kde_file_selector(message, default_path="", default_filename="", default_extension="", wildcard="*.*", flags=0, *args, **kwds): """\ Pops up the standard KDE file selector box, calling kdialog. The API is identical to that of wx.FileSelector. If kdialog can't be invoked, reverts to the standard wx.FileSelector. Note that at the moment not all the arguments are meaningful (for example, parent and initial position are ignored), and multiple selections are not supported. """ if not _kdialog_ok: return wx.FileSelector(message, default_path, default_filename, default_extension, wildcard, flags, *args, **kwds) r, w = os.pipe() handler = _SigChldHandler() oldhandler = signal.signal(signal.SIGCHLD, handler) pid = os.fork() if pid == 0: os.close(r) os.dup2(w, sys.stdout.fileno()) os.close(w) startdir = default_path if default_filename: if not os.path.isdir(startdir): startdir = os.path.dirname(startdir) startdir = os.path.join(startdir, default_filename) if flags & wx.SAVE: kind = '--getsavefilename' else: kind = '--getopenfilename' os.execlp('kdialog', 'kdialog', kind, startdir, _wx_to_kde_wildcard(wildcard), '--title', message) elif pid > 0: disabler = wx.WindowDisabler() app = wx.GetApp() os.close(w) while not handler.done: app.Dispatch() if handler.status != 0: os.close(r) return "" filename = os.fdopen(r).readline().strip() signal.signal(signal.SIGCHLD, oldhandler or signal.SIG_DFL) if (flags & wx.SAVE) and (flags & wx.OVERWRITE_PROMPT) and \ os.path.exists(filename): if wx.MessageBox(_("File '%s' already exists: do you really want " "to overwrite it?") % misc.wxstr(filename), _("Confirm"), style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: return kde_file_selector(message, default_path, default_filename, default_extension, wildcard, flags) return filename else: raise OSError, _("Fork Error") def kde_dir_selector(message="", default_path="", *args, **kwds): """\ Pops up the standard KDE directory selector box, calling kdialog. The API is identical to that of wx.DirSelector. If kdialog can't be invoked, reverts to the standard wx.DirSelector. Note that at the moment not all the arguments are meaningful (for example, parent and initial position are ignored). """ if not _kdialog_ok: return wx.DirSelector(message, default_path, *args, **kwds) r, w = os.pipe() handler = _SigChldHandler() oldhandler = signal.signal(signal.SIGCHLD, handler) pid = os.fork() if pid == 0: os.close(r) os.dup2(w, sys.stdout.fileno()) os.close(w) if not default_path: default_path = os.getcwd() os.execlp('kdialog', 'kdialog', '--getexistingdirectory', default_path, '--title', message) elif pid > 0: disabler = wx.WindowDisabler() app = wx.GetApp() os.close(w) while not handler.done: app.Dispatch() if handler.status != 0: os.close(r) return "" dirname = os.fdopen(r).readline().strip() signal.signal(signal.SIGCHLD, oldhandler or signal.SIG_DFL) return dirname else: raise OSError, _("Fork Error") def test_kde(): """\ Checks whether KDE (actually, kdesktop) is running. """ return os.system('dcop kdesktop > /dev/null 2>&1') == 0 class _SigChldHandler: def __init__(self): self.done = False self.status = 0 def __call__(self, signo, stackframe): pid, self.status = os.wait() self.done = True # end of class _SigChldHandler def _wx_to_kde_wildcard(wildcard): bits = wildcard.split('|') l = len(bits) ret = [] for i in range(0, l, 2): if i+1 < l: ret.append(bits[i+1].replace(';', ' ') + '|' + bits[i]) else: ret.append(bits[i].replace(';', ' ')) return '\n'.join(ret) if __name__ == '__main__': app = wx.PySimpleApp() frame = wx.Frame(None, -1, "Prova") b = wx.Button(frame, -1, "KDE File selector", pos=(0, 0)) b2 = wx.Button(frame, -1, "wx File selector", pos=(0, 70)) def on_click(event): filename = kde_file_selector( 'Select file to save', '', 'prova.py', wildcard="Python files|*.py;*.pyc|All files|*", flags=wx.SAVE|wx.OVERWRITE_PROMPT) if filename: wx.MessageBox('You selected file: %s' % filename, style=wx.OK|wx.ICON_INFORMATION) else: wx.MessageBox('No files selected!', style=wx.OK|wx.ICON_EXCLAMATION) def on_click2(event): filename = wx.FileSelector( 'Select file to save', '', 'prova.py', wildcard=_("Python files|*.py;*.pyc|All files|*"), flags=wx.SAVE|wx.OVERWRITE_PROMPT) if filename: wx.MessageBox(_('You selected file: %s') % filename, style=wx.OK|wx.ICON_INFORMATION) else: wx.MessageBox(_('No files selected!'), style=wx.OK|wx.ICON_EXCLAMATION) wx.EVT_BUTTON(b, -1, on_click) wx.EVT_BUTTON(b2, -1, on_click2) app.SetTopWindow(frame) frame.Show() app.MainLoop() spe-0.8.4.h/_spe/plugins/wxGlade/wxglade0000755000175000017500000000021510743421035017136 0ustar stanistani#!/bin/sh #pv=`python -c 'import sys; print sys.version[:3]'` pv="2.3" exec python /usr/lib/python$pv/site-packages/wxglade/wxglade.py "$@" spe-0.8.4.h/_spe/plugins/wxGlade/po/0000755000175000017500000000000011004131465016171 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/templates/0000755000175000017500000000000011004131465017551 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/0000755000175000017500000000000011004131465017012 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/0000755000175000017500000000000011004131465017221 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/0000755000175000017500000000000011004131465020077 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/res/0000755000175000017500000000000011004131465016344 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/icons/0000755000175000017500000000000011004131466016667 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/codegen/0000755000175000017500000000000011004131465017157 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/po/it.po0000644000175000017500000001516610743421035017162 0ustar stanistani# translation of PACKAGE. # Copyright (C) 2007 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # <>, 2007. # , fuzzy # # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-01-27 15:22+0100\n" "PO-Revision-Date: 2007-01-27 20:56+0100\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit" #: clipboard.py:40 msgid "Invalid data in the clipboard" msgstr "Dati negli appunti non validi" #: clipboard.py:65 msgid "Data can't be copied to clipboard." msgstr "I dati non possono essere copiati negli appunti." #: clipboard.py:71 clipboard.py:105 msgid "Clipboard can't be opened." msgstr "Impossibile aprire gli appunti." #: clipboard.py:98 msgid "Data can't be copied from clipboard." msgstr "Impossibile copiare i dati dagli appunti." #: clipboard.py:129 msgid "Please only drop one file at a time" msgstr "Trascinare solo un file alla volta" #: color_dialog.py:20 color_dialog.py:18 msgid "System colour" msgstr "Colori di sistema" #: color_dialog.py:24 color_dialog.py:22 msgid "Custom colour" msgstr "Colori personalizzati" #: color_dialog.py:27 configUI.py:40 color_dialog.py:25 configUI.py:38 msgid "OK" msgstr "" #: color_dialog.py:28 configUI.py:41 color_dialog.py:26 configUI.py:39 msgid "Cancel" msgstr "Annulla" #: color_dialog.py:72 color_dialog.py:70 msgid "Select widget colour" msgstr "Selezionare il colore dello widget" #: common.py:94 common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "\"%s\" non è un modulo di generazione codice valido" #: common.py:98 common.py:96 #, python-format msgid "loaded code generator for %s" msgstr "caricato generatore di codice per %s" #: common.py:129 common.py:127 #, python-format msgid "Found widgets listing -> %s" msgstr "Trovata lista di widget -> %s" #: common.py:130 common.py:128 msgid "loading widget modules:" msgstr "caricamento moduli per gli widget:" #: common.py:139 common.py:137 #, python-format msgid "ERROR loading \"%s\"" msgstr "ERRORE durante il caricamento di \"%s\"" #: common.py:205 common.py:203 #, python-format msgid "Add a %s" msgstr "Aggiungi un %s" #: config.py:62 config.py:60 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" "Impossibile leggere il file di configurazione:\n" "%s" #: config.py:105 config.py:103 msgid "Choose a directory:" msgstr "Scegli una directory:" #: config.py:248 config.py:246 msgid "Changes will take effect after wxGlade is restarted" msgstr "I cambiamenti saranno effettivi dopo il riavvio di wxGlade" #: config.py:249 config.py:247 msgid "Preferences saved" msgstr "Preferenze salvate" #: configUI.py:17 configUI.py:15 msgid "Local widget path" msgstr "Percorso dei widget locali" #: configUI.py:19 configUI.py:17 msgid "Use icons in menu items" msgstr "Usare le icone nel menu" #: configUI.py:20 configUI.py:18 msgid "Show properties and tree windows as small frames (Win32 only)" msgstr "Mostra le finestre delle proprietà e albero con piccole cornici (solo Win32)" #: configUI.py:21 configUI.py:19 msgid "Show progress dialog when loading wxg files" msgstr "Mostra barra di avanzamento durante il caricamento dei file wxg" #: configUI.py:22 configUI.py:20 msgid "Remember position and size of wxGlade windows" msgstr "Ricorda la posizione e la dimenzione delle finestre di wxGlade" #: configUI.py:23 configUI.py:21 msgid "Show \"handles\" of sizers" msgstr "Mostra \"maniglie\" dei sizer" #: configUI.py:24 configUI.py:22 msgid "Use native file dialogs on KDE" msgstr "In KDE usa il dialogo file nativo" #: configUI.py:29 configUI.py:27 msgid "Use dialog units by default for size properties" msgstr "Usare unità di dialogo per la proprietà dimenzionali" #: configUI.py:30 configUI.py:28 msgid "Create backup wxg files" msgstr "Creare una copia di sicurezza dei file wxg" #: configUI.py:31 configUI.py:29 msgid "Create backup files for generated source" msgstr "Creare una copia di sicurezza per i sorgenti generati" #: configUI.py:32 configUI.py:30 msgid "Allow duplicate widget names" msgstr "Nomi di widget duplicati permessi" #: configUI.py:33 configUI.py:31 msgid "Default border width for widgets" msgstr "Dimenzione bordo widget" #: configUI.py:35 configUI.py:33 msgid "Auto save wxg files every " msgstr "Salvataggio automatico dei file wxg ogni " #: configUI.py:37 configUI.py:35 msgid "Backup options" msgstr "Opzioni copia di sicurezza" #: configUI.py:37 configUI.py:35 msgid "append .bak to filename" msgstr "aggiungi .bak al nome del file" #: configUI.py:37 configUI.py:35 msgid "append ~ to filename" msgstr "aggiungi ~ al nome del file" #: configUI.py:49 configUI.py:47 msgid "wxGlade: preferences" msgstr "wxGlade: preferenze" #: configUI.py:85 configUI.py:83 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "Percorso iniziale per \n" "dialogo apri file:" #: configUI.py:88 configUI.py:86 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "Percorso iniziale per \n" "dialogo file generazione codice" #: configUI.py:92 configUI.py:90 msgid "Number of items in file history" msgstr "Numero di righe nella storia file" #: configUI.py:95 configUI.py:93 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "Numero di bottoni per riga\n" "nella pulsantiera principale" #: configUI.py:124 configUI.py:122 msgid "Interface" msgstr "Interfaccia" #: configUI.py:125 configUI.py:123 msgid "Other" msgstr "Altro" #: wxglade.py:74 wxglade.py:76 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "" #: wxglade.py:78 wxglade.py:80 #, python-format msgid "Error: %s" msgstr "" #: wxglade.py:88 wxglade.py:90 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" #: wxglade.py:99 wxglade.py:101 msgid "Valid LANGUAGE values:" msgstr "" #: about.py:49 msgid "About wxGlade" msgstr "" #: about.py:59 msgid "wxGlade - License" msgstr "" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" #: about.py:67 msgid "Error" msgstr "" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "" #: about.py:80 msgid "Oops!" msgstr "" spe-0.8.4.h/_spe/plugins/wxGlade/po/fr.po0000644000175000017500000005473010743421035017155 0ustar stanistani# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-02-09 23:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: about.py:49 msgid "About wxGlade" msgstr "" #: about.py:59 msgid "wxGlade - License" msgstr "" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" #: about.py:67 edit_windows.py:149 main.py:620 main.py:637 main.py:692 #: main.py:705 main.py:753 main.py:815 zmain.py:482 zmain.py:499 zmain.py:538 #: zmain.py:551 zmain.py:587 edit_sizers/edit_sizers.py:651 msgid "Error" msgstr "" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "" #: about.py:80 msgid "Oops!" msgstr "" #: clipboard.py:40 clipboard.py:38 msgid "Invalid data in the clipboard" msgstr "" #: clipboard.py:65 clipboard.py:63 msgid "Data can't be copied to clipboard." msgstr "" #: clipboard.py:71 clipboard.py:105 clipboard.py:69 clipboard.py:103 msgid "Clipboard can't be opened." msgstr "" #: clipboard.py:98 clipboard.py:96 msgid "Data can't be copied from clipboard." msgstr "" #: clipboard.py:129 clipboard.py:127 msgid "Please only drop one file at a time" msgstr "" #: color_dialog.py:18 color_dialog.py:19 msgid "System colour" msgstr "" #: color_dialog.py:22 color_dialog.py:23 msgid "Custom colour" msgstr "" #: color_dialog.py:25 configUI.py:38 color_dialog.py:26 #: edit_sizers/edit_sizers.py:395 edit_sizers/edit_sizers.py:1808 #: edit_sizers/edit_sizers.py:2026 edit_sizers/edit_sizers.py:2122 #: widgets/gauge/gauge.py:104 widgets/menubar/menubar.py:71 #: widgets/menubar/menubar.py:777 widgets/notebook/notebook.py:339 msgid "OK" msgstr "" #: color_dialog.py:26 configUI.py:39 color_dialog.py:27 #: edit_sizers/edit_sizers.py:396 edit_sizers/edit_sizers.py:1809 #: widgets/menubar/menubar.py:73 widgets/menubar/menubar.py:778 msgid "Cancel" msgstr "" #: color_dialog.py:70 color_dialog.py:71 msgid "Select widget colour" msgstr "" #: common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "" #: common.py:96 #, python-format msgid "loaded code generator for %s" msgstr "" #: common.py:127 #, python-format msgid "Found widgets listing -> %s" msgstr "" #: common.py:128 msgid "loading widget modules:" msgstr "" #: common.py:137 #, python-format msgid "ERROR loading \"%s\"" msgstr "" #: common.py:203 #, python-format msgid "Add a %s" msgstr "" #: config.py:60 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" #: config.py:103 msgid "Choose a directory:" msgstr "" #: config.py:246 msgid "Changes will take effect after wxGlade is restarted" msgstr "" #: config.py:247 msgid "Preferences saved" msgstr "" #: configUI.py:15 msgid "Local widget path" msgstr "" #: configUI.py:17 msgid "Use icons in menu items" msgstr "" #: configUI.py:18 msgid "Show properties and tree windows as small frames (Win32 only)" msgstr "" #: configUI.py:19 msgid "Show progress dialog when loading wxg files" msgstr "" #: configUI.py:20 msgid "Remember position and size of wxGlade windows" msgstr "" #: configUI.py:21 msgid "Show \"handles\" of sizers" msgstr "" #: configUI.py:22 msgid "Use native file dialogs on KDE" msgstr "" #: configUI.py:27 msgid "Use dialog units by default for size properties" msgstr "" #: configUI.py:28 msgid "Create backup wxg files" msgstr "" #: configUI.py:29 msgid "Create backup files for generated source" msgstr "" #: configUI.py:30 msgid "Allow duplicate widget names" msgstr "" #: configUI.py:31 msgid "Default border width for widgets" msgstr "" #: configUI.py:33 msgid "Auto save wxg files every " msgstr "" #: configUI.py:35 msgid "Backup options" msgstr "" #: configUI.py:35 msgid "append ~ to filename" msgstr "" #: configUI.py:35 msgid "append .bak to filename" msgstr "" #: configUI.py:47 msgid "wxGlade: preferences" msgstr "" #: configUI.py:83 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" #: configUI.py:86 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" #: configUI.py:90 msgid "Number of items in file history" msgstr "" #: configUI.py:93 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" #: configUI.py:122 msgid "Interface" msgstr "" #: configUI.py:123 msgid "Other" msgstr "" #: wxglade.py:76 wxglade.py:78 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "" #: wxglade.py:80 wxglade.py:82 #, python-format msgid "Error: %s" msgstr "" #: wxglade.py:90 wxglade.py:92 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" #: wxglade.py:101 wxglade.py:103 msgid "Valid LANGUAGE values:" msgstr "" #: edit_widget.py:103 msgid "'name' attribute missing" msgstr "" #: edit_windows.py:57 msgid "" "If you change the default value, it will be interpreted as the name of the " "subclass of the widget. How this name affects code generation depends on the " "kind (i.e. language) of output. See the docs for more details." msgstr "" #: edit_windows.py:148 edit_sizers/edit_sizers.py:650 #, python-format msgid "" "Name \"%s\" is already in use.\n" "Please enter a different one." msgstr "" #: edit_windows.py:161 edit_windows.py:261 edit_sizers/edit_sizers.py:664 #: edit_sizers/edit_sizers.py:706 #, python-format msgid "Properties - <%s>" msgstr "" #: edit_windows.py:179 edit_windows.py:1024 edit_sizers/edit_sizers.py:87 #: edit_sizers/edit_sizers.py:215 widgets/menubar/menubar.py:666 msgid "Remove\tDel" msgstr "" #: edit_windows.py:181 edit_sizers/edit_sizers.py:498 msgid "Copy\tCtrl+C" msgstr "" #: edit_windows.py:183 edit_sizers/edit_sizers.py:499 msgid "Cut\tCtrl+X" msgstr "" #: edit_windows.py:480 edit_sizers/edit_sizers.py:634 #: widgets/menubar/menubar.py:587 msgid "Common" msgstr "" #: edit_windows.py:946 msgid "Preview" msgstr "" #: edit_windows.py:960 msgid "Close Preview" msgstr "" #: edit_windows.py:1026 widgets/menubar/menubar.py:668 msgid "Hide" msgstr "" #: edit_windows.py:1033 edit_sizers/edit_sizers.py:89 msgid "Paste\tCtrl+V" msgstr "" #: edit_windows.py:1041 msgid "" "\n" "wxGlade-WARNING: sizer already set for this window" msgstr "" #: edit_windows.py:1050 msgid "" "\n" "wxGlade-WARNING: only sizers can be pasted here" msgstr "" #: events_mixin.py:22 msgid "Event" msgstr "" #: events_mixin.py:23 msgid "Handler" msgstr "" #: font_dialog.py:30 msgid "Family:" msgstr "" #: font_dialog.py:31 msgid "Style:" msgstr "" #: font_dialog.py:32 msgid "Weight:" msgstr "" #: font_dialog.py:97 msgid "Select font attributes" msgstr "" #: kdefiledialog.py:69 #, python-format msgid "File '%s' already exists: do you really want to overwrite it?" msgstr "" #: kdefiledialog.py:77 kdefiledialog.py:118 msgid "Fork Error" msgstr "" #: layout_option_property.py:40 layout_option_property.py:42 msgid "Option" msgstr "" #: layout_option_property.py:62 layout_option_property.py:64 msgid "Position" msgstr "" #: layout_option_property.py:72 layout_option_property.py:74 msgid "Span" msgstr "" #: main.py:165 zmain.py:148 msgid "Show &Tree\tCtrl+T" msgstr "" #: main.py:168 zmain.py:151 msgid "Show &Properties\tCtrl+P" msgstr "" #: main.py:172 zmain.py:155 msgid "&New\tCtrl+N" msgstr "" #: main.py:174 zmain.py:157 msgid "&Open...\tCtrl+O" msgstr "" #: main.py:176 zmain.py:159 msgid "&Save\tCtrl+S" msgstr "" #: main.py:178 zmain.py:161 msgid "Save As...\tShift+Ctrl+S" msgstr "" #: main.py:182 msgid "&Refresh\tf5" msgstr "" #: main.py:184 zmain.py:165 msgid "&Generate Code\tCtrl+G" msgstr "" #: main.py:189 msgid "&Import from XRC...\tCtrl+I" msgstr "" #: main.py:193 zmain.py:169 msgid "E&xit\tCtrl+Q" msgstr "" #: main.py:196 zmain.py:172 msgid "Preferences..." msgstr "" #: main.py:197 zmain.py:173 msgid "&File" msgstr "" #: main.py:198 zmain.py:174 msgid "&View" msgstr "" #: main.py:200 zmain.py:176 msgid "Contents\tF1" msgstr "" #: main.py:202 zmain.py:178 msgid "About..." msgstr "" #: main.py:203 main.py:210 zmain.py:179 msgid "&Help" msgstr "" #: main.py:228 main.py:573 msgid "" "There seems to be auto saved data for this file: do you want to restore it?" msgstr "" #: main.py:230 main.py:478 main.py:575 msgid "Auto save detected" msgstr "" #: main.py:274 zmain.py:219 msgid "Core components" msgstr "" #: main.py:274 zmain.py:219 msgid "Custom components" msgstr "" #: main.py:347 zmain.py:292 msgid "Properties - " msgstr "" #: main.py:380 zmain.py:324 msgid "wxGlade: Tree" msgstr "" #: main.py:475 msgid "" "There seems to be auto saved data from last wxGlade session: do you want to " "restore it?" msgstr "" #: main.py:484 msgid "Recovery from auto save complete" msgstr "" #: main.py:491 msgid "Auto saving... done" msgstr "" #: main.py:525 zmain.py:421 msgid "Save changes to the current app?" msgstr "" #: main.py:525 zmain.py:421 msgid "Confirm" msgstr "" #: main.py:549 msgid "Impossible to reload an unsaved application" msgstr "" #: main.py:550 msgid "Alert" msgstr "" #: main.py:565 zmain.py:445 msgid "Open file" msgstr "" #: main.py:619 zmain.py:481 #, python-format msgid "Error loading file %s: %s" msgstr "" #: main.py:632 zmain.py:494 #, python-format msgid "" "An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:653 msgid "Loaded template" msgstr "" #: main.py:657 #, python-format msgid "Loading time: %.5f" msgstr "" #: main.py:669 #, python-format msgid "Loaded %s (%.2f seconds)" msgstr "" #: main.py:692 zmain.py:538 #, python-format msgid "" "Error saving app:\n" "%s" msgstr "" #: main.py:698 zmain.py:544 #, python-format msgid "" "An exception occurred while saving file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:714 #, python-format msgid "Saved %s" msgstr "" #: main.py:720 zmain.py:560 msgid "Save project as..." msgstr "" #: main.py:752 zmain.py:587 #, python-format msgid "" "Error saving preferences:\n" "%s" msgstr "" #: main.py:797 msgid "Import file" msgstr "" #: main.py:810 #, python-format msgid "" "An exception occurred while importing file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: misc.py:404 msgid " - " msgstr "" #: tree.py:32 msgid "Properties - <>" msgstr "" #: tree.py:267 msgid "Application" msgstr "" #: tree.py:280 msgid "Show" msgstr "" #: tree.py:448 #, python-format msgid "wxGlade: Tree %s" msgstr "" #: widget_properties.py:641 msgid "All Files|*" msgstr "" #: widget_properties.py:642 msgid "Choose a file" msgstr "" #: widget_properties.py:765 #, python-format msgid "error in the value of the property \"%s\"" msgstr "" #: widget_properties.py:918 msgid " Apply " msgstr "" #: widget_properties.py:921 msgid " Add " msgstr "" #: widget_properties.py:924 msgid " Insert " msgstr "" #: widget_properties.py:927 msgid " Remove " msgstr "" #: xml_parse.py:253 msgid "Loading..." msgstr "" #: xml_parse.py:253 msgid "Please wait while loading the app" msgstr "" #: zmain.py:445 zmain.py:561 msgid "wxGlade files (*.wxg)|*.wxg|XML files (*.xml)|*.xml|All files|*" msgstr "" #: edit_sizers/edit_sizers.py:83 msgid "Options" msgstr "" #: edit_sizers/edit_sizers.py:286 edit_sizers/edit_sizers.py:287 msgid "Select sizer type" msgstr "" #: edit_sizers/edit_sizers.py:389 msgid "Select a position" msgstr "" #: edit_sizers/edit_sizers.py:495 edit_sizers/edit_sizers.py:1492 msgid "Add slot" msgstr "" #: edit_sizers/edit_sizers.py:496 edit_sizers/edit_sizers.py:1493 msgid "Insert slot..." msgstr "" #: edit_sizers/edit_sizers.py:626 msgid "Fit parent" msgstr "" #: edit_sizers/edit_sizers.py:1494 msgid "Add row" msgstr "" #: edit_sizers/edit_sizers.py:1495 msgid "Add column" msgstr "" #: edit_sizers/edit_sizers.py:1496 msgid "Insert row..." msgstr "" #: edit_sizers/edit_sizers.py:1497 msgid "Insert column..." msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Growable Rows" msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Select growable rows" msgstr "" #: edit_sizers/edit_sizers.py:1891 msgid "Growable Columns" msgstr "" #: edit_sizers/edit_sizers.py:1892 msgid "Select growable columns" msgstr "" #: edit_sizers/edit_sizers.py:2002 msgid "Orientation" msgstr "" #: edit_sizers/edit_sizers.py:2003 edit_sizers/edit_sizers.py:2049 msgid "Horizontal" msgstr "" #: edit_sizers/edit_sizers.py:2003 msgid "Vertical" msgstr "" #: edit_sizers/edit_sizers.py:2006 msgid "Slots: " msgstr "" #: edit_sizers/edit_sizers.py:2016 msgid "Has a Static Box" msgstr "" #: edit_sizers/edit_sizers.py:2022 msgid "Label: " msgstr "" #: edit_sizers/edit_sizers.py:2098 msgid "Select sizer attributes" msgstr "" #: widgets/bitmap_button/bitmap_button.py:120 msgid "Select the image for the button" msgstr "" #: widgets/gauge/gauge.py:32 msgid "Creates a horizontal gauge." msgstr "" #: widgets/gauge/gauge.py:33 msgid "Creates a vertical gauge." msgstr "" #: widgets/gauge/gauge.py:34 msgid "Under Windows 95, creates a horizontal progress bar." msgstr "" #: widgets/gauge/gauge.py:35 msgid "" "Creates smooth progress bar with one pixel wide update step (not supported " "by all platforms)." msgstr "" #: widgets/gauge/gauge.py:91 widgets/slider/slider.py:131 msgid "Select style" msgstr "" #: widgets/grid/grid.py:199 msgid "" "The following properties are meaningful\n" "only if 'Create grid' is selected" msgstr "" #: widgets/grid/grid.py:220 widgets/notebook/notebook.py:224 #: widgets/radio_button/radio_button.py:74 widgets/slider/slider.py:84 #: widgets/static_text/static_text.py:65 widgets/text_ctrl/text_ctrl.py:76 #: widgets/tree_ctrl/tree_ctrl.py:105 msgid "Widget" msgstr "" #: widgets/list_box/list_box.py:46 msgid "Single-selection list." msgstr "" #: widgets/list_box/list_box.py:47 msgid "Multiple-selection list: the user can toggle multiple items on and off." msgstr "" #: widgets/list_box/list_box.py:48 msgid "" "Extended-selection list: the user can select multiple items using the SHIFT " "key and the mouse or special key combinations." msgstr "" #: widgets/list_box/list_box.py:49 msgid "Create horizontal scrollbar if contents are too wide (Windows only)." msgstr "" #: widgets/list_box/list_box.py:50 msgid "Always show a vertical scrollbar." msgstr "" #: widgets/list_box/list_box.py:51 msgid "Only create a vertical scrollbar if needed." msgstr "" #: widgets/list_box/list_box.py:52 msgid "The listbox contents are sorted in alphabetical order." msgstr "" #: widgets/list_ctrl/list_ctrl.py:71 msgid "" "Multicolumn list view, with optional small icons. Columns are computed " "automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, " "the list wraps, unlike a wxListBox." msgstr "" #: widgets/list_ctrl/list_ctrl.py:72 msgid "Single or multicolumn report view, with optional header." msgstr "" #: widgets/list_ctrl/list_ctrl.py:73 msgid "Large icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:74 msgid "" "The application provides items text on demand. May only be used with " "wxLC_REPORT." msgstr "" #: widgets/list_ctrl/list_ctrl.py:75 msgid "Small icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:76 msgid "Icons align to the top. Win32 default, Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:77 msgid "Icons align to the left." msgstr "" #: widgets/list_ctrl/list_ctrl.py:78 msgid "Icons arrange themselves. Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:79 msgid "" "Labels are editable: the application will be notified when editing starts." msgstr "" #: widgets/list_ctrl/list_ctrl.py:80 msgid "No header in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:81 msgid "Single selection (default is multiple)." msgstr "" #: widgets/list_ctrl/list_ctrl.py:82 msgid "" "Sort in ascending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:83 msgid "" "Sort in descending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:84 msgid "Draws light horizontal rules between rows in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:85 msgid "Draws light vertical rules between columns in report mode" msgstr "" #: widgets/list_ctrl/list_ctrl.py:86 msgid "" "Displays a thin border around the window. wxBORDER is the old name for this " "style." msgstr "" #: widgets/list_ctrl/list_ctrl.py:87 msgid "Displays a double border. Windows and Mac only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:88 msgid "Displays a sunken border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:89 msgid "Displays a raised border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:90 msgid "Displays a border suitable for a static control. Windows only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:91 msgid "Displays no border, overriding the default border style for the window." msgstr "" #: widgets/list_ctrl/list_ctrl.py:92 msgid "" "Use this to indicate that the window wants to get all char/key events for " "all keys - even for keys like TAB or ENTER which are usually used for dialog " "navigation and which wouldn't be generated without this style. If you need " "to use this style in order to get the arrows or etc., but would still like " "to have normal keyboard navigation take place, you should create and send a " "wxNavigationKeyEvent in response to the key events for Tab and Shift-Tab." msgstr "" #: widgets/list_ctrl/list_ctrl.py:93 msgid "" "On Windows, this style used to disable repainting the window completely when " "its size is changed. Since this behaviour is now the default, the style is " "now obsolete and no longer has an effect." msgstr "" #: widgets/list_ctrl/list_ctrl.py:94 msgid "" "Use this style to force a complete redraw of the window whenever it is " "resized instead of redrawing just the part of the window affected by " "resizing. Note that this was the behaviour by default before 2.5.1 release " "and that if you experience redraw problems with code which previously used " "to work you may want to try this. Currently this style applies on GTK+ 2 and " "Windows only, and full repainting is always done on other platforms." msgstr "" #: widgets/menubar/menubar.py:18 msgid "Menu editor" msgstr "" #: widgets/menubar/menubar.py:24 msgid "Menu item:" msgstr "" #: widgets/menubar/menubar.py:32 msgid "Label" msgstr "" #: widgets/menubar/menubar.py:33 msgid "Id" msgstr "" #: widgets/menubar/menubar.py:34 msgid "Name" msgstr "" #: widgets/menubar/menubar.py:35 msgid "Help String" msgstr "" #: widgets/menubar/menubar.py:36 widgets/menubar/menubar.py:58 msgid "Type" msgstr "" #: widgets/menubar/menubar.py:38 msgid "Event Handler" msgstr "" #: widgets/menubar/menubar.py:61 msgid "Add" msgstr "" #: widgets/menubar/menubar.py:62 msgid "Remove" msgstr "" #: widgets/menubar/menubar.py:63 msgid "Add separator" msgstr "" #: widgets/menubar/menubar.py:66 msgid "Up" msgstr "" #: widgets/menubar/menubar.py:67 msgid "Down" msgstr "" #: widgets/menubar/menubar.py:72 msgid "Apply" msgstr "" #: widgets/menubar/menubar.py:120 msgid "Id " msgstr "" #: widgets/menubar/menubar.py:122 msgid "Label " msgstr "" #: widgets/menubar/menubar.py:124 msgid "Name " msgstr "" #: widgets/menubar/menubar.py:126 msgid "Help String " msgstr "" #: widgets/menubar/menubar.py:128 msgid "Event Handler " msgstr "" #: widgets/menubar/menubar.py:506 msgid "Edit menus..." msgstr "" #: widgets/menubar/menubar.py:766 msgid "Select menubar class" msgstr "" #: widgets/notebook/notebook.py:331 msgid "Select tab placement" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Top" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Bottom" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Left" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Right" msgstr "" #: widgets/radio_button/radio_button.py:37 msgid "Clicked" msgstr "" #: widgets/radio_button/radio_button.py:42 msgid "Marks the beginning of a new group of radio buttons." msgstr "" #: widgets/radio_button/radio_button.py:43 msgid "" "In some circumstances, radio buttons that are not consecutive siblings " "trigger a hang bug in Windows (only). If this happens, add this style to " "mark the button as not belonging to a group, and implement the mutually-" "exclusive group behaviour yourself." msgstr "" #: widgets/radio_button/radio_button.py:44 msgid "" "Use a checkbox button instead of radio button (currently supported only on " "PalmOS)." msgstr "" #: widgets/slider/slider.py:52 msgid "Displays the slider horizontally (this is the default)." msgstr "" #: widgets/slider/slider.py:53 msgid "Displays the slider vertically." msgstr "" #: widgets/slider/slider.py:54 msgid "Displays tick marks." msgstr "" #: widgets/slider/slider.py:55 msgid "Displays minimum, maximum and value labels." msgstr "" #: widgets/slider/slider.py:56 msgid "Displays ticks on the left and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:57 msgid "Displays ticks on the right and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:58 msgid "Displays ticks on the top." msgstr "" #: widgets/slider/slider.py:59 msgid "Displays ticks on the bottom (this is the default)." msgstr "" #: widgets/slider/slider.py:60 msgid "Allows the user to select a range on the slider. Windows only." msgstr "" #: widgets/slider/slider.py:61 msgid "" "Inverses the mininum and maximum endpoints on the slider. Not compatible " "with wxSL_SELRANGE." msgstr "" #: widgets/static_text/static_text.py:42 msgid "Store as attribute" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:79 msgid " Tree Control:" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:82 #, python-format msgid " on wxGlade %s" msgstr "" spe-0.8.4.h/_spe/plugins/wxGlade/po/ja.po0000644000175000017500000011753010743421035017136 0ustar stanistanimsgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: brian_nt@nifty.com\n" "POT-Creation-Date: 2007-09-05 04:39+0900\n" "PO-Revision-Date: 2007-09-23 03:55+0900\n" "Last-Translator: Norihiko Tashi \n" "Language-Team: ja \n" "Plural-Forms: nplurals=1; plural=0\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.2dev-r319\n" msgid "" "\n" "wxGlade-WARNING: only sizers can be pasted here" msgstr "" "\n" "wxGlade-警告: ここにはサイザーしか貼り付けることができません" msgid "" "\n" "wxGlade-WARNING: sizer already set for this window" msgstr "" "\n" "wxGlade-警告: このウィンドウにはサイザーが既に設定されています" msgid " Add " msgstr " 追加 " msgid " Apply " msgstr " 適用 " msgid " Insert " msgstr " 挿入 " msgid " Remove " msgstr " 削除 " msgid " Tree Control:" msgstr " ツリーコントロール:" msgid " seconds" msgstr "秒" msgid "\"%s\" is not a valid code generator module" msgstr "\"%s\" は、有効なコード生成モジュールではありません" msgid "%s files (*.%s)|*.%s" msgstr "%sファイル(*.%s)|*.%s" msgid "&Edit" msgstr "編集(&E)" msgid "&File" msgstr "ファイル(&F)" msgid "&Generate Code\tCtrl+G" msgstr "コード生成(&G)\tCtrl+G" msgid "&Help" msgstr "ヘルプ(&H)" msgid "&Import from XRC...\tCtrl+I" msgstr "XRCからインポート(&I)...\tCtrl+I" msgid "&New\tCtrl+N" msgstr "新規作成(&N)\tCtrl+N" msgid "&Open...\tCtrl+O" msgstr "開く(&O)...\tCtrl+O" msgid "&Raise All\tF4" msgstr "全て表示(&R)" msgid "&Refresh\tf5" msgstr "リフレッシュ(&R)\tf5" msgid "&Save\tCtrl+S" msgstr "保存(&S)\tCtrl+S" msgid "&View" msgstr "表示(&V)" msgid "'name' attribute missing" msgstr "'name'属性がありません" msgid "'object' items must have a 'class' attribute" msgstr "'object'項目は'class'属性を持っていなければなりません" msgid "'path' attribute missing: could not generate code" msgstr "'path' 属性がありません: コードを生成できませんでした" msgid "'sizeritem' object not found" msgstr "'sizerItem'オブジェクトが見つかりません" msgid " - " msgstr "<デザイン> - " msgid " - %s" msgstr "<プレビュー> - %s" msgid "" "A comma-separated list of custom base classes. The first will be invoked " "with the same parameters as this class, while for the others the default " "constructor will be used. You should probably not use this if \"overwrite " "existing sources\" is not set." msgstr "" "コンマで区切ったカスタム基底クラスのリスト。最初のものは、このクラスと同じパ" "ラメータで呼び出されます。残りはディフォルトコンストラクタが使われます。\"既" "存のソースを上書きする\"が設定されていないなら、これを使うべきではありませ" "ん。" msgid "" "A template called '%s' already exists:\n" "do you want to overwrite it?" msgstr "" "'%s'テンプレートファイルは既に存在します:\n" "上書きしてもよろしいですか?" msgid "About wxGlade" msgstr "wxGladeについて" msgid "About..." msgstr "バージョン情報..." msgid "Add" msgstr "追加" msgid "Add a %s" msgstr "%sを追加" msgid "Add column" msgstr "列の追加" msgid "Add row" msgstr "行の追加" msgid "Add separator" msgstr "セパレータ追加" msgid "Add slot" msgstr "スロット追加" msgid "Alert" msgstr "警告" msgid "Alignment" msgstr "配置" msgid "Aligns the bitmap label to the bottom of the button. WIN32 only." msgstr "ビットマップラベルをボタンの下に揃える。WIN32のみ。" msgid "Aligns the bitmap label to the top of the button. WIN32 only." msgstr "ビットマップラベルをボタンの上に揃える。WIN32のみ。" msgid "Aligns the label to the bottom of the button. Windows and GTK+ only." msgstr "ラベルをボタンの下に揃える。WindowsとGTK+のみ。" msgid "Aligns the label to the top of the button. Windows and GTK+ only." msgstr "ラベルをボタンの上に揃える。WindowsとGTK+のみ。" msgid "All Files|*" msgstr "全てのファイル|*" msgid "All files|*" msgstr "全てのファイル|*" msgid "Allow duplicate widget names" msgstr "Widget名の重複を許可" msgid "Allows the user to select a range on the slider. Windows only." msgstr "ユーザがスライダーの範囲を選択可能にする。Windowsのみ。" msgid "Always show a vertical scrollbar." msgstr "常に垂直スクロールバーを表示する。" msgid "" "An exception occurred while generating the code for the application.\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "このアプリケーションのコード生成時に例外が発生しました。\n" "これは、以下に関連したエラーメッセージです:\n" " %s\n" "詳細は、コンソールに出力された完全なトレースバックを参照してください。\n" "wxGladeのバグとお思いならばぜひ報告をお願いします。" msgid "" "An exception occurred while importing file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"ファイルのインポート時に例外が発生しました。\n" "これは、以下に関連したエラーメッセージです:\n" " %s\n" "詳細は、コンソールに出力された完全なトレースバックを参照してください。\n" "wxGladeのバグとお思いならばぜひ報告をお願いします。" msgid "" "An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"ファイルの読み込み時に例外が発生しました。\n" "これは、以下に関連したエラーメッセージです:\n" " %s\n" "詳細は、コンソールに出力された完全なトレースバックを参照してください。\n" "wxGladeのバグとお思いならばぜひ報告をお願いします。" msgid "" "An exception occurred while saving file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"ファイルの保存時に例外が発生しました。\n" "これは、以下に関連したエラーメッセージです:\n" " %s\n" "詳細は、コンソールに出力された完全なトレースバックを参照してください。\n" "wxGladeのバグとお思いならばぜひ報告をお願いします。" msgid "Application" msgstr "アプリケーション" msgid "Apply" msgstr "適用" msgid "Are you sure?" msgstr "よろしいですか?" msgid "Author" msgstr "作者" msgid "Auto save detected" msgstr "自動保存を検出しました" msgid "Auto save wxg files every " msgstr "wxgファイルを指定時間毎に自動保存する " msgid "Auto saving... done" msgstr "自動保存... 完了" msgid "Available templates" msgstr "利用可能なテンプレート" msgid "Backup options" msgstr "バックアップオプション" msgid "Base class(es)" msgstr "基底クラス" msgid "Border" msgstr "ボーダー" msgid "Bottom" msgstr "下" msgid "Can't find the credits file!\n" msgstr "クレジットファイルが見つかりません!\n" msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" "ライセンスが見つかりません!\n" "以下でコピーを入手できます\n" "http://www.opensource.org/licenses/mit-license.php" msgid "Can't save a template with an empty name" msgstr "テンプレートを空の名前で保存できません" msgid "Cancel" msgstr "キャンセル" msgid "Changes will take effect after wxGlade is restarted" msgstr "変更はwxGlade再起動後に有効になります" msgid "Checked" msgstr "チェック化" msgid "Choose a directory:" msgstr "ディレクトリを選択してください" msgid "Choose a file" msgstr "ファイルを選択してください" msgid "Clicked" msgstr "クリック" msgid "Clipboard can't be opened." msgstr "クリップボードを開けません。" msgid "Close Preview" msgstr "プレビューを閉じる" msgid "Close preview" msgstr "プレビューを閉じる" msgid "Code" msgstr "コード" msgid "Code generation completed successfully" msgstr "コード生成が完了しました" msgid "Common" msgstr "共通" msgid "Confirm" msgstr "確認" msgid "Contents\tF1" msgstr "ヘルプの表示\tF1" msgid "Copy\tCtrl+C" msgstr "コピー\tCtrl+C" msgid "Core components" msgstr "コアコンポーネント" msgid "Create backup files for generated source" msgstr "生成ソースのバックアップファイルを作成する" msgid "Create backup wxg files" msgstr "wxgファイルのバックアップを作成する" msgid "Create horizontal scrollbar if contents are too wide (Windows only)." msgstr "幅を超えた場合水平スクロールバーを作成する(Windowsのみ)。" msgid "Creates a combobox with a drop-down list." msgstr "ドロップダウンリストを持つコンボボックスを作成" msgid "Creates a combobox with a permanently displayed list. Windows only." msgstr "常時表示リストを持つコンボボックスを作成。Windowsのみ。" msgid "Creates a flat button. Windows and GTK+ only." msgstr "二重ボーダを表示する。WindowsとMacのみ。" msgid "Creates a horizontal gauge." msgstr "水平ゲージを作成する" msgid "Creates a vertical gauge." msgstr "垂直ゲージを作成する" msgid "" "Creates smooth progress bar with one pixel wide update step (not supported " "by all platforms)." msgstr "" "1ピクセル幅の更新間隔を持つスムースプログレスバーを作成する全てのプラット" "フォームでサポートされているわけではありません" msgid "" "Creates the button as small as possible instead of making it of the standard " "size (which is the default behaviour )." msgstr "出来る限り小さいボタンを作成する。ディフォルトでは標準サイズ" msgid "Custom Widget: %s" msgstr "カスタムWidget: %s" msgid "Custom colour" msgstr "カスタムカラー" msgid "Custom components" msgstr "カスタムコンポーネント" msgid "Cut\tCtrl+X" msgstr "切り取り\tCtrl+X" msgid "Data can't be copied from clipboard." msgstr "クリップボードからデータをコピーできません。" msgid "Data can't be copied to clipboard." msgstr "クリップボードにデータをコピーできません。" msgid "Default border width for widgets" msgstr "Widgetのディフォルトボーダー幅" msgid "Delete template '%s'?" msgstr "テンプレート '%s'を削除しますか? " msgid "Description" msgstr "詳細" msgid "Disable the month (and, implicitly, the year) changing" msgstr "月(暗黙に年)の変更を禁止" msgid "Disable the year changing" msgstr "年の変更を禁止" msgid "Display a resizeable frame around the window." msgstr "ウィンドウ周りにリサイズ可能なフレームを表示" msgid "Display a system menu." msgstr "システムメニューを表示" msgid "Display a thick frame around the window." msgstr "ウィンドウ周りに薄いフレームを表示" msgid "Displays a border suitable for a static control. Windows only." msgstr "スタティックコントロール用に適したボーダを表示する。Windowsのみ。" msgid "Displays a close box on the frame." msgstr "クローズボックスをフレーム上に表示する" msgid "Displays a double border. Windows and Mac only." msgstr "二重ボーダを表示する。WindowsとMacのみ。" msgid "Displays a maximize box on the dialog." msgstr "ダイアログに最大ボックスを表示" msgid "Displays a minimize box on the dialog." msgstr "ダイアログに最小ボックスを表示" msgid "Displays a raised border." msgstr "浮き彫り型ボーダを表示する" msgid "Displays a sunken border." msgstr "窪んだボーダを表示する" msgid "" "Displays a thin border around the window. wxBORDER is the old name for this " "style." msgstr "" "ウィンドウに薄いボーダーを表示する。wxBORDERはこのスタイルの古い名前です。" msgid "Displays minimum, maximum and value labels." msgstr "ラベルの最小値・最大値・値ラベルを表示する" msgid "Displays no border, overriding the default border style for the window." msgstr "" "ボーダを表示しない。ウィンドウのディフォルトボーダスタイルを上書きします。" msgid "Displays the slider horizontally (this is the default)." msgstr "スライダを水平に表示(ディフォルト設定)" msgid "Displays the slider vertically." msgstr "スライダを垂直に表示" msgid "Displays tick marks." msgstr "メモリを表示" msgid "Displays ticks on the bottom (this is the default)." msgstr "メモリを下に表示する" msgid "Displays ticks on the left and forces the slider to be vertical." msgstr "目盛りを左に表示し、スライダーを垂直にします" msgid "Displays ticks on the right and forces the slider to be vertical." msgstr "目盛りを右に表示し、スライダーを垂直にします" msgid "Displays ticks on the top." msgstr "メモリを上に表示する" msgid "Don't generate code for this custom class" msgstr "このカスタムクラスではコードを生成しない" msgid "Down" msgstr "下へ" msgid "Draws light horizontal rules between rows in report mode." msgstr "レポートモードで行間に細い水平の罫線を絵画する" msgid "Draws light vertical rules between columns in report mode" msgstr "レポートモードで列間に細い垂直の罫線を絵画する" msgid "E&xit\tCtrl+Q" msgstr "終了(&X)\tCtrl+Q" msgid "ERR:" msgstr "エラー:" msgid "ERROR creating %s: %s" msgstr "%s 作成エラー: %s" msgid "ERROR loading \"%s\"" msgstr "\"%s\"の読み込みエラー" msgid "Edit" msgstr "編集" msgid "Edit menus..." msgstr "メニューの編集..." msgid "Edit tools..." msgstr "ツールの編集..." msgid "EditBase or SizerBase object needed" msgstr "EditBaseまたはSizerBaseオブジェクトが必要です" msgid "EditPanel: Unable to disconnect the event hanlder" msgstr "エディットパネル:イベントハンドラを切断できません" msgid "Enable gettext support" msgstr "gettextサポートを有効化" msgid "Enter size" msgstr "サイズを入力してください" msgid "Error" msgstr "エラー" msgid "" "Error generating code:\n" "%s" msgstr "" "コード生成エラー:\n" "%s" msgid "Error loading file %s: %s" msgstr "ファイル%s読み込みエラー: %s" msgid "" "Error reading config file:\n" "%s" msgstr "" "コンフィグファイルの読み込みに失敗しました:\n" "%s" msgid "" "Error saving app:\n" "%s" msgstr "" "アプリ保存エラー:\n" "%s" msgid "" "Error saving preferences:\n" "%s" msgstr "" "設定保存エラー:\n" "%s" msgid "Error: %s" msgstr "エラー: %s" msgid "Error: no writer for language \"%s\" available" msgstr "エラー: \"%s\"言語用のライターは利用可能ではありません" msgid "Event" msgstr "イベント" msgid "Event Handler" msgstr "イベントハンドラ" msgid "Event Handler " msgstr "イベントハンドラ " msgid "Event handler `on_delete' not implemented!" msgstr "イベントハンドラ `on_delete' が実装されていません!" msgid "Event handler `on_edit' not implemented!" msgstr "イベントハンドラ `on_edit' が実装されていません!" msgid "Event handler `on_open' not implemented!" msgstr "イベントハンドラ `on_open' が実装されていません!" msgid "Event handler `on_select_template' not implemented!" msgstr "イベントハンドラ `on_select_template' が実装されていません!" msgid "Events" msgstr "イベント" msgid "Exception! obj: %s" msgstr "例外! オブジェクト: %s" msgid "" "Extended-selection list: the user can select multiple items using the SHIFT " "key and the mouse or special key combinations." msgstr "" "拡張選択リスト: ユーザはシフトキー、マウス、特殊なキー操作を使用することで複" "数項目を選択することができます" msgid "Extra code for this widget" msgstr "このWidget特有のコード" msgid "Extra properties for this widget" msgstr "このWidget特有のプロパティ" msgid "Family:" msgstr "ファミリー:" msgid "File '%s' already exists: do you really want to overwrite it?" msgstr "ファイル '%s' は既に存在します:本当に上書きしたいですか?" msgid "Fit parent" msgstr "親に合わせる" msgid "Flexible" msgstr "伸縮可能" msgid "Fork Error" msgstr "フォークエラー" msgid "Found widgets listing -> %s" msgstr "Widgetsリストが見つかりました -> %s" msgid "Generate code" msgstr "コード生成" msgid "Grid" msgstr "グリッド" msgid "Growable Columns" msgstr "伸張可能列" msgid "Growable Rows" msgstr "伸張可能行" msgid "Handler" msgstr "ハンドラ" msgid "Has MenuBar" msgstr "メニューバーを保持" msgid "Has StatusBar" msgstr "ステータスバーを保持" msgid "Has ToolBar" msgstr "ツールバーを保持" msgid "Has a Static Box" msgstr "スタティックボックスを保持" msgid "Help String" msgstr "ヘルプ文字列" msgid "Help String " msgstr "ヘルプ文字列 " msgid "Help on \"Arguments\" property" msgstr "\"引数\"プロパティのヘルプ" msgid "Hide" msgstr "隠す" msgid "Highlight holidays in the calendar" msgstr "カレンダーで休日を強調" msgid "Horizontal" msgstr "水平" msgid "Icons align to the left." msgstr "アイコンを左に寄せます" msgid "Icons align to the top. Win32 default, Win32 only." msgstr "アイコンを上に寄せます。Win32のディフォルトです。Win32のみ。" msgid "Icons arrange themselves. Win32 only." msgstr "アイコン自身で整列。Win32のみ。" msgid "" "If this is a custom class, setting this property prevents wxGlade\n" "from generating the class definition code" msgstr "" "これがカスタムクラスなら、このプロパティをセットすることで\n" "wxGladeがクラス定義コードを生成するのを抑制します。" msgid "" "If you change the default value, it will be interpreted as the name of the " "subclass of the widget. How this name affects code generation depends on the " "kind (i.e. language) of output. See the docs for more details." msgstr "" "ディフォルト値を変更した場合は、そのWidgetのサブクラスの名前と解釈されます。" "この名前がコード生成にどう影響を与えるかは、出力方式(言語など)によります。詳" "細はドキュメントを参照してください。" msgid "Import file" msgstr "ファイルのインポート" msgid "Impossible to reload an unsaved application" msgstr "保存されていないアプリは再読み込みできません" msgid "Information" msgstr "情報" msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" "コード生成ファイルダイアログの\n" "初期パス:" msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" "ファイル読み込み/保存ダイアログの\n" "初期パス:" msgid "Insert .wxg file name on generated source files" msgstr "生成ソースファイルに.wxgファイル名を挿入する" msgid "Insert column..." msgstr "列の挿入..." msgid "Insert row..." msgstr "行の挿入..." msgid "Insert slot..." msgstr "スロット挿入..." msgid "Insert timestamp on generated source files" msgstr "生成ソースファイルにタイムスタンプを挿入する" msgid "Instructions" msgstr "説明" msgid "Interface" msgstr "インターフェース" msgid "Invalid data in the clipboard" msgstr "クリップボードのデータは有効ではありません" msgid "" "Inverses the mininum and maximum endpoints on the slider. Not compatible " "with wxSL_SELRANGE." msgstr "" "スライダーの最小値と最大値を反転する。wxSL_SELRANGEと\"\n" "\"互換性がありません。" msgid "Label" msgstr "ラベル " msgid "Label " msgstr "ラベル " msgid "Label: " msgstr "ラベル: " msgid "" "Labels are editable: the application will be notified when editing starts." msgstr "ラベルは編集可能: アプリケーションは編集開始時に通知を受けます。" msgid "Large icon view, with optional labels." msgstr "オプションラベルを持つ大きいアイコンビュー" msgid "Layout" msgstr "レイアウト" msgid "Left" msgstr "左" msgid "Left-justifies the label. Windows and GTK+ only." msgstr "ラベルを左に揃える。WindowsとGTK+のみ。" msgid "List Control:" msgstr "リストコンロトール" msgid "Loaded %s (%.2f seconds)" msgstr " %sを読み込みました (%.2f 秒)" msgid "Loaded template" msgstr "テンプレートを読み込みました" msgid "Loading time: %.5f" msgstr "読み込み時間: %.5f" msgid "Loading..." msgstr "読み込み中..." msgid "Local widget path" msgstr "ローカルWidgetパス" msgid "Long Help" msgstr "長いヘルプ" msgid "Long Help " msgstr "長いヘルプ" msgid "Marks the beginning of a new group of radio buttons." msgstr "新規ラジオボタングループの開始を指定してください" msgid "Menu editor" msgstr "メニューエディタ" msgid "Menu item:" msgstr "メニューアイテム:" msgid "" "Multicolumn list view, with optional small icons. Columns are computed " "automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, " "the list wraps, unlike a wxListBox." msgstr "" "オプションの小さいアイコンを持つ複数列リストビュー。列は自動的に計算されます" "(wxLC_REPORTをセットしなくて良い)。言い換えると、wxListBoxと違い一巡します。" msgid "Multiple-selection list: the user can toggle multiple items on and off." msgstr "複数選択リスト: ユーザは複数のアイテムをオンオフ出来ます。" msgid "NO DESCRIPTION" msgstr "詳細なし" msgid "Name" msgstr "名前" msgid "Name " msgstr "名前 " msgid "" "Name \"%s\" is already in use.\n" "Please enter a different one." msgstr "" "名前\"%s\"は既に使われています。\n" "別の名前を入力してください。" msgid "New from &Template...\tShift+Ctrl+N" msgstr "テンプレートから新規作成(&T)...\tShift+Ctrl+N" msgid "No %s code generator for %s (of type %s) available" msgstr "%sコードジェネレータは利用できません:%s (タイプ%s)" msgid "No files selected!" msgstr "ファイルが選択されませんでした!" msgid "No header in report mode." msgstr "レポートモード内にヘッダ無し" msgid "No wxApp created yet" msgstr "wxAppはまだ生成されていません" msgid "None node in _find_toplevel" msgstr "_find_toplevel内にノードがありません" msgid "Normal Bitmap" msgstr "通常のビットマップ" msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" "メインパレットにおける\"\n" "\"一行当たりのボタンの数" msgid "Number of items in file history" msgstr "ファイル履歴の項目数" msgid "OK" msgstr "OK" msgid "" "On Windows, this style used to disable repainting the window completely when " "its size is changed. Since this behaviour is now the default, the style is " "now obsolete and no longer has an effect." msgstr "" "過去Windowsでは、サイズが変わったときに、このスタイルを使ってウィンドウの完全" "な再絵画を禁止していました。今ではこの動作がディフォルトです。このスタイルは" "現在削除されており、何の効果もありません。" msgid "Only create a vertical scrollbar if needed." msgstr "必要な時のみ垂直スクロールバーを表示する。" msgid "Oops!" msgstr "おっと!" msgid "Open file" msgstr "ファイルのインポート" msgid "Options" msgstr "オプション " msgid "Orientation" msgstr "方向" msgid "Other" msgstr "その他" msgid "Output path" msgstr "出力パス" msgid "Output path can't be a directory when generating a single file" msgstr "単一ファイル生成時の出力パスはディレクトリにできません" msgid "" "Output path must be an existing directory when generating multiple files" msgstr "複数ファイル生成時の出力パスは存在するディレクトでなければなりません" msgid "Overwrite existing sources" msgstr "既存のソースを上書きする" msgid "Paste\tCtrl+V" msgstr "貼り付け\tCtrl+V" msgid "Please only drop one file at a time" msgstr "同時に1ファイルのみドロップ可能です" msgid "Please select a top window for the application" msgstr "アプリケーション用のトップウィンドウを選択してください" msgid "Please wait while loading the app" msgstr "アプリを読み込む間お待ちください" msgid "Position" msgstr "位置" msgid "Preferences saved" msgstr "設定が保存されました" msgid "Preferences..." msgstr "設定..." msgid "Preview" msgstr "プレビュー" msgid "Problem previewing gui: %s" msgstr "GUIのプレビューに問題が発生しました: %s" msgid "Properties - <%s>" msgstr "プロパティ - <%s>" msgid "Properties - <>" msgstr "プロパティ - <>" msgid "Properties - " msgstr "プロパティ - " msgid "Property" msgstr "プロパティ" msgid "Proportion" msgstr "プロポーション" msgid "Puts a caption on the dialog box." msgstr "ダイアログボックスにキャプションを入れる" msgid "Python files|*.py;*.pyc|All files|*" msgstr "Pythonファイル|*.py;*.pyc|全てのファイル|*" msgid "Question" msgstr "質問" msgid "Recovery from auto save complete" msgstr "自動保存から完全に回復" msgid "Remember position and size of wxGlade windows" msgstr "wxGladeウィンドウズの位置とサイズを記憶" msgid "Remove" msgstr "削除" msgid "Remove\tDel" msgstr "削除\tDel" msgid "Right" msgstr "右" msgid "Right-justifies the bitmap label. WIN32 only." msgstr "ビットマップラベルを右に揃える。WIN32のみ。" msgid "Right-justifies the bitmap label. Windows and GTK+ only." msgstr "ぶっとマップラベルを右に揃える。WindowsとGTK+のみ。" msgid "Save As Template..." msgstr "テンプレートとして保存..." msgid "Save As...\tShift+Ctrl+S" msgstr "名前を付けて保存...\tShift+Ctrl+S" msgid "Save changes to the current app?" msgstr "現在のアプリへの変更を保存しますか?" msgid "Save project as..." msgstr "名前をつけてプロジェクトを保存..." msgid "Saved %s" msgstr "%sを保存しました" msgid "Second Bitmap" msgstr "二番目のビットマップ" msgid "Select a position" msgstr "位置を選択してください" msgid "Select font attributes" msgstr "フォント属性を選択してください" msgid "Select frame class" msgstr "メニューバークラスを選択してください" msgid "Select growable columns" msgstr "伸張可能列を選択してください" msgid "Select growable rows" msgstr "伸張可能行を選択してください" msgid "Select menubar class" msgstr "メニューバークラスを選択してください" msgid "Select output directory" msgstr "出力ディレクトリを選択してください:" msgid "Select output file" msgstr "出力ファイルを選択してください" msgid "Select sizer attributes" msgstr "サイザー属性を選択してください" msgid "Select sizer type" msgstr "サイザータイプを選択してください" msgid "Select style" msgstr "スタイルを選択してください" msgid "Select tab placement" msgstr "タブの位置を選択してください" msgid "Select the image for the button" msgstr "ボタンのイメージを選択してください" msgid "Select toolbar class" msgstr "ツールバークラスを選択してください" msgid "Select widget class" msgstr "メニューバークラスを選択してください" msgid "Select widget colour" msgstr "Widgetカラーを選択してください" msgid "Separate file for each class" msgstr "クラス別にファイルを分ける" msgid "Short Help" msgstr "短いヘルプ" msgid "Short Help " msgstr "短いヘルプ" msgid "Show" msgstr "表示" msgid "Show \"handles\" of sizers" msgstr "サイザーの\"ハンドル\"を表示" msgid "Show &Properties\tF3" msgstr "プロパティを表示(&P)\tF3" msgid "Show &Tree\tF2" msgstr "ツリーを表示(&T)\tF2" msgid "Show Monday as the first day in the week" msgstr "月曜を週の最初に表示" msgid "Show Sunday as the first day in the week" msgstr "日曜を週の最初に表示" msgid "Show progress dialog when loading wxg files" msgstr "wxgファイルの読み込み時に進行ダイアログを表示" msgid "Show properties and tree windows as small frames" msgstr "プロパティとツリーウィンドウをスモールフレームとして表示" msgid "Show the neighbouring weeks in the previous and next months" msgstr "前と次の月の近隣週を表示" msgid "Single file" msgstr "単一ファイル" msgid "Single or multicolumn report view, with optional header." msgstr "オプションヘッダを持つ単一・複数列のレポート" msgid "Single selection (default is multiple)." msgstr "単一選択(ディフォルト設定)" msgid "Single-selection list." msgstr "単一選択リスト" msgid "Size in points:" msgstr "サイズ(ポイント)" msgid "Slots: " msgstr "スロット: " msgid "Small icon view, with optional labels." msgstr "オプションのラベルを持つ小さいアイコンビュー" msgid "" "Sort in ascending order (must still supply a comparison callback in " "SortItems." msgstr "昇順でソート(SortItems内で比較コールバックを提供する必要があります)。" msgid "" "Sort in descending order (must still supply a comparison callback in " "SortItems." msgstr "降順でソート(SortItems内で比較コールバックを提供する必要があります)。" msgid "Sorts the entries in the list alphabetically." msgstr "リスト内エントリをアルファベット順にソート" msgid "Spacer" msgstr "スペーサー" msgid "Span" msgstr "範囲" msgid "Specific font..." msgstr "フォント指定..." msgid "Store as attribute" msgstr "属性として保存" msgid "Style" msgstr "スタイル" msgid "Style:" msgstr "スタイル:" msgid "System colour" msgstr "システムカラー" msgid "Templates Manager..." msgstr "テンプレートマネージャ..." msgid "" "The application provides items text on demand. May only be used with " "wxLC_REPORT." msgstr "" "アプリケーションはオンデマンドで項目テキストを提供する。\"\n" "\"wxLC_REPORTと一緒の時のみ使われるでしょう。" msgid "The dialog stays on top of all other windows." msgstr "ダイアログを他の全てのウィンドウより前に表示" msgid "" "The following properties are meaningful\n" "only if 'Create grid' is selected" msgstr "以下のプロパティは'グリッドを作成する'が選択されている場合のみ有効です" msgid "The listbox contents are sorted in alphabetical order." msgstr "リストボックスの内容はアルファベット順にソート。" msgid "" "There seems to be auto saved data for this file: do you want to restore it?" msgstr "" "このファイルには自動保存されたデータがあるようです:\"\n" "\"回復しますか?" msgid "" "There seems to be auto saved data from last wxGlade session: do you want to " "restore it?" msgstr "" "最後のwxGladeセッションでの自動保存データがあるようです。\n" "回復しますか?:" msgid "" "To save the changes to the template, edit the GUI as usual,\n" "and then click File->Save as Template..." msgstr "" "テンプレートへの変更を保存する場合、GUIを通常通り編集し、\n" "ファイル->テンプレートとして保存...をクリックしてください" msgid "Tool:" msgstr "ツール:" msgid "Toolbar editor" msgstr "ツールバーエディタ" msgid "Top" msgstr "上" msgid "Top window" msgstr "トップウィンドウ" msgid "Type" msgstr "タイプ" msgid "Under Windows 95, creates a horizontal progress bar." msgstr "Windows 95では、水平プログレスバーを作成する。" msgid "Underlined" msgstr "下線" msgid "Up" msgstr "上へ" msgid "" "Use a checkbox button instead of radio button (currently supported only on " "PalmOS)." msgstr "" "ラジオボタンの代わりにチェックボックスボタンを使用してください(現在ではPalmOS" "でのみサポートされています)" msgid "" "Use alternative, more compact, style for the month and year selection " "controls." msgstr "月と年の選択に別のよりコンパクトなスタイルを使用" msgid "Use dialog units by default for size properties" msgstr "サイズプロパティではディフォルトでダイアログユニットを使用" msgid "Use icons in menu items" msgstr "メニューアイテムにアイコンを使う" msgid "Use native file dialogs on KDE" msgstr "KDEでネイティブのファイルダイアログを使用" msgid "" "Use old \"from wxPython.wx\"\n" "import (python output only)" msgstr "" "古い形式の\"wxPython.wx\"を使用する\n" "インポート(出力はpythonのみ)" msgid "Valid LANGUAGE values:" msgstr "有効なLANGUAGE値:" msgid "Value" msgstr "値" msgid "Vertical" msgstr "垂直" msgid "WARNING" msgstr "警告" msgid "Warning: property '%s' not supported by this object ('%s') " msgstr "" "警告: '%s'プロパティはこのオブジェクト('%s')ではサポートされていません " msgid "Weight:" msgstr "幅:" msgid "" "You must specify an output file\n" "before generating any code" msgstr "" "コード出力をする前に\n" "出力ファイルを指定してください" msgid "You selected file: %s" msgstr "次のファイルを選択しました: %s" msgid "append .bak to filename" msgstr "ファイル名に.bakを追加" msgid "append ~ to filename" msgstr "ファイル名に~を追加" msgid "arguments" msgstr "引数" msgid "background" msgstr "バックグラウンド" msgid "base class" msgstr "基底クラス" msgid "bitmap" msgstr "ビットマップ" msgid "bitmapsize" msgstr "ビットマップサイズ" msgid "border" msgstr "ボーダー" msgid "centered" msgstr "中央" msgid "character data can be present only inside properties" msgstr "キャラクタデータはproperty内にのみ存在可能です" msgid "character data can only appear inside properties" msgstr "キャラクタデータはproperty内にのみ存在可能です" msgid "choices" msgstr "選択" msgid "class" msgstr "クラス" msgid "code generation" msgstr "コード生成" msgid "col_label_size" msgstr "列ラベルサイズ" msgid "cols" msgstr "列" msgid "columns" msgstr "列" msgid "create_grid" msgstr "グリッドを作成する" msgid "default" msgstr "ディフォルト" msgid "dimension" msgstr "次元" msgid "disabled" msgstr "禁止" msgid "disabled bitmap" msgstr "禁止時ビットマップ" msgid "enable_col_resize" msgstr "列のリサイズを有効化" msgid "enable_editing" msgstr "編集を有効化" msgid "enable_grid_lines" msgstr "グリッドラインを有効化" msgid "enable_grid_resize" msgstr "グリッドのリサイズを有効化" msgid "enable_row_resize" msgstr "行のリサイズを有効化" msgid "encoding" msgstr "エンコーディング" msgid "error in the value of the property \"%s\"" msgstr "プロパティ値エラー \"%s\"" msgid "events" msgstr "イベント" msgid "focused" msgstr "フォーカス" msgid "font" msgstr "フォント" msgid "foreground" msgstr "フォアグラウンド" msgid "height" msgstr "高さ" msgid "hgap" msgstr "水平ギャップ" msgid "hidden" msgstr "隠す" msgid "icon" msgstr "アイコン" msgid "label" msgstr "ラベル" msgid "label_bg_color" msgstr "ラベルバックグラウンドカラー" msgid "language" msgstr "言語" msgid "lines_color" msgstr "線の色" msgid "loaded code generator for %s" msgstr "%s 用のコードジェネレータを読み込みました" msgid "loading widget modules:" msgstr "Widgetモジュールを読み込み中:" msgid "malformed wxg file: slots can only be inside sizers!" msgstr "不正なwxgファイルです:slotはsizer内にのみ存在可能です" msgid "margins" msgstr "マージン" msgid "menu item outside a menu" msgstr "メニュー外のメニュー項目" msgid "name" msgstr "名前" msgid "orientation" msgstr "方向" msgid "packing" msgstr "パッキング" msgid "position" msgstr "位置" msgid "property '%s' not supported by '%s' objects" msgstr "'%s'プロパティは、'%s'クラスでサポートされていません" msgid "range" msgstr "範囲" msgid "row_label_size" msgstr "行ラベルサイズ" msgid "rows" msgstr "行" msgid "rows_number" msgstr "行の数" msgid "sash_pos" msgstr "窓枠位置" msgid "scroll_rate" msgstr "スクロールレート" msgid "scrollable" msgstr "スクロール可能" msgid "selection" msgstr "選択" msgid "selection_mode" msgstr "選択モード" msgid "separation" msgstr "セパレーション" msgid "size" msgstr "サイズ" msgid "sizer or sizeritem object cannot be None" msgstr "SizerまたはSizerItemオブジェクトが無いことは許されません" msgid "stockitem" msgstr "ストックアイテム" msgid "style" msgstr "スタイル" msgid "tab_placement" msgstr "タブ配置" msgid "tabs" msgstr "タブ" msgid "the root of the tree must be " msgstr "ツリーのルートはでなければなりません" msgid "title" msgstr "タイトル" msgid "tooltip" msgstr "ツールチップ" msgid "value" msgstr "値" msgid "vgap" msgstr "垂直ギャップ" msgid "width" msgstr "幅" msgid "wxGlade - Credits" msgstr "wxGlade - クレジット" msgid "wxGlade - License" msgstr "wxGlade - ライセンス" msgid "wxGlade message" msgstr "wxGladeメッセージ" msgid "wxGlade template information" msgstr "wxGladeテンプレート情報" msgid "wxGlade template list" msgstr "wxGladeテンプレートリスト" msgid "wxGlade template:\n" msgstr "wxGladeテンプレート:\n" msgid "wxGlade template: " msgstr "wxGladeテンプレート: " msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" "wxGlade 使用法:\n" "- GUIを開始する: python wxglade.py [WXG_FILE]\n" "- コマンドラインからコードを生成する: python wxglade.py オプション... FILE\n" " オプションには以下の物があります:\n" " -g, --generate-code=LANGUAGE (必須) 出力言語を指定する\n" " -o, --output=PATH (オプション)\n" " 出力ファイル名(単一ファイルモード)\n" " ディレクトリ(複数ファイルモード)\n" " " msgid "wxGlade: Tree" msgstr "wxGlade: ツリー" msgid "wxGlade: Tree %s" msgstr "wxGlade: ツリー %s" msgid "wxGlade: preferences" msgstr "wxGlade: 設定" msgid "wxWidgets compatibility" msgstr "wxWidgets互換性" spe-0.8.4.h/_spe/plugins/wxGlade/po/de.po0000644000175000017500000005473010743421035017136 0ustar stanistani# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-02-09 23:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: about.py:49 msgid "About wxGlade" msgstr "" #: about.py:59 msgid "wxGlade - License" msgstr "" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" #: about.py:67 edit_windows.py:149 main.py:620 main.py:637 main.py:692 #: main.py:705 main.py:753 main.py:815 zmain.py:482 zmain.py:499 zmain.py:538 #: zmain.py:551 zmain.py:587 edit_sizers/edit_sizers.py:651 msgid "Error" msgstr "" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "" #: about.py:80 msgid "Oops!" msgstr "" #: clipboard.py:40 clipboard.py:38 msgid "Invalid data in the clipboard" msgstr "" #: clipboard.py:65 clipboard.py:63 msgid "Data can't be copied to clipboard." msgstr "" #: clipboard.py:71 clipboard.py:105 clipboard.py:69 clipboard.py:103 msgid "Clipboard can't be opened." msgstr "" #: clipboard.py:98 clipboard.py:96 msgid "Data can't be copied from clipboard." msgstr "" #: clipboard.py:129 clipboard.py:127 msgid "Please only drop one file at a time" msgstr "" #: color_dialog.py:18 color_dialog.py:19 msgid "System colour" msgstr "" #: color_dialog.py:22 color_dialog.py:23 msgid "Custom colour" msgstr "" #: color_dialog.py:25 configUI.py:38 color_dialog.py:26 #: edit_sizers/edit_sizers.py:395 edit_sizers/edit_sizers.py:1808 #: edit_sizers/edit_sizers.py:2026 edit_sizers/edit_sizers.py:2122 #: widgets/gauge/gauge.py:104 widgets/menubar/menubar.py:71 #: widgets/menubar/menubar.py:777 widgets/notebook/notebook.py:339 msgid "OK" msgstr "" #: color_dialog.py:26 configUI.py:39 color_dialog.py:27 #: edit_sizers/edit_sizers.py:396 edit_sizers/edit_sizers.py:1809 #: widgets/menubar/menubar.py:73 widgets/menubar/menubar.py:778 msgid "Cancel" msgstr "" #: color_dialog.py:70 color_dialog.py:71 msgid "Select widget colour" msgstr "" #: common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "" #: common.py:96 #, python-format msgid "loaded code generator for %s" msgstr "" #: common.py:127 #, python-format msgid "Found widgets listing -> %s" msgstr "" #: common.py:128 msgid "loading widget modules:" msgstr "" #: common.py:137 #, python-format msgid "ERROR loading \"%s\"" msgstr "" #: common.py:203 #, python-format msgid "Add a %s" msgstr "" #: config.py:60 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" #: config.py:103 msgid "Choose a directory:" msgstr "" #: config.py:246 msgid "Changes will take effect after wxGlade is restarted" msgstr "" #: config.py:247 msgid "Preferences saved" msgstr "" #: configUI.py:15 msgid "Local widget path" msgstr "" #: configUI.py:17 msgid "Use icons in menu items" msgstr "" #: configUI.py:18 msgid "Show properties and tree windows as small frames (Win32 only)" msgstr "" #: configUI.py:19 msgid "Show progress dialog when loading wxg files" msgstr "" #: configUI.py:20 msgid "Remember position and size of wxGlade windows" msgstr "" #: configUI.py:21 msgid "Show \"handles\" of sizers" msgstr "" #: configUI.py:22 msgid "Use native file dialogs on KDE" msgstr "" #: configUI.py:27 msgid "Use dialog units by default for size properties" msgstr "" #: configUI.py:28 msgid "Create backup wxg files" msgstr "" #: configUI.py:29 msgid "Create backup files for generated source" msgstr "" #: configUI.py:30 msgid "Allow duplicate widget names" msgstr "" #: configUI.py:31 msgid "Default border width for widgets" msgstr "" #: configUI.py:33 msgid "Auto save wxg files every " msgstr "" #: configUI.py:35 msgid "Backup options" msgstr "" #: configUI.py:35 msgid "append ~ to filename" msgstr "" #: configUI.py:35 msgid "append .bak to filename" msgstr "" #: configUI.py:47 msgid "wxGlade: preferences" msgstr "" #: configUI.py:83 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" #: configUI.py:86 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" #: configUI.py:90 msgid "Number of items in file history" msgstr "" #: configUI.py:93 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" #: configUI.py:122 msgid "Interface" msgstr "" #: configUI.py:123 msgid "Other" msgstr "" #: wxglade.py:76 wxglade.py:78 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "" #: wxglade.py:80 wxglade.py:82 #, python-format msgid "Error: %s" msgstr "" #: wxglade.py:90 wxglade.py:92 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" #: wxglade.py:101 wxglade.py:103 msgid "Valid LANGUAGE values:" msgstr "" #: edit_widget.py:103 msgid "'name' attribute missing" msgstr "" #: edit_windows.py:57 msgid "" "If you change the default value, it will be interpreted as the name of the " "subclass of the widget. How this name affects code generation depends on the " "kind (i.e. language) of output. See the docs for more details." msgstr "" #: edit_windows.py:148 edit_sizers/edit_sizers.py:650 #, python-format msgid "" "Name \"%s\" is already in use.\n" "Please enter a different one." msgstr "" #: edit_windows.py:161 edit_windows.py:261 edit_sizers/edit_sizers.py:664 #: edit_sizers/edit_sizers.py:706 #, python-format msgid "Properties - <%s>" msgstr "" #: edit_windows.py:179 edit_windows.py:1024 edit_sizers/edit_sizers.py:87 #: edit_sizers/edit_sizers.py:215 widgets/menubar/menubar.py:666 msgid "Remove\tDel" msgstr "" #: edit_windows.py:181 edit_sizers/edit_sizers.py:498 msgid "Copy\tCtrl+C" msgstr "" #: edit_windows.py:183 edit_sizers/edit_sizers.py:499 msgid "Cut\tCtrl+X" msgstr "" #: edit_windows.py:480 edit_sizers/edit_sizers.py:634 #: widgets/menubar/menubar.py:587 msgid "Common" msgstr "" #: edit_windows.py:946 msgid "Preview" msgstr "" #: edit_windows.py:960 msgid "Close Preview" msgstr "" #: edit_windows.py:1026 widgets/menubar/menubar.py:668 msgid "Hide" msgstr "" #: edit_windows.py:1033 edit_sizers/edit_sizers.py:89 msgid "Paste\tCtrl+V" msgstr "" #: edit_windows.py:1041 msgid "" "\n" "wxGlade-WARNING: sizer already set for this window" msgstr "" #: edit_windows.py:1050 msgid "" "\n" "wxGlade-WARNING: only sizers can be pasted here" msgstr "" #: events_mixin.py:22 msgid "Event" msgstr "" #: events_mixin.py:23 msgid "Handler" msgstr "" #: font_dialog.py:30 msgid "Family:" msgstr "" #: font_dialog.py:31 msgid "Style:" msgstr "" #: font_dialog.py:32 msgid "Weight:" msgstr "" #: font_dialog.py:97 msgid "Select font attributes" msgstr "" #: kdefiledialog.py:69 #, python-format msgid "File '%s' already exists: do you really want to overwrite it?" msgstr "" #: kdefiledialog.py:77 kdefiledialog.py:118 msgid "Fork Error" msgstr "" #: layout_option_property.py:40 layout_option_property.py:42 msgid "Option" msgstr "" #: layout_option_property.py:62 layout_option_property.py:64 msgid "Position" msgstr "" #: layout_option_property.py:72 layout_option_property.py:74 msgid "Span" msgstr "" #: main.py:165 zmain.py:148 msgid "Show &Tree\tCtrl+T" msgstr "" #: main.py:168 zmain.py:151 msgid "Show &Properties\tCtrl+P" msgstr "" #: main.py:172 zmain.py:155 msgid "&New\tCtrl+N" msgstr "" #: main.py:174 zmain.py:157 msgid "&Open...\tCtrl+O" msgstr "" #: main.py:176 zmain.py:159 msgid "&Save\tCtrl+S" msgstr "" #: main.py:178 zmain.py:161 msgid "Save As...\tShift+Ctrl+S" msgstr "" #: main.py:182 msgid "&Refresh\tf5" msgstr "" #: main.py:184 zmain.py:165 msgid "&Generate Code\tCtrl+G" msgstr "" #: main.py:189 msgid "&Import from XRC...\tCtrl+I" msgstr "" #: main.py:193 zmain.py:169 msgid "E&xit\tCtrl+Q" msgstr "" #: main.py:196 zmain.py:172 msgid "Preferences..." msgstr "" #: main.py:197 zmain.py:173 msgid "&File" msgstr "" #: main.py:198 zmain.py:174 msgid "&View" msgstr "" #: main.py:200 zmain.py:176 msgid "Contents\tF1" msgstr "" #: main.py:202 zmain.py:178 msgid "About..." msgstr "" #: main.py:203 main.py:210 zmain.py:179 msgid "&Help" msgstr "" #: main.py:228 main.py:573 msgid "" "There seems to be auto saved data for this file: do you want to restore it?" msgstr "" #: main.py:230 main.py:478 main.py:575 msgid "Auto save detected" msgstr "" #: main.py:274 zmain.py:219 msgid "Core components" msgstr "" #: main.py:274 zmain.py:219 msgid "Custom components" msgstr "" #: main.py:347 zmain.py:292 msgid "Properties - " msgstr "" #: main.py:380 zmain.py:324 msgid "wxGlade: Tree" msgstr "" #: main.py:475 msgid "" "There seems to be auto saved data from last wxGlade session: do you want to " "restore it?" msgstr "" #: main.py:484 msgid "Recovery from auto save complete" msgstr "" #: main.py:491 msgid "Auto saving... done" msgstr "" #: main.py:525 zmain.py:421 msgid "Save changes to the current app?" msgstr "" #: main.py:525 zmain.py:421 msgid "Confirm" msgstr "" #: main.py:549 msgid "Impossible to reload an unsaved application" msgstr "" #: main.py:550 msgid "Alert" msgstr "" #: main.py:565 zmain.py:445 msgid "Open file" msgstr "" #: main.py:619 zmain.py:481 #, python-format msgid "Error loading file %s: %s" msgstr "" #: main.py:632 zmain.py:494 #, python-format msgid "" "An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:653 msgid "Loaded template" msgstr "" #: main.py:657 #, python-format msgid "Loading time: %.5f" msgstr "" #: main.py:669 #, python-format msgid "Loaded %s (%.2f seconds)" msgstr "" #: main.py:692 zmain.py:538 #, python-format msgid "" "Error saving app:\n" "%s" msgstr "" #: main.py:698 zmain.py:544 #, python-format msgid "" "An exception occurred while saving file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:714 #, python-format msgid "Saved %s" msgstr "" #: main.py:720 zmain.py:560 msgid "Save project as..." msgstr "" #: main.py:752 zmain.py:587 #, python-format msgid "" "Error saving preferences:\n" "%s" msgstr "" #: main.py:797 msgid "Import file" msgstr "" #: main.py:810 #, python-format msgid "" "An exception occurred while importing file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: misc.py:404 msgid " - " msgstr "" #: tree.py:32 msgid "Properties - <>" msgstr "" #: tree.py:267 msgid "Application" msgstr "" #: tree.py:280 msgid "Show" msgstr "" #: tree.py:448 #, python-format msgid "wxGlade: Tree %s" msgstr "" #: widget_properties.py:641 msgid "All Files|*" msgstr "" #: widget_properties.py:642 msgid "Choose a file" msgstr "" #: widget_properties.py:765 #, python-format msgid "error in the value of the property \"%s\"" msgstr "" #: widget_properties.py:918 msgid " Apply " msgstr "" #: widget_properties.py:921 msgid " Add " msgstr "" #: widget_properties.py:924 msgid " Insert " msgstr "" #: widget_properties.py:927 msgid " Remove " msgstr "" #: xml_parse.py:253 msgid "Loading..." msgstr "" #: xml_parse.py:253 msgid "Please wait while loading the app" msgstr "" #: zmain.py:445 zmain.py:561 msgid "wxGlade files (*.wxg)|*.wxg|XML files (*.xml)|*.xml|All files|*" msgstr "" #: edit_sizers/edit_sizers.py:83 msgid "Options" msgstr "" #: edit_sizers/edit_sizers.py:286 edit_sizers/edit_sizers.py:287 msgid "Select sizer type" msgstr "" #: edit_sizers/edit_sizers.py:389 msgid "Select a position" msgstr "" #: edit_sizers/edit_sizers.py:495 edit_sizers/edit_sizers.py:1492 msgid "Add slot" msgstr "" #: edit_sizers/edit_sizers.py:496 edit_sizers/edit_sizers.py:1493 msgid "Insert slot..." msgstr "" #: edit_sizers/edit_sizers.py:626 msgid "Fit parent" msgstr "" #: edit_sizers/edit_sizers.py:1494 msgid "Add row" msgstr "" #: edit_sizers/edit_sizers.py:1495 msgid "Add column" msgstr "" #: edit_sizers/edit_sizers.py:1496 msgid "Insert row..." msgstr "" #: edit_sizers/edit_sizers.py:1497 msgid "Insert column..." msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Growable Rows" msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Select growable rows" msgstr "" #: edit_sizers/edit_sizers.py:1891 msgid "Growable Columns" msgstr "" #: edit_sizers/edit_sizers.py:1892 msgid "Select growable columns" msgstr "" #: edit_sizers/edit_sizers.py:2002 msgid "Orientation" msgstr "" #: edit_sizers/edit_sizers.py:2003 edit_sizers/edit_sizers.py:2049 msgid "Horizontal" msgstr "" #: edit_sizers/edit_sizers.py:2003 msgid "Vertical" msgstr "" #: edit_sizers/edit_sizers.py:2006 msgid "Slots: " msgstr "" #: edit_sizers/edit_sizers.py:2016 msgid "Has a Static Box" msgstr "" #: edit_sizers/edit_sizers.py:2022 msgid "Label: " msgstr "" #: edit_sizers/edit_sizers.py:2098 msgid "Select sizer attributes" msgstr "" #: widgets/bitmap_button/bitmap_button.py:120 msgid "Select the image for the button" msgstr "" #: widgets/gauge/gauge.py:32 msgid "Creates a horizontal gauge." msgstr "" #: widgets/gauge/gauge.py:33 msgid "Creates a vertical gauge." msgstr "" #: widgets/gauge/gauge.py:34 msgid "Under Windows 95, creates a horizontal progress bar." msgstr "" #: widgets/gauge/gauge.py:35 msgid "" "Creates smooth progress bar with one pixel wide update step (not supported " "by all platforms)." msgstr "" #: widgets/gauge/gauge.py:91 widgets/slider/slider.py:131 msgid "Select style" msgstr "" #: widgets/grid/grid.py:199 msgid "" "The following properties are meaningful\n" "only if 'Create grid' is selected" msgstr "" #: widgets/grid/grid.py:220 widgets/notebook/notebook.py:224 #: widgets/radio_button/radio_button.py:74 widgets/slider/slider.py:84 #: widgets/static_text/static_text.py:65 widgets/text_ctrl/text_ctrl.py:76 #: widgets/tree_ctrl/tree_ctrl.py:105 msgid "Widget" msgstr "" #: widgets/list_box/list_box.py:46 msgid "Single-selection list." msgstr "" #: widgets/list_box/list_box.py:47 msgid "Multiple-selection list: the user can toggle multiple items on and off." msgstr "" #: widgets/list_box/list_box.py:48 msgid "" "Extended-selection list: the user can select multiple items using the SHIFT " "key and the mouse or special key combinations." msgstr "" #: widgets/list_box/list_box.py:49 msgid "Create horizontal scrollbar if contents are too wide (Windows only)." msgstr "" #: widgets/list_box/list_box.py:50 msgid "Always show a vertical scrollbar." msgstr "" #: widgets/list_box/list_box.py:51 msgid "Only create a vertical scrollbar if needed." msgstr "" #: widgets/list_box/list_box.py:52 msgid "The listbox contents are sorted in alphabetical order." msgstr "" #: widgets/list_ctrl/list_ctrl.py:71 msgid "" "Multicolumn list view, with optional small icons. Columns are computed " "automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, " "the list wraps, unlike a wxListBox." msgstr "" #: widgets/list_ctrl/list_ctrl.py:72 msgid "Single or multicolumn report view, with optional header." msgstr "" #: widgets/list_ctrl/list_ctrl.py:73 msgid "Large icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:74 msgid "" "The application provides items text on demand. May only be used with " "wxLC_REPORT." msgstr "" #: widgets/list_ctrl/list_ctrl.py:75 msgid "Small icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:76 msgid "Icons align to the top. Win32 default, Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:77 msgid "Icons align to the left." msgstr "" #: widgets/list_ctrl/list_ctrl.py:78 msgid "Icons arrange themselves. Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:79 msgid "" "Labels are editable: the application will be notified when editing starts." msgstr "" #: widgets/list_ctrl/list_ctrl.py:80 msgid "No header in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:81 msgid "Single selection (default is multiple)." msgstr "" #: widgets/list_ctrl/list_ctrl.py:82 msgid "" "Sort in ascending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:83 msgid "" "Sort in descending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:84 msgid "Draws light horizontal rules between rows in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:85 msgid "Draws light vertical rules between columns in report mode" msgstr "" #: widgets/list_ctrl/list_ctrl.py:86 msgid "" "Displays a thin border around the window. wxBORDER is the old name for this " "style." msgstr "" #: widgets/list_ctrl/list_ctrl.py:87 msgid "Displays a double border. Windows and Mac only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:88 msgid "Displays a sunken border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:89 msgid "Displays a raised border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:90 msgid "Displays a border suitable for a static control. Windows only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:91 msgid "Displays no border, overriding the default border style for the window." msgstr "" #: widgets/list_ctrl/list_ctrl.py:92 msgid "" "Use this to indicate that the window wants to get all char/key events for " "all keys - even for keys like TAB or ENTER which are usually used for dialog " "navigation and which wouldn't be generated without this style. If you need " "to use this style in order to get the arrows or etc., but would still like " "to have normal keyboard navigation take place, you should create and send a " "wxNavigationKeyEvent in response to the key events for Tab and Shift-Tab." msgstr "" #: widgets/list_ctrl/list_ctrl.py:93 msgid "" "On Windows, this style used to disable repainting the window completely when " "its size is changed. Since this behaviour is now the default, the style is " "now obsolete and no longer has an effect." msgstr "" #: widgets/list_ctrl/list_ctrl.py:94 msgid "" "Use this style to force a complete redraw of the window whenever it is " "resized instead of redrawing just the part of the window affected by " "resizing. Note that this was the behaviour by default before 2.5.1 release " "and that if you experience redraw problems with code which previously used " "to work you may want to try this. Currently this style applies on GTK+ 2 and " "Windows only, and full repainting is always done on other platforms." msgstr "" #: widgets/menubar/menubar.py:18 msgid "Menu editor" msgstr "" #: widgets/menubar/menubar.py:24 msgid "Menu item:" msgstr "" #: widgets/menubar/menubar.py:32 msgid "Label" msgstr "" #: widgets/menubar/menubar.py:33 msgid "Id" msgstr "" #: widgets/menubar/menubar.py:34 msgid "Name" msgstr "" #: widgets/menubar/menubar.py:35 msgid "Help String" msgstr "" #: widgets/menubar/menubar.py:36 widgets/menubar/menubar.py:58 msgid "Type" msgstr "" #: widgets/menubar/menubar.py:38 msgid "Event Handler" msgstr "" #: widgets/menubar/menubar.py:61 msgid "Add" msgstr "" #: widgets/menubar/menubar.py:62 msgid "Remove" msgstr "" #: widgets/menubar/menubar.py:63 msgid "Add separator" msgstr "" #: widgets/menubar/menubar.py:66 msgid "Up" msgstr "" #: widgets/menubar/menubar.py:67 msgid "Down" msgstr "" #: widgets/menubar/menubar.py:72 msgid "Apply" msgstr "" #: widgets/menubar/menubar.py:120 msgid "Id " msgstr "" #: widgets/menubar/menubar.py:122 msgid "Label " msgstr "" #: widgets/menubar/menubar.py:124 msgid "Name " msgstr "" #: widgets/menubar/menubar.py:126 msgid "Help String " msgstr "" #: widgets/menubar/menubar.py:128 msgid "Event Handler " msgstr "" #: widgets/menubar/menubar.py:506 msgid "Edit menus..." msgstr "" #: widgets/menubar/menubar.py:766 msgid "Select menubar class" msgstr "" #: widgets/notebook/notebook.py:331 msgid "Select tab placement" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Top" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Bottom" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Left" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Right" msgstr "" #: widgets/radio_button/radio_button.py:37 msgid "Clicked" msgstr "" #: widgets/radio_button/radio_button.py:42 msgid "Marks the beginning of a new group of radio buttons." msgstr "" #: widgets/radio_button/radio_button.py:43 msgid "" "In some circumstances, radio buttons that are not consecutive siblings " "trigger a hang bug in Windows (only). If this happens, add this style to " "mark the button as not belonging to a group, and implement the mutually-" "exclusive group behaviour yourself." msgstr "" #: widgets/radio_button/radio_button.py:44 msgid "" "Use a checkbox button instead of radio button (currently supported only on " "PalmOS)." msgstr "" #: widgets/slider/slider.py:52 msgid "Displays the slider horizontally (this is the default)." msgstr "" #: widgets/slider/slider.py:53 msgid "Displays the slider vertically." msgstr "" #: widgets/slider/slider.py:54 msgid "Displays tick marks." msgstr "" #: widgets/slider/slider.py:55 msgid "Displays minimum, maximum and value labels." msgstr "" #: widgets/slider/slider.py:56 msgid "Displays ticks on the left and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:57 msgid "Displays ticks on the right and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:58 msgid "Displays ticks on the top." msgstr "" #: widgets/slider/slider.py:59 msgid "Displays ticks on the bottom (this is the default)." msgstr "" #: widgets/slider/slider.py:60 msgid "Allows the user to select a range on the slider. Windows only." msgstr "" #: widgets/slider/slider.py:61 msgid "" "Inverses the mininum and maximum endpoints on the slider. Not compatible " "with wxSL_SELRANGE." msgstr "" #: widgets/static_text/static_text.py:42 msgid "Store as attribute" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:79 msgid " Tree Control:" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:82 #, python-format msgid " on wxGlade %s" msgstr "" spe-0.8.4.h/_spe/plugins/wxGlade/po/ko.po0000644000175000017500000004561410743421035017160 0ustar stanistani# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: wxglade\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-02-09 23:22+0100\n" "PO-Revision-Date: 2007-11-07 18:48+0900\n" "Last-Translator: homin,Lee \n" "Language-Team: Gnome-kr-hackers \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Kannada\n" "X-Poedit-Country: KOREA, REPUBLIC OF\n" #: edit_windows.py:1131 msgid "" "\n" "wxGlade-WARNING: only sizers can be pasted here" msgstr "" "\n" "wxGlade-경고: 이곳에는 sizer만 붙일 수 있습니다." #: edit_windows.py:1122 msgid "" "\n" "wxGlade-WARNING: sizer already set for this window" msgstr "" "\n" "wxGlade-경고: 이 윈도우에 대한 sizer가 이미 설정되어 있습니다." #: widget_properties.py:926 msgid " Add " msgstr " 더하기" #: widget_properties.py:923 msgid " Apply " msgstr " 적용" #: widget_properties.py:930 msgid " Insert " msgstr " 삽입" #: widget_properties.py:934 msgid " Remove " msgstr " 지우기" #: configUI.py:127 msgid " seconds" msgstr " 초" #: common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "\"%s\"은(는) 유효한 코드 생성 모듈이 아닙니다" #: templates_ui.py:87 msgid "&Edit" msgstr "편집(&E)" #: main.py:207 msgid "&File" msgstr "파일(&F)" #: main.py:190 msgid "&Generate Code\tCtrl+G" msgstr "코드 생성하기(&G)\tCtrl+G" #: main.py:213 #: main.py:220 msgid "&Help" msgstr "도움말(&H)" #: main.py:195 msgid "&Import from XRC...\tCtrl+I" msgstr "XRC로 부터 가져오기(&I)...\tCtrl+I" #: main.py:173 msgid "&New\tCtrl+N" msgstr "새로 만들기(&N)\tCtrl+N" #: main.py:178 msgid "&Open...\tCtrl+O" msgstr "열기(&O)...\tCtrl+O" #: main.py:171 msgid "&Raise All\tF4" msgstr "모두 끌어 올리기(&R)\tF4" #: main.py:188 msgid "&Refresh\tf5" msgstr "새로고침(&R)\tf5" #: main.py:180 msgid "&Save\tCtrl+S" msgstr "저장(&S)\tCtrl+S" #: main.py:208 msgid "&View" msgstr "보기(&V)" #: edit_widget.py:111 msgid "'name' attribute missing" msgstr "'name' 속성 실종됨" #: configUI.py:53 msgid "..." msgstr "..." #: misc.py:450 msgid " - " msgstr " - " #: template.py:205 #, python-format msgid "" "A template called '%s' already exists:\n" "do you want to overwrite it?" msgstr "" "'%s'(이)라는 템플릿이 이미 존재합니다:\n" "정말로 덮어쓰기를 원하시나요?" #: about.py:49 msgid "About wxGlade" msgstr "wxGlade 정보 " #: main.py:212 msgid "About..." msgstr "정보..." #: common.py:214 #, python-format msgid "Add a %s" msgstr "%s 더하기(add)" #: main.py:601 msgid "Alert" msgstr "경고" #: widget_properties.py:643 msgid "All Files|*" msgstr "모든 파일|*" #: configUI.py:44 msgid "Allow duplicate widget names" msgstr "위젯이름의 중복을 허용" #: main.py:881 #, python-format msgid "" "An exception occurred while importing file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"파일을 가져오는 도중 예외가 발생하였습니다.\n" "이것이 예외의 에러 메세지 입니다.:\n" " %s\n" "더 자세한 내요은 콘솔에서 full traceback을 살펴보십시오.\n" "만약 이것이 wxGlade의 버그로 판단되면 레포트 해주시면 감사하겠습니다." #: main.py:685 #, python-format msgid "" "An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"파일을 읽어오는 도중 예외가 발생하였습니다.\n" "이것이 예외의 에러 메세지 입니다.:\n" " %s\n" "더 자세한 내요은 콘솔에서 full traceback을 살펴보십시오.\n" "만약 이것이 wxGlade의 버그로 판단되면 레포트 해주시면 감사하겠습니다." #: main.py:759 #, python-format msgid "" "An exception occurred while saving file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" "\"%s\"파일을 저장하는 도중 예외가 발생하였습니다.\n" "이것이 예외의 에러 메세지 입니다.:\n" " %s\n" "더 자세한 내요은 콘솔에서 full traceback을 살펴보십시오.\n" "만약 이것이 wxGlade의 버그로 판단되면 레포트 해주시면 감사하겠습니다." #: tree.py:280 msgid "Application" msgstr "Application" #: template.py:126 msgid "Are you sure?" msgstr "정말 입니까?" #: templates_ui.py:24 #: templates_ui.py:77 msgid "Author" msgstr "작성자" #: main.py:240 #: main.py:508 #: main.py:627 msgid "Auto save detected" msgstr "자동 저장 발견됨" #: configUI.py:47 msgid "Auto save wxg files every " msgstr "다음마다 wxg 파일들을 자동으로 저장" #: main.py:521 msgid "Auto saving... done" msgstr "자동 저장... 완료" #: templates_ui.py:80 msgid "Available templates" msgstr "사용가능한 템플릿" #: configUI.py:51 msgid "Backup options" msgstr "백업 옵션" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "크레딧 파일을 찾을 수 없습니다!\n" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" "라이센스를 찾을 수 없습니다!\n" "아래의 위치에서 복사본을 얻을 수 있습니다. \n" "http://www.opensource.org/licenses/mit-license.php" #: template.py:191 msgid "Can't save a template with an empty name" msgstr "이름 없이 템플릿을 저장할 수 없습니다" #: color_dialog.py:27 msgid "Cancel" msgstr "취소" #: config.py:279 msgid "Changes will take effect after wxGlade is restarted" msgstr "바뀐 내용은 wxGlade가 다시 시작될때 적용될 것 입니다" #: config.py:128 msgid "Choose a directory:" msgstr "디렉토리 선택:" #: widget_properties.py:644 msgid "Choose a file" msgstr "파일을 선택하세요" #: clipboard.py:69 #: clipboard.py:103 msgid "Clipboard can't be opened." msgstr "클립보드를 열 수 없습니다." #: edit_windows.py:1032 msgid "Close Preview" msgstr "미리보기 닫기" #: edit_windows.py:231 msgid "Close preview" msgstr "미리보기 닫기" #: edit_windows.py:547 msgid "Common" msgstr "일반" #: main.py:566 msgid "Confirm" msgstr "확인" #: main.py:210 msgid "Contents\tF1" msgstr "내용\tF1" #: edit_windows.py:205 msgid "Copy\tCtrl+C" msgstr "복사\tCtrl+C" #: main.py:300 msgid "Core components" msgstr "핵심 컴포넌트들 " #: configUI.py:43 msgid "Create backup files for generated source" msgstr "생성된 소스의 백업본을 만들기" #: configUI.py:42 msgid "Create backup wxg files" msgstr "wxg파일의 백업본을 만들기" #: color_dialog.py:23 msgid "Custom colour" msgstr "사용자 컬러" #: main.py:300 msgid "Custom components" msgstr "사용자 컴포넌트들" #: edit_windows.py:207 msgid "Cut\tCtrl+X" msgstr "잘라내기\tCtrl+X" #: clipboard.py:96 msgid "Data can't be copied from clipboard." msgstr "데이터를 클립보드에서 복사할 수 없습니다." #: clipboard.py:63 msgid "Data can't be copied to clipboard." msgstr "데이터를 클립보드에 복사할 수 없습니다." #: configUI.py:45 msgid "Default border width for widgets" msgstr "위젯들의 기본 테두리 넓이" #: template.py:125 #, python-format msgid "Delete template '%s'?" msgstr "'%s' 템플릿을 지울까요?" #: templates_ui.py:22 #: templates_ui.py:78 msgid "Description" msgstr "설명" #: main.py:199 msgid "E&xit\tCtrl+Q" msgstr "나가기(&X)\tCtrl+Q" #: common.py:148 #, python-format msgid "ERROR loading \"%s\"" msgstr "\"%s\" 로딩 실패" #: main.py:673 #: main.py:693 #: main.py:753 #: main.py:766 #: main.py:821 #: main.py:887 #: about.py:67 #: template.py:192 #: edit_windows.py:173 msgid "Error" msgstr "에러" #: main.py:671 #, python-format msgid "Error loading file %s: %s" msgstr "%s 파일 불러오기 에러: %s" #: config.py:66 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" "설정파일 읽기 실패:\n" "%s" #: main.py:753 #, python-format msgid "" "Error saving app:\n" "%s" msgstr "" "app 저장 에러:\n" "%s" #: main.py:820 #, python-format msgid "" "Error saving preferences:\n" "%s" msgstr "" "설정 저장 에러:\n" "%s" #: wxglade.py:80 #, python-format msgid "Error: %s" msgstr "에러: %s" #: wxglade.py:77 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "에러: \"%s\"언어에 대한 사용가능한 작성기가 없습니다" #: events_mixin.py:22 msgid "Event" msgstr "이벤트" #: code_property.py:90 msgid "Extra properties for this widget" msgstr "이 위젯에 대한 추가 설정" #: font_dialog.py:30 msgid "Family:" msgstr "종류(Family):" #: kdefiledialog.py:77 #, python-format msgid "File '%s' already exists: do you really want to overwrite it?" msgstr "'%s' 파일이 이미 존재합니다: 정말로 덮어쓰기를 원하시나요?" #: kdefiledialog.py:86 #: kdefiledialog.py:127 msgid "Fork Error" msgstr "분기(Fork) 에러" #: common.py:129 #, python-format msgid "Found widgets listing -> %s" msgstr "검색된 위젯들을 리스팅 -> %s" #: application.py:161 msgid "Generate code" msgstr "코드 생성" #: events_mixin.py:23 msgid "Handler" msgstr "핸들러" #: edit_windows.py:1102 msgid "Hide" msgstr "숨기기" #: edit_windows.py:57 msgid "If you change the default value, it will be interpreted as the name of the subclass of the widget. How this name affects code generation depends on the kind (i.e. language) of output. See the docs for more details." msgstr "만약 기본 값을 바꾼다면, 그것은 위젯의 서브클래스 이름으로 해석될 것입니다. 이 이름이 코드 생성에 어떻게 영향을 미치는 지는 출력 종류(예. 언어)에 따라 다릅니다. 자세한 내용은 문서를 참조하세요." #: main.py:867 msgid "Import file" msgstr "파일 가져오기" #: main.py:600 msgid "Impossible to reload an unsaved application" msgstr "저장하지 않은 application을 다시 읽어오는 것은 불가능합니다" #: main.py:898 msgid "Information" msgstr "정보" #: configUI.py:106 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" "코드 생성 파일 다이얼로그의 \n" "초기 경로:" #: configUI.py:103 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" "파일 열기/저장 다이얼로그의 \n" "초기 경로:" #: configUI.py:50 msgid "Insert .wxg file name on generated source files" msgstr "만들어진 소스 파일에 .wxg 파일 이름을 추가하기" #: configUI.py:49 msgid "Insert timestamp on generated source files" msgstr "만들어진 소스 파일에 타임스탬프를 추가하기" #: templates_ui.py:23 #: templates_ui.py:79 msgid "Instructions" msgstr "사용 설명" #: configUI.py:137 msgid "Interface" msgstr "인터페이스" #: clipboard.py:38 msgid "Invalid data in the clipboard" msgstr "유효하지 않은 데이터가 클립보드에 있습니다" #: main.py:726 #, python-format msgid "Loaded %s (%.2f seconds)" msgstr "%s 불러옴 (%.2f 초)" #: main.py:709 msgid "Loaded template" msgstr "템플릿 불러옴" #: main.py:714 #, python-format msgid "Loading time: %.5f" msgstr "불러오는중 시간: %.5f" #: xml_parse.py:255 msgid "Loading..." msgstr "불러오는중..." #: configUI.py:29 msgid "Local widget path" msgstr "로컬 위젯 경로" #: edit_windows.py:172 #, python-format msgid "" "Name \"%s\" is already in use.\n" "Please enter a different one." msgstr "" "\"%s\"(이)라는 이름이 이미 사용중입니다.\n" "다른 이름을 입력하세요." #: main.py:176 msgid "New from &Template...\tShift+Ctrl+N" msgstr "템플릿으로 부터 새로 만들기(&T)...\tShift+Ctrl+N" #: configUI.py:112 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" "메인 팔렛트에서\n" "한줄당 단추의 개수" #: configUI.py:109 msgid "Number of items in file history" msgstr "열었던 파일 기록의 갯수" #: color_dialog.py:26 msgid "OK" msgstr "확인" #: about.py:80 msgid "Oops!" msgstr "이런!" #: main.py:616 msgid "Open file" msgstr "파일 열기" #: configUI.py:138 msgid "Other" msgstr "기타" #: edit_windows.py:1109 msgid "Paste\tCtrl+V" msgstr "붙이기\tCtrl+V" #: clipboard.py:131 msgid "Please only drop one file at a time" msgstr "한번에 하나의 파일을 드롭해 주세요" #: xml_parse.py:255 msgid "Please wait while loading the app" msgstr "app를 불러오는 중입니다. 잠시만 기다려주세요." #: layout_option_property.py:62 #: layout_option_property.py:64 msgid "Position" msgstr "위치" #: config.py:280 msgid "Preferences saved" msgstr "참조 저장됨" #: main.py:205 msgid "Preferences..." msgstr "기본 설정..." #: edit_windows.py:211 #: edit_windows.py:233 #: edit_windows.py:1018 #: edit_windows.py:1114 msgid "Preview" msgstr "미리보기" #: edit_windows.py:185 #: edit_windows.py:313 #, python-format msgid "Properties - <%s>" msgstr "속성들 - <%s>" #: tree.py:36 msgid "Properties - <>" msgstr "설정 - <>" #: main.py:375 msgid "Properties - " msgstr "속성 - " #: code_property.py:88 msgid "Property" msgstr "설정" #: template.py:206 msgid "Question" msgstr "질문" #: main.py:514 msgid "Recovery from auto save complete" msgstr "자동 저장으로부터 복구 완료" #: configUI.py:34 msgid "Remember position and size of wxGlade windows" msgstr "wxGlade 윈도우들의 위치와 크기 기억" #: edit_windows.py:203 #: edit_windows.py:1100 msgid "Remove\tDel" msgstr "삭제\tDel" #: main.py:185 msgid "Save As Template..." msgstr "템플릿으로 저장하기..." #: main.py:182 msgid "Save As...\tShift+Ctrl+S" msgstr "다른이름으로 저장...\tShift+Ctrl+S" #: main.py:565 msgid "Save changes to the current app?" msgstr "현재 app에 바뀐 내용을 저장 할까요?" #: main.py:781 msgid "Save project as..." msgstr "프로젝트를 다른이름으로 저장..." #: main.py:775 #, python-format msgid "Saved %s" msgstr "%s 저장됨" #: font_dialog.py:97 msgid "Select font attributes" msgstr "글꼴 속성 선택" #: color_dialog.py:71 msgid "Select widget colour" msgstr "위젯 컬러 선택" #: tree.py:293 msgid "Show" msgstr "보이기" #: configUI.py:35 msgid "Show \"handles\" of sizers" msgstr "사이저의 \"핸들\"을 보여줌" #: main.py:170 msgid "Show &Properties\tF3" msgstr "속성 보이기(&P)\tF3" #: main.py:167 msgid "Show &Tree\tF2" msgstr "트리 보이기(&T)\tF2" #: configUI.py:33 msgid "Show progress dialog when loading wxg files" msgstr "wxg파일을 읽을 때 프로그래스 바를 보여주기" #: configUI.py:32 msgid "Show properties and tree windows as small frames" msgstr "설정창과 트리창을 작은 프레임으로 보여주기" #: layout_option_property.py:72 #: layout_option_property.py:74 msgid "Span" msgstr "폭(Span)" #: font_dialog.py:31 msgid "Style:" msgstr "스타일:" #: color_dialog.py:19 msgid "System colour" msgstr "시스템 컬러" #: main.py:203 msgid "Templates Manager..." msgstr "템플릿 관리기..." #: main.py:238 #: main.py:625 msgid "There seems to be auto saved data for this file: do you want to restore it?" msgstr "이 파일에 대한 자동 저장 내용이 있습니다: 이 내용을 복구 할까요?" #: main.py:505 msgid "There seems to be auto saved data from last wxGlade session: do you want to restore it?" msgstr "지난 wxGlade 세션의 자동 저장된 데이타가 있습니다: 이 내용을 복구 할까요?" #: main.py:896 msgid "" "To save the changes to the template, edit the GUI as usual,\n" "and then click File->Save as Template..." msgstr "" "바뀐 내용을 템플릿에 저장하기 위해서는 평소처럼 GUI를 편집하고,\n" "파일->템플릿으로 저장하기... 를 선택하세요" #: configUI.py:41 msgid "Use dialog units by default for size properties" msgstr "기본 크기 속성으로 다이얼로그 단위를 사용" #: configUI.py:31 msgid "Use icons in menu items" msgstr "메뉴 아이템에 아이콘 사용" #: configUI.py:36 msgid "Use native file dialogs on KDE" msgstr "KDE에서 고유의 파일 다이얼로그를 사용" #: wxglade.py:101 msgid "Valid LANGUAGE values:" msgstr "유요한 언어(LANGUAGE) 값들:" #: code_property.py:89 msgid "Value" msgstr "값" #: font_dialog.py:32 msgid "Weight:" msgstr "너비:" #: configUI.py:51 msgid "append .bak to filename" msgstr "파일 이름의 뒤에 .bak를 붙임" #: configUI.py:51 msgid "append ~ to filename" msgstr "파일 이름의 뒤에 ~를 붙임" #: widget_properties.py:768 #, python-format msgid "error in the value of the property \"%s\"" msgstr "\"%s\"속성 값 에러" #: common.py:98 #, python-format msgid "loaded code generator for %s" msgstr "%s을(를) 위한 코드 생성기가 로드됨" #: common.py:130 msgid "loading widget modules:" msgstr "위젯 모듈을 로드중:" #: about.py:59 msgid "wxGlade - License" msgstr "wxGlade - 라이센스" #: msgdialog.py:17 #: msgdialog.py:28 msgid "wxGlade message" msgstr "wxGlade 메세지" #: templates_ui.py:38 msgid "wxGlade template information" msgstr "wxGlade 템플릿 정보" #: templates_ui.py:103 msgid "wxGlade template list" msgstr "wxGlade 템플릿 리스트" #: template.py:115 #: templates_ui.py:82 msgid "wxGlade template:\n" msgstr "wxGalde 템플릿:\n" #: templates_ui.py:50 msgid "wxGlade template: " msgstr "wxGlade 템플릿:" #: wxglade.py:90 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" "wxGlade 사용법\n" "- GUI로 시작하려면: python wxglade.py [WXG_FILE]\n" "- 커맨드라인에서 코드를 만들려면: python wxglade.py OPTIONS... FILE\n" " OPTIONS 들은 아래와 같습니다.:\n" " -g, --generate-code=LANGUAGE (필수) 출력 언어\n" " -o, --output=PATH (선택) 출력 파일의 이름 (\n" " 단일-파일 모드인 경우) 혹은 디렉토리 (\n" " 여러-파일 모드인 경우)\n" " " #: main.py:408 msgid "wxGlade: Tree" msgstr "wxGlade: 트리" #: tree.py:463 #, python-format msgid "wxGlade: Tree %s" msgstr "wxGlade: 트리 %s" #: configUI.py:63 msgid "wxGlade: preferences" msgstr "wxGlade: 설정" spe-0.8.4.h/_spe/plugins/wxGlade/po/en.po0000644000175000017500000001111210743421035017133 0ustar stanistani# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-01-27 15:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: about.py:49 msgid "About wxGlade" msgstr "" #: about.py:59 msgid "wxGlade - License" msgstr "" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" #: about.py:67 msgid "Error" msgstr "" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "" #: about.py:80 msgid "Oops!" msgstr "" #: clipboard.py:40 msgid "Invalid data in the clipboard" msgstr "" #: clipboard.py:65 msgid "Data can't be copied to clipboard." msgstr "" #: clipboard.py:71 clipboard.py:105 msgid "Clipboard can't be opened." msgstr "" #: clipboard.py:98 msgid "Data can't be copied from clipboard." msgstr "" #: clipboard.py:129 msgid "Please only drop one file at a time" msgstr "" #: color_dialog.py:18 msgid "System colour" msgstr "" #: color_dialog.py:22 msgid "Custom colour" msgstr "" #: color_dialog.py:25 configUI.py:38 msgid "OK" msgstr "" #: color_dialog.py:26 configUI.py:39 msgid "Cancel" msgstr "" #: color_dialog.py:70 msgid "Select widget colour" msgstr "" #: common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "" #: common.py:96 #, python-format msgid "loaded code generator for %s" msgstr "" #: common.py:127 #, python-format msgid "Found widgets listing -> %s" msgstr "" #: common.py:128 msgid "loading widget modules:" msgstr "" #: common.py:137 #, python-format msgid "ERROR loading \"%s\"" msgstr "" #: common.py:203 #, python-format msgid "Add a %s" msgstr "" #: config.py:60 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" #: config.py:103 msgid "Choose a directory:" msgstr "" #: config.py:246 msgid "Changes will take effect after wxGlade is restarted" msgstr "" #: config.py:247 msgid "Preferences saved" msgstr "" #: configUI.py:15 msgid "Local widget path" msgstr "" #: configUI.py:17 msgid "Use icons in menu items" msgstr "" #: configUI.py:18 msgid "Show properties and tree windows as small frames (Win32 only)" msgstr "" #: configUI.py:19 msgid "Show progress dialog when loading wxg files" msgstr "" #: configUI.py:20 msgid "Remember position and size of wxGlade windows" msgstr "" #: configUI.py:21 msgid "Show \"handles\" of sizers" msgstr "" #: configUI.py:22 msgid "Use native file dialogs on KDE" msgstr "" #: configUI.py:27 msgid "Use dialog units by default for size properties" msgstr "" #: configUI.py:28 msgid "Create backup wxg files" msgstr "" #: configUI.py:29 msgid "Create backup files for generated source" msgstr "" #: configUI.py:30 msgid "Allow duplicate widget names" msgstr "" #: configUI.py:31 msgid "Default border width for widgets" msgstr "" #: configUI.py:33 msgid "Auto save wxg files every " msgstr "" #: configUI.py:35 msgid "Backup options" msgstr "" #: configUI.py:35 msgid "append ~ to filename" msgstr "" #: configUI.py:35 msgid "append .bak to filename" msgstr "" #: configUI.py:47 msgid "wxGlade: preferences" msgstr "" #: configUI.py:83 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" #: configUI.py:86 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" #: configUI.py:90 msgid "Number of items in file history" msgstr "" #: configUI.py:93 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" #: configUI.py:122 msgid "Interface" msgstr "" #: configUI.py:123 msgid "Other" msgstr "" #: wxglade.py:76 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "" #: wxglade.py:80 #, python-format msgid "Error: %s" msgstr "" #: wxglade.py:90 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" #: wxglade.py:101 msgid "Valid LANGUAGE values:" msgstr "" spe-0.8.4.h/_spe/plugins/wxGlade/po/messages.pot0000644000175000017500000005473010743421035020541 0ustar stanistani# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-02-09 23:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: about.py:49 msgid "About wxGlade" msgstr "" #: about.py:59 msgid "wxGlade - License" msgstr "" #: about.py:64 msgid "" "Can't find the license!\n" "You can get a copy at \n" "http://www.opensource.org/licenses/mit-license.php" msgstr "" #: about.py:67 edit_windows.py:149 main.py:620 main.py:637 main.py:692 #: main.py:705 main.py:753 main.py:815 zmain.py:482 zmain.py:499 zmain.py:538 #: zmain.py:551 zmain.py:587 edit_sizers/edit_sizers.py:651 msgid "Error" msgstr "" #: about.py:80 msgid "Can't find the credits file!\n" msgstr "" #: about.py:80 msgid "Oops!" msgstr "" #: clipboard.py:40 clipboard.py:38 msgid "Invalid data in the clipboard" msgstr "" #: clipboard.py:65 clipboard.py:63 msgid "Data can't be copied to clipboard." msgstr "" #: clipboard.py:71 clipboard.py:105 clipboard.py:69 clipboard.py:103 msgid "Clipboard can't be opened." msgstr "" #: clipboard.py:98 clipboard.py:96 msgid "Data can't be copied from clipboard." msgstr "" #: clipboard.py:129 clipboard.py:127 msgid "Please only drop one file at a time" msgstr "" #: color_dialog.py:18 color_dialog.py:19 msgid "System colour" msgstr "" #: color_dialog.py:22 color_dialog.py:23 msgid "Custom colour" msgstr "" #: color_dialog.py:25 configUI.py:38 color_dialog.py:26 #: edit_sizers/edit_sizers.py:395 edit_sizers/edit_sizers.py:1808 #: edit_sizers/edit_sizers.py:2026 edit_sizers/edit_sizers.py:2122 #: widgets/gauge/gauge.py:104 widgets/menubar/menubar.py:71 #: widgets/menubar/menubar.py:777 widgets/notebook/notebook.py:339 msgid "OK" msgstr "" #: color_dialog.py:26 configUI.py:39 color_dialog.py:27 #: edit_sizers/edit_sizers.py:396 edit_sizers/edit_sizers.py:1809 #: widgets/menubar/menubar.py:73 widgets/menubar/menubar.py:778 msgid "Cancel" msgstr "" #: color_dialog.py:70 color_dialog.py:71 msgid "Select widget colour" msgstr "" #: common.py:92 #, python-format msgid "\"%s\" is not a valid code generator module" msgstr "" #: common.py:96 #, python-format msgid "loaded code generator for %s" msgstr "" #: common.py:127 #, python-format msgid "Found widgets listing -> %s" msgstr "" #: common.py:128 msgid "loading widget modules:" msgstr "" #: common.py:137 #, python-format msgid "ERROR loading \"%s\"" msgstr "" #: common.py:203 #, python-format msgid "Add a %s" msgstr "" #: config.py:60 #, python-format msgid "" "Error reading config file:\n" "%s" msgstr "" #: config.py:103 msgid "Choose a directory:" msgstr "" #: config.py:246 msgid "Changes will take effect after wxGlade is restarted" msgstr "" #: config.py:247 msgid "Preferences saved" msgstr "" #: configUI.py:15 msgid "Local widget path" msgstr "" #: configUI.py:17 msgid "Use icons in menu items" msgstr "" #: configUI.py:18 msgid "Show properties and tree windows as small frames (Win32 only)" msgstr "" #: configUI.py:19 msgid "Show progress dialog when loading wxg files" msgstr "" #: configUI.py:20 msgid "Remember position and size of wxGlade windows" msgstr "" #: configUI.py:21 msgid "Show \"handles\" of sizers" msgstr "" #: configUI.py:22 msgid "Use native file dialogs on KDE" msgstr "" #: configUI.py:27 msgid "Use dialog units by default for size properties" msgstr "" #: configUI.py:28 msgid "Create backup wxg files" msgstr "" #: configUI.py:29 msgid "Create backup files for generated source" msgstr "" #: configUI.py:30 msgid "Allow duplicate widget names" msgstr "" #: configUI.py:31 msgid "Default border width for widgets" msgstr "" #: configUI.py:33 msgid "Auto save wxg files every " msgstr "" #: configUI.py:35 msgid "Backup options" msgstr "" #: configUI.py:35 msgid "append ~ to filename" msgstr "" #: configUI.py:35 msgid "append .bak to filename" msgstr "" #: configUI.py:47 msgid "wxGlade: preferences" msgstr "" #: configUI.py:83 msgid "" "Initial path for \n" "file opening/saving dialogs:" msgstr "" #: configUI.py:86 msgid "" "Initial path for \n" "code generation file dialogs:" msgstr "" #: configUI.py:90 msgid "Number of items in file history" msgstr "" #: configUI.py:93 msgid "" "Number of buttons per row\n" "in the main palette" msgstr "" #: configUI.py:122 msgid "Interface" msgstr "" #: configUI.py:123 msgid "Other" msgstr "" #: wxglade.py:76 wxglade.py:78 #, python-format msgid "Error: no writer for language \"%s\" available" msgstr "" #: wxglade.py:80 wxglade.py:82 #, python-format msgid "Error: %s" msgstr "" #: wxglade.py:90 wxglade.py:92 msgid "" "wxGlade usage:\n" "- to start the GUI: python wxglade.py [WXG_FILE]\n" "- to generate code from the command line: python wxglade.py OPTIONS... FILE\n" " OPTIONS are the following:\n" " -g, --generate-code=LANGUAGE (required) give the output language\n" " -o, --output=PATH (optional) name of the output file (in\n" " single-file mode) or directory (in\n" " multi-file mode)\n" " " msgstr "" #: wxglade.py:101 wxglade.py:103 msgid "Valid LANGUAGE values:" msgstr "" #: edit_widget.py:103 msgid "'name' attribute missing" msgstr "" #: edit_windows.py:57 msgid "" "If you change the default value, it will be interpreted as the name of the " "subclass of the widget. How this name affects code generation depends on the " "kind (i.e. language) of output. See the docs for more details." msgstr "" #: edit_windows.py:148 edit_sizers/edit_sizers.py:650 #, python-format msgid "" "Name \"%s\" is already in use.\n" "Please enter a different one." msgstr "" #: edit_windows.py:161 edit_windows.py:261 edit_sizers/edit_sizers.py:664 #: edit_sizers/edit_sizers.py:706 #, python-format msgid "Properties - <%s>" msgstr "" #: edit_windows.py:179 edit_windows.py:1024 edit_sizers/edit_sizers.py:87 #: edit_sizers/edit_sizers.py:215 widgets/menubar/menubar.py:666 msgid "Remove\tDel" msgstr "" #: edit_windows.py:181 edit_sizers/edit_sizers.py:498 msgid "Copy\tCtrl+C" msgstr "" #: edit_windows.py:183 edit_sizers/edit_sizers.py:499 msgid "Cut\tCtrl+X" msgstr "" #: edit_windows.py:480 edit_sizers/edit_sizers.py:634 #: widgets/menubar/menubar.py:587 msgid "Common" msgstr "" #: edit_windows.py:946 msgid "Preview" msgstr "" #: edit_windows.py:960 msgid "Close Preview" msgstr "" #: edit_windows.py:1026 widgets/menubar/menubar.py:668 msgid "Hide" msgstr "" #: edit_windows.py:1033 edit_sizers/edit_sizers.py:89 msgid "Paste\tCtrl+V" msgstr "" #: edit_windows.py:1041 msgid "" "\n" "wxGlade-WARNING: sizer already set for this window" msgstr "" #: edit_windows.py:1050 msgid "" "\n" "wxGlade-WARNING: only sizers can be pasted here" msgstr "" #: events_mixin.py:22 msgid "Event" msgstr "" #: events_mixin.py:23 msgid "Handler" msgstr "" #: font_dialog.py:30 msgid "Family:" msgstr "" #: font_dialog.py:31 msgid "Style:" msgstr "" #: font_dialog.py:32 msgid "Weight:" msgstr "" #: font_dialog.py:97 msgid "Select font attributes" msgstr "" #: kdefiledialog.py:69 #, python-format msgid "File '%s' already exists: do you really want to overwrite it?" msgstr "" #: kdefiledialog.py:77 kdefiledialog.py:118 msgid "Fork Error" msgstr "" #: layout_option_property.py:40 layout_option_property.py:42 msgid "Option" msgstr "" #: layout_option_property.py:62 layout_option_property.py:64 msgid "Position" msgstr "" #: layout_option_property.py:72 layout_option_property.py:74 msgid "Span" msgstr "" #: main.py:165 zmain.py:148 msgid "Show &Tree\tCtrl+T" msgstr "" #: main.py:168 zmain.py:151 msgid "Show &Properties\tCtrl+P" msgstr "" #: main.py:172 zmain.py:155 msgid "&New\tCtrl+N" msgstr "" #: main.py:174 zmain.py:157 msgid "&Open...\tCtrl+O" msgstr "" #: main.py:176 zmain.py:159 msgid "&Save\tCtrl+S" msgstr "" #: main.py:178 zmain.py:161 msgid "Save As...\tShift+Ctrl+S" msgstr "" #: main.py:182 msgid "&Refresh\tf5" msgstr "" #: main.py:184 zmain.py:165 msgid "&Generate Code\tCtrl+G" msgstr "" #: main.py:189 msgid "&Import from XRC...\tCtrl+I" msgstr "" #: main.py:193 zmain.py:169 msgid "E&xit\tCtrl+Q" msgstr "" #: main.py:196 zmain.py:172 msgid "Preferences..." msgstr "" #: main.py:197 zmain.py:173 msgid "&File" msgstr "" #: main.py:198 zmain.py:174 msgid "&View" msgstr "" #: main.py:200 zmain.py:176 msgid "Contents\tF1" msgstr "" #: main.py:202 zmain.py:178 msgid "About..." msgstr "" #: main.py:203 main.py:210 zmain.py:179 msgid "&Help" msgstr "" #: main.py:228 main.py:573 msgid "" "There seems to be auto saved data for this file: do you want to restore it?" msgstr "" #: main.py:230 main.py:478 main.py:575 msgid "Auto save detected" msgstr "" #: main.py:274 zmain.py:219 msgid "Core components" msgstr "" #: main.py:274 zmain.py:219 msgid "Custom components" msgstr "" #: main.py:347 zmain.py:292 msgid "Properties - " msgstr "" #: main.py:380 zmain.py:324 msgid "wxGlade: Tree" msgstr "" #: main.py:475 msgid "" "There seems to be auto saved data from last wxGlade session: do you want to " "restore it?" msgstr "" #: main.py:484 msgid "Recovery from auto save complete" msgstr "" #: main.py:491 msgid "Auto saving... done" msgstr "" #: main.py:525 zmain.py:421 msgid "Save changes to the current app?" msgstr "" #: main.py:525 zmain.py:421 msgid "Confirm" msgstr "" #: main.py:549 msgid "Impossible to reload an unsaved application" msgstr "" #: main.py:550 msgid "Alert" msgstr "" #: main.py:565 zmain.py:445 msgid "Open file" msgstr "" #: main.py:619 zmain.py:481 #, python-format msgid "Error loading file %s: %s" msgstr "" #: main.py:632 zmain.py:494 #, python-format msgid "" "An exception occurred while loading file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:653 msgid "Loaded template" msgstr "" #: main.py:657 #, python-format msgid "Loading time: %.5f" msgstr "" #: main.py:669 #, python-format msgid "Loaded %s (%.2f seconds)" msgstr "" #: main.py:692 zmain.py:538 #, python-format msgid "" "Error saving app:\n" "%s" msgstr "" #: main.py:698 zmain.py:544 #, python-format msgid "" "An exception occurred while saving file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: main.py:714 #, python-format msgid "Saved %s" msgstr "" #: main.py:720 zmain.py:560 msgid "Save project as..." msgstr "" #: main.py:752 zmain.py:587 #, python-format msgid "" "Error saving preferences:\n" "%s" msgstr "" #: main.py:797 msgid "Import file" msgstr "" #: main.py:810 #, python-format msgid "" "An exception occurred while importing file \"%s\".\n" "This is the error message associated with it:\n" " %s\n" "For more details, look at the full traceback on the console.\n" "If you think this is a wxGlade bug, please report it." msgstr "" #: misc.py:404 msgid " - " msgstr "" #: tree.py:32 msgid "Properties - <>" msgstr "" #: tree.py:267 msgid "Application" msgstr "" #: tree.py:280 msgid "Show" msgstr "" #: tree.py:448 #, python-format msgid "wxGlade: Tree %s" msgstr "" #: widget_properties.py:641 msgid "All Files|*" msgstr "" #: widget_properties.py:642 msgid "Choose a file" msgstr "" #: widget_properties.py:765 #, python-format msgid "error in the value of the property \"%s\"" msgstr "" #: widget_properties.py:918 msgid " Apply " msgstr "" #: widget_properties.py:921 msgid " Add " msgstr "" #: widget_properties.py:924 msgid " Insert " msgstr "" #: widget_properties.py:927 msgid " Remove " msgstr "" #: xml_parse.py:253 msgid "Loading..." msgstr "" #: xml_parse.py:253 msgid "Please wait while loading the app" msgstr "" #: zmain.py:445 zmain.py:561 msgid "wxGlade files (*.wxg)|*.wxg|XML files (*.xml)|*.xml|All files|*" msgstr "" #: edit_sizers/edit_sizers.py:83 msgid "Options" msgstr "" #: edit_sizers/edit_sizers.py:286 edit_sizers/edit_sizers.py:287 msgid "Select sizer type" msgstr "" #: edit_sizers/edit_sizers.py:389 msgid "Select a position" msgstr "" #: edit_sizers/edit_sizers.py:495 edit_sizers/edit_sizers.py:1492 msgid "Add slot" msgstr "" #: edit_sizers/edit_sizers.py:496 edit_sizers/edit_sizers.py:1493 msgid "Insert slot..." msgstr "" #: edit_sizers/edit_sizers.py:626 msgid "Fit parent" msgstr "" #: edit_sizers/edit_sizers.py:1494 msgid "Add row" msgstr "" #: edit_sizers/edit_sizers.py:1495 msgid "Add column" msgstr "" #: edit_sizers/edit_sizers.py:1496 msgid "Insert row..." msgstr "" #: edit_sizers/edit_sizers.py:1497 msgid "Insert column..." msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Growable Rows" msgstr "" #: edit_sizers/edit_sizers.py:1885 msgid "Select growable rows" msgstr "" #: edit_sizers/edit_sizers.py:1891 msgid "Growable Columns" msgstr "" #: edit_sizers/edit_sizers.py:1892 msgid "Select growable columns" msgstr "" #: edit_sizers/edit_sizers.py:2002 msgid "Orientation" msgstr "" #: edit_sizers/edit_sizers.py:2003 edit_sizers/edit_sizers.py:2049 msgid "Horizontal" msgstr "" #: edit_sizers/edit_sizers.py:2003 msgid "Vertical" msgstr "" #: edit_sizers/edit_sizers.py:2006 msgid "Slots: " msgstr "" #: edit_sizers/edit_sizers.py:2016 msgid "Has a Static Box" msgstr "" #: edit_sizers/edit_sizers.py:2022 msgid "Label: " msgstr "" #: edit_sizers/edit_sizers.py:2098 msgid "Select sizer attributes" msgstr "" #: widgets/bitmap_button/bitmap_button.py:120 msgid "Select the image for the button" msgstr "" #: widgets/gauge/gauge.py:32 msgid "Creates a horizontal gauge." msgstr "" #: widgets/gauge/gauge.py:33 msgid "Creates a vertical gauge." msgstr "" #: widgets/gauge/gauge.py:34 msgid "Under Windows 95, creates a horizontal progress bar." msgstr "" #: widgets/gauge/gauge.py:35 msgid "" "Creates smooth progress bar with one pixel wide update step (not supported " "by all platforms)." msgstr "" #: widgets/gauge/gauge.py:91 widgets/slider/slider.py:131 msgid "Select style" msgstr "" #: widgets/grid/grid.py:199 msgid "" "The following properties are meaningful\n" "only if 'Create grid' is selected" msgstr "" #: widgets/grid/grid.py:220 widgets/notebook/notebook.py:224 #: widgets/radio_button/radio_button.py:74 widgets/slider/slider.py:84 #: widgets/static_text/static_text.py:65 widgets/text_ctrl/text_ctrl.py:76 #: widgets/tree_ctrl/tree_ctrl.py:105 msgid "Widget" msgstr "" #: widgets/list_box/list_box.py:46 msgid "Single-selection list." msgstr "" #: widgets/list_box/list_box.py:47 msgid "Multiple-selection list: the user can toggle multiple items on and off." msgstr "" #: widgets/list_box/list_box.py:48 msgid "" "Extended-selection list: the user can select multiple items using the SHIFT " "key and the mouse or special key combinations." msgstr "" #: widgets/list_box/list_box.py:49 msgid "Create horizontal scrollbar if contents are too wide (Windows only)." msgstr "" #: widgets/list_box/list_box.py:50 msgid "Always show a vertical scrollbar." msgstr "" #: widgets/list_box/list_box.py:51 msgid "Only create a vertical scrollbar if needed." msgstr "" #: widgets/list_box/list_box.py:52 msgid "The listbox contents are sorted in alphabetical order." msgstr "" #: widgets/list_ctrl/list_ctrl.py:71 msgid "" "Multicolumn list view, with optional small icons. Columns are computed " "automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, " "the list wraps, unlike a wxListBox." msgstr "" #: widgets/list_ctrl/list_ctrl.py:72 msgid "Single or multicolumn report view, with optional header." msgstr "" #: widgets/list_ctrl/list_ctrl.py:73 msgid "Large icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:74 msgid "" "The application provides items text on demand. May only be used with " "wxLC_REPORT." msgstr "" #: widgets/list_ctrl/list_ctrl.py:75 msgid "Small icon view, with optional labels." msgstr "" #: widgets/list_ctrl/list_ctrl.py:76 msgid "Icons align to the top. Win32 default, Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:77 msgid "Icons align to the left." msgstr "" #: widgets/list_ctrl/list_ctrl.py:78 msgid "Icons arrange themselves. Win32 only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:79 msgid "" "Labels are editable: the application will be notified when editing starts." msgstr "" #: widgets/list_ctrl/list_ctrl.py:80 msgid "No header in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:81 msgid "Single selection (default is multiple)." msgstr "" #: widgets/list_ctrl/list_ctrl.py:82 msgid "" "Sort in ascending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:83 msgid "" "Sort in descending order (must still supply a comparison callback in " "SortItems." msgstr "" #: widgets/list_ctrl/list_ctrl.py:84 msgid "Draws light horizontal rules between rows in report mode." msgstr "" #: widgets/list_ctrl/list_ctrl.py:85 msgid "Draws light vertical rules between columns in report mode" msgstr "" #: widgets/list_ctrl/list_ctrl.py:86 msgid "" "Displays a thin border around the window. wxBORDER is the old name for this " "style." msgstr "" #: widgets/list_ctrl/list_ctrl.py:87 msgid "Displays a double border. Windows and Mac only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:88 msgid "Displays a sunken border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:89 msgid "Displays a raised border." msgstr "" #: widgets/list_ctrl/list_ctrl.py:90 msgid "Displays a border suitable for a static control. Windows only." msgstr "" #: widgets/list_ctrl/list_ctrl.py:91 msgid "Displays no border, overriding the default border style for the window." msgstr "" #: widgets/list_ctrl/list_ctrl.py:92 msgid "" "Use this to indicate that the window wants to get all char/key events for " "all keys - even for keys like TAB or ENTER which are usually used for dialog " "navigation and which wouldn't be generated without this style. If you need " "to use this style in order to get the arrows or etc., but would still like " "to have normal keyboard navigation take place, you should create and send a " "wxNavigationKeyEvent in response to the key events for Tab and Shift-Tab." msgstr "" #: widgets/list_ctrl/list_ctrl.py:93 msgid "" "On Windows, this style used to disable repainting the window completely when " "its size is changed. Since this behaviour is now the default, the style is " "now obsolete and no longer has an effect." msgstr "" #: widgets/list_ctrl/list_ctrl.py:94 msgid "" "Use this style to force a complete redraw of the window whenever it is " "resized instead of redrawing just the part of the window affected by " "resizing. Note that this was the behaviour by default before 2.5.1 release " "and that if you experience redraw problems with code which previously used " "to work you may want to try this. Currently this style applies on GTK+ 2 and " "Windows only, and full repainting is always done on other platforms." msgstr "" #: widgets/menubar/menubar.py:18 msgid "Menu editor" msgstr "" #: widgets/menubar/menubar.py:24 msgid "Menu item:" msgstr "" #: widgets/menubar/menubar.py:32 msgid "Label" msgstr "" #: widgets/menubar/menubar.py:33 msgid "Id" msgstr "" #: widgets/menubar/menubar.py:34 msgid "Name" msgstr "" #: widgets/menubar/menubar.py:35 msgid "Help String" msgstr "" #: widgets/menubar/menubar.py:36 widgets/menubar/menubar.py:58 msgid "Type" msgstr "" #: widgets/menubar/menubar.py:38 msgid "Event Handler" msgstr "" #: widgets/menubar/menubar.py:61 msgid "Add" msgstr "" #: widgets/menubar/menubar.py:62 msgid "Remove" msgstr "" #: widgets/menubar/menubar.py:63 msgid "Add separator" msgstr "" #: widgets/menubar/menubar.py:66 msgid "Up" msgstr "" #: widgets/menubar/menubar.py:67 msgid "Down" msgstr "" #: widgets/menubar/menubar.py:72 msgid "Apply" msgstr "" #: widgets/menubar/menubar.py:120 msgid "Id " msgstr "" #: widgets/menubar/menubar.py:122 msgid "Label " msgstr "" #: widgets/menubar/menubar.py:124 msgid "Name " msgstr "" #: widgets/menubar/menubar.py:126 msgid "Help String " msgstr "" #: widgets/menubar/menubar.py:128 msgid "Event Handler " msgstr "" #: widgets/menubar/menubar.py:506 msgid "Edit menus..." msgstr "" #: widgets/menubar/menubar.py:766 msgid "Select menubar class" msgstr "" #: widgets/notebook/notebook.py:331 msgid "Select tab placement" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Top" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Bottom" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Left" msgstr "" #: widgets/notebook/notebook.py:335 msgid "Right" msgstr "" #: widgets/radio_button/radio_button.py:37 msgid "Clicked" msgstr "" #: widgets/radio_button/radio_button.py:42 msgid "Marks the beginning of a new group of radio buttons." msgstr "" #: widgets/radio_button/radio_button.py:43 msgid "" "In some circumstances, radio buttons that are not consecutive siblings " "trigger a hang bug in Windows (only). If this happens, add this style to " "mark the button as not belonging to a group, and implement the mutually-" "exclusive group behaviour yourself." msgstr "" #: widgets/radio_button/radio_button.py:44 msgid "" "Use a checkbox button instead of radio button (currently supported only on " "PalmOS)." msgstr "" #: widgets/slider/slider.py:52 msgid "Displays the slider horizontally (this is the default)." msgstr "" #: widgets/slider/slider.py:53 msgid "Displays the slider vertically." msgstr "" #: widgets/slider/slider.py:54 msgid "Displays tick marks." msgstr "" #: widgets/slider/slider.py:55 msgid "Displays minimum, maximum and value labels." msgstr "" #: widgets/slider/slider.py:56 msgid "Displays ticks on the left and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:57 msgid "Displays ticks on the right and forces the slider to be vertical." msgstr "" #: widgets/slider/slider.py:58 msgid "Displays ticks on the top." msgstr "" #: widgets/slider/slider.py:59 msgid "Displays ticks on the bottom (this is the default)." msgstr "" #: widgets/slider/slider.py:60 msgid "Allows the user to select a range on the slider. Windows only." msgstr "" #: widgets/slider/slider.py:61 msgid "" "Inverses the mininum and maximum endpoints on the slider. Not compatible " "with wxSL_SELRANGE." msgstr "" #: widgets/static_text/static_text.py:42 msgid "Store as attribute" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:79 msgid " Tree Control:" msgstr "" #: widgets/tree_ctrl/tree_ctrl.py:82 #, python-format msgid " on wxGlade %s" msgstr "" spe-0.8.4.h/_spe/plugins/wxGlade/templates/Dialog with two buttons.wgt0000644000175000017500000000421410743421035024705 0ustar stanistani Alberto Griggio <agriggio@users.sourceforge.net> A simple dialog with two standard buttons (OK and Cancel) at the bottom. Used for illustrating the templating capabilities of wxGlade. Open it and play with it in whatever way you want! dialog_1 200, 150d wxVERTICAL wxALL|wxALIGN_RIGHT 5 wxHORIZONTAL 0 OK wxLEFT 10 CANCEL spe-0.8.4.h/_spe/plugins/wxGlade/locale/it/0000755000175000017500000000000011004131465017426 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/ja/0000755000175000017500000000000011004131465017404 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/en/0000755000175000017500000000000011004131465017414 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/it/LC_MESSAGES/0000755000175000017500000000000011004131465021213 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/it/LC_MESSAGES/wxglade.mo0000644000175000017500000000754610743421035023223 0ustar stanistani+t;) $33:n( $" 4Uh/.  )-;i#-+!=M /-Jb w2  ! )   +: 3 n 5 *  ) 0 E v% 1  6 ) ; e q 7 !  "  -> @"  ? M L6^!$ "/R #"!& $ '% *( + )"%s" is not a valid code generator moduleAdd a %sAllow duplicate widget namesAuto save wxg files every Backup optionsCancelChanges will take effect after wxGlade is restartedChoose a directory:Clipboard can't be opened.Create backup files for generated sourceCreate backup wxg filesCustom colourData can't be copied from clipboard.Data can't be copied to clipboard.Default border width for widgetsERROR loading "%s"Error reading config file: %sFound widgets listing -> %sInitial path for code generation file dialogs:Initial path for file opening/saving dialogs:InterfaceInvalid data in the clipboardLocal widget pathNumber of buttons per row in the main paletteNumber of items in file historyOtherPlease only drop one file at a timePreferences savedRemember position and size of wxGlade windowsSelect widget colourShow "handles" of sizersShow progress dialog when loading wxg filesShow properties and tree windows as small frames (Win32 only)System colourUse dialog units by default for size propertiesUse icons in menu itemsUse native file dialogs on KDEappend .bak to filenameappend ~ to filenameloaded code generator for %sloading widget modules:wxGlade: preferencesProject-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2007-01-27 15:22+0100 PO-Revision-Date: 2007-01-27 20:56+0100 Last-Translator: <> Language-Team: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit"%s" non è un modulo di generazione codice validoAggiungi un %sNomi di widget duplicati permessiSalvataggio automatico dei file wxg ogni Opzioni copia di sicurezzaAnnullaI cambiamenti saranno effettivi dopo il riavvio di wxGladeScegli una directory:Impossibile aprire gli appunti.Creare una copia di sicurezza per i sorgenti generatiCreare una copia di sicurezza dei file wxgColori personalizzatiImpossibile copiare i dati dagli appunti.I dati non possono essere copiati negli appunti.Dimenzione bordo widgetERRORE durante il caricamento di "%s"Impossibile leggere il file di configurazione: %sTrovata lista di widget -> %sPercorso iniziale per dialogo file generazione codicePercorso iniziale per dialogo apri file:InterfacciaDati negli appunti non validiPercorso dei widget localiNumero di bottoni per riga nella pulsantiera principaleNumero di righe nella storia fileAltroTrascinare solo un file alla voltaPreferenze salvateRicorda la posizione e la dimenzione delle finestre di wxGladeSelezionare il colore dello widgetMostra "maniglie" dei sizerMostra barra di avanzamento durante il caricamento dei file wxgMostra le finestre delle proprietà e albero con piccole cornici (solo Win32)Colori di sistemaUsare unità di dialogo per la proprietà dimenzionaliUsare le icone nel menuIn KDE usa il dialogo file nativoaggiungi .bak al nome del fileaggiungi ~ al nome del filecaricato generatore di codice per %scaricamento moduli per gli widget:wxGlade: preferenzespe-0.8.4.h/_spe/plugins/wxGlade/locale/ja/LC_MESSAGES/0000755000175000017500000000000011004131465021171 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/ja/LC_MESSAGES/wxglade.mo0000644000175000017500000012102610743421035023167 0ustar stanistani K\$0$3$$ $ % %%%%).%X%m%s%y%%% %% % % %%%,&1?&q& &&&C' '''( (( (+(4( :(@D(=(D(A) J) V)b)>)!))*+, c-o- u---------. .a*.(..3... //"/ =/ K/Y/&^/// / //(//D/)B0Cl0-000]1tr11 12 2$$2"I2 l22 2622-3.3(E3>n3"3/3&4&'4N4h4R4+4G57I55535@5A+6m6)669696 +787=7S7f7 k7 y7#7177 778898W8l8 8,88 88*8(9(893a999z9*: E:f:=n: :: :: ::: ;; !; -; ;;G; X; d;r;;"; ;;2;%<k4<< w=+= =/=.=/>J> [>i>*x> > >>\>5?;?C?JK?&???0? ?@!@1@ D@O@ a@ k@4w@ @ @@G{AAAA:A"B2D DD>PDHDD D#E.$E!SEuE~EEEEEEEE F! F#-FQF ZF-{FF FF-F8F(GnG$(4C0x!-60*g*64-)-W0'*ތ3 3=6q*'Ӎ &"IiBT$Y~B&ԏ)B8b{bސ?A đ ёߑ$BhHYbgm !=A Z@dHLW0<R[ėȗϗd֗;L@+٘&9 UbAiA $(,H[bi!'ٚ !9 [h x ̛*֛ <(OIx œ$ϜJdk ˝ҝ MP i vC Ξ۞ #=T"tϟʡݡF1Z37n'$W`i{e:Pg1 b]6N=P 0 jmX_u)Hd;iEJSq!&o^wV/#r[5a4h4h~2>*}.OctVp8\dB&]x9:pO"GTzfE?-#6lxD^7+;| 8QQ!@K fH[I.m LI"y@-Xl9Bu Myk0gKq >`C bk~MARAnY/(W+r,*? %S$a5w N<s=YvtLFvJDzo) 2c_,CT%'ZsU<Gj(U|R}\e3{ wxGlade-WARNING: only sizers can be pasted here wxGlade-WARNING: sizer already set for this window Add Apply Insert Remove Tree Control: seconds"%s" is not a valid code generator module%s files (*.%s)|*.%s&Edit&File&Generate Code Ctrl+G&Help&Import from XRC... Ctrl+I&New Ctrl+N&Open... Ctrl+O&Raise All F4&Refresh f5&Save Ctrl+S&View'name' attribute missing'object' items must have a 'class' attribute'path' attribute missing: could not generate code'sizeritem' object not found - - %sA comma-separated list of custom base classes. The first will be invoked with the same parameters as this class, while for the others the default constructor will be used. You should probably not use this if "overwrite existing sources" is not set.A template called '%s' already exists: do you want to overwrite it?About wxGladeAbout...AddAdd a %sAdd columnAdd rowAdd separatorAdd slotAlertAlignmentAligns the bitmap label to the bottom of the button. WIN32 only.Aligns the bitmap label to the top of the button. WIN32 only.Aligns the label to the bottom of the button. Windows and GTK+ only.Aligns the label to the top of the button. Windows and GTK+ only.All Files|*All files|*Allow duplicate widget namesAllows the user to select a range on the slider. Windows only.Always show a vertical scrollbar.An exception occurred while generating the code for the application. This is the error message associated with it: %s For more details, look at the full traceback on the console. If you think this is a wxGlade bug, please report it.An exception occurred while importing file "%s". This is the error message associated with it: %s For more details, look at the full traceback on the console. If you think this is a wxGlade bug, please report it.An exception occurred while loading file "%s". This is the error message associated with it: %s For more details, look at the full traceback on the console. If you think this is a wxGlade bug, please report it.An exception occurred while saving file "%s". This is the error message associated with it: %s For more details, look at the full traceback on the console. If you think this is a wxGlade bug, please report it.ApplicationApplyAre you sure?AuthorAuto save detectedAuto save wxg files every Auto saving... doneAvailable templatesBackup optionsBase class(es)BorderBottomCan't find the credits file! Can't find the license! You can get a copy at http://www.opensource.org/licenses/mit-license.phpCan't save a template with an empty nameCancelChanges will take effect after wxGlade is restartedCheckedChoose a directory:Choose a fileClickedClipboard can't be opened.Close PreviewClose previewCodeCode generation completed successfullyCommonConfirmContents F1Copy Ctrl+CCore componentsCreate backup files for generated sourceCreate backup wxg filesCreate horizontal scrollbar if contents are too wide (Windows only).Creates a combobox with a drop-down list.Creates a combobox with a permanently displayed list. Windows only.Creates a flat button. Windows and GTK+ only.Creates a horizontal gauge.Creates a vertical gauge.Creates smooth progress bar with one pixel wide update step (not supported by all platforms).Creates the button as small as possible instead of making it of the standard size (which is the default behaviour ).Custom Widget: %sCustom colourCustom componentsCut Ctrl+XData can't be copied from clipboard.Data can't be copied to clipboard.Default border width for widgetsDelete template '%s'?DescriptionDisable the month (and, implicitly, the year) changingDisable the year changingDisplay a resizeable frame around the window.Display a system menu.Display a thick frame around the window.Displays a border suitable for a static control. Windows only.Displays a close box on the frame.Displays a double border. Windows and Mac only.Displays a maximize box on the dialog.Displays a minimize box on the dialog.Displays a raised border.Displays a sunken border.Displays a thin border around the window. wxBORDER is the old name for this style.Displays minimum, maximum and value labels.Displays no border, overriding the default border style for the window.Displays the slider horizontally (this is the default).Displays the slider vertically.Displays tick marks.Displays ticks on the bottom (this is the default).Displays ticks on the left and forces the slider to be vertical.Displays ticks on the right and forces the slider to be vertical.Displays ticks on the top.Don't generate code for this custom classDownDraws light horizontal rules between rows in report mode.Draws light vertical rules between columns in report modeE&xit Ctrl+QERR:ERROR creating %s: %sERROR loading "%s"EditEdit menus...Edit tools...EditBase or SizerBase object neededEditPanel: Unable to disconnect the event hanlderEnable gettext supportEnter sizeErrorError generating code: %sError loading file %s: %sError reading config file: %sError saving app: %sError saving preferences: %sError: %sError: no writer for language "%s" availableEventEvent HandlerEvent Handler Event handler `on_delete' not implemented!Event handler `on_edit' not implemented!Event handler `on_open' not implemented!Event handler `on_select_template' not implemented!EventsException! obj: %sExtended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.Extra code for this widgetExtra properties for this widgetFamily:File '%s' already exists: do you really want to overwrite it?Fit parentFlexibleFork ErrorFound widgets listing -> %sGenerate codeGridGrowable ColumnsGrowable RowsHandlerHas MenuBarHas StatusBarHas ToolBarHas a Static BoxHelp StringHelp String Help on "Arguments" propertyHideHighlight holidays in the calendarHorizontalIcons align to the left.Icons align to the top. Win32 default, Win32 only.Icons arrange themselves. Win32 only.If this is a custom class, setting this property prevents wxGlade from generating the class definition codeIf you change the default value, it will be interpreted as the name of the subclass of the widget. How this name affects code generation depends on the kind (i.e. language) of output. See the docs for more details.Import fileImpossible to reload an unsaved applicationInformationInitial path for code generation file dialogs:Initial path for file opening/saving dialogs:Insert .wxg file name on generated source filesInsert column...Insert row...Insert slot...Insert timestamp on generated source filesInstructionsInterfaceInvalid data in the clipboardInverses the mininum and maximum endpoints on the slider. Not compatible with wxSL_SELRANGE.LabelLabel Label: Labels are editable: the application will be notified when editing starts.Large icon view, with optional labels.LayoutLeftLeft-justifies the label. Windows and GTK+ only.List Control:Loaded %s (%.2f seconds)Loaded templateLoading time: %.5fLoading...Local widget pathLong HelpLong Help Marks the beginning of a new group of radio buttons.Menu editorMenu item:Multicolumn list view, with optional small icons. Columns are computed automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, the list wraps, unlike a wxListBox.Multiple-selection list: the user can toggle multiple items on and off.NO DESCRIPTIONNameName Name "%s" is already in use. Please enter a different one.New from &Template... Shift+Ctrl+NNo %s code generator for %s (of type %s) availableNo files selected!No header in report mode.No wxApp created yetNone node in _find_toplevelNormal BitmapNumber of buttons per row in the main paletteNumber of items in file historyOKOn Windows, this style used to disable repainting the window completely when its size is changed. Since this behaviour is now the default, the style is now obsolete and no longer has an effect.Only create a vertical scrollbar if needed.Oops!Open fileOptionsOrientationOtherOutput pathOutput path can't be a directory when generating a single fileOutput path must be an existing directory when generating multiple filesOverwrite existing sourcesPaste Ctrl+VPlease only drop one file at a timePlease select a top window for the applicationPlease wait while loading the appPositionPreferences savedPreferences...PreviewProblem previewing gui: %sProperties - <%s>Properties - <>Properties - PropertyProportionPuts a caption on the dialog box.Python files|*.py;*.pyc|All files|*QuestionRecovery from auto save completeRemember position and size of wxGlade windowsRemoveRemove DelRightRight-justifies the bitmap label. WIN32 only.Right-justifies the bitmap label. Windows and GTK+ only.Save As Template...Save As... Shift+Ctrl+SSave changes to the current app?Save project as...Saved %sSecond BitmapSelect a positionSelect font attributesSelect frame classSelect growable columnsSelect growable rowsSelect menubar classSelect output directorySelect output fileSelect sizer attributesSelect sizer typeSelect styleSelect tab placementSelect the image for the buttonSelect toolbar classSelect widget classSelect widget colourSeparate file for each classShort HelpShort Help ShowShow "handles" of sizersShow &Properties F3Show &Tree F2Show Monday as the first day in the weekShow Sunday as the first day in the weekShow progress dialog when loading wxg filesShow properties and tree windows as small framesShow the neighbouring weeks in the previous and next monthsSingle fileSingle or multicolumn report view, with optional header.Single selection (default is multiple).Single-selection list.Size in points:Slots: Small icon view, with optional labels.Sort in ascending order (must still supply a comparison callback in SortItems.Sort in descending order (must still supply a comparison callback in SortItems.Sorts the entries in the list alphabetically.SpacerSpanSpecific font...Store as attributeStyleStyle:System colourTemplates Manager...The application provides items text on demand. May only be used with wxLC_REPORT.The dialog stays on top of all other windows.The following properties are meaningful only if 'Create grid' is selectedThe listbox contents are sorted in alphabetical order.There seems to be auto saved data for this file: do you want to restore it?There seems to be auto saved data from last wxGlade session: do you want to restore it?To save the changes to the template, edit the GUI as usual, and then click File->Save as Template...Tool:Toolbar editorTopTop windowTypeUnder Windows 95, creates a horizontal progress bar.UnderlinedUpUse a checkbox button instead of radio button (currently supported only on PalmOS).Use alternative, more compact, style for the month and year selection controls.Use dialog units by default for size propertiesUse icons in menu itemsUse native file dialogs on KDEUse old "from wxPython.wx" import (python output only)Valid LANGUAGE values:ValueVerticalWARNINGWarning: property '%s' not supported by this object ('%s') Weight:You must specify an output file before generating any codeYou selected file: %sappend .bak to filenameappend ~ to filenameargumentsbackgroundbase classbitmapbitmapsizebordercenteredcharacter data can be present only inside propertiescharacter data can only appear inside propertieschoicesclasscode generationcol_label_sizecolscolumnscreate_griddefaultdimensiondisableddisabled bitmapenable_col_resizeenable_editingenable_grid_linesenable_grid_resizeenable_row_resizeencodingerror in the value of the property "%s"eventsfocusedfontforegroundheighthgaphiddeniconlabellabel_bg_colorlanguagelines_colorloaded code generator for %sloading widget modules:malformed wxg file: slots can only be inside sizers!marginsmenu item outside a menunameorientationpackingpositionproperty '%s' not supported by '%s' objectsrangerow_label_sizerowsrows_numbersash_posscroll_ratescrollableselectionselection_modeseparationsizesizer or sizeritem object cannot be Nonestockitemstyletab_placementtabsthe root of the tree must be titletooltipvaluevgapwidthwxGlade - CreditswxGlade - LicensewxGlade messagewxGlade template informationwxGlade template listwxGlade template: wxGlade template: wxGlade usage: - to start the GUI: python wxglade.py [WXG_FILE] - to generate code from the command line: python wxglade.py OPTIONS... FILE OPTIONS are the following: -g, --generate-code=LANGUAGE (required) give the output language -o, --output=PATH (optional) name of the output file (in single-file mode) or directory (in multi-file mode) wxGlade: TreewxGlade: Tree %swxGlade: preferenceswxWidgets compatibilityProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: brian_nt@nifty.com POT-Creation-Date: 2007-09-05 04:39+0900 PO-Revision-Date: 2007-09-23 03:55+0900 Last-Translator: Norihiko Tashi Language-Team: ja Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 0.9.2dev-r319 wxGlade-警告: ここにはサイザーしか貼り付けることができません wxGlade-警告: このウィンドウにはサイザーが既に設定されています 追加 適用 挿入 削除 ツリーコントロール:秒"%s" は、有効なコード生成モジュールではありません%sファイル(*.%s)|*.%s編集(&E)ファイル(&F)コード生成(&G) Ctrl+Gヘルプ(&H)XRCからインポート(&I)... Ctrl+I新規作成(&N) Ctrl+N開く(&O)... Ctrl+O全て表示(&R)リフレッシュ(&R) f5保存(&S) Ctrl+S表示(&V)'name'属性がありません'object'項目は'class'属性を持っていなければなりません'path' 属性がありません: コードを生成できませんでした'sizerItem'オブジェクトが見つかりません<デザイン> - <プレビュー> - %sコンマで区切ったカスタム基底クラスのリスト。最初のものは、このクラスと同じパラメータで呼び出されます。残りはディフォルトコンストラクタが使われます。"既存のソースを上書きする"が設定されていないなら、これを使うべきではありません。'%s'テンプレートファイルは既に存在します: 上書きしてもよろしいですか?wxGladeについてバージョン情報...追加%sを追加列の追加行の追加セパレータ追加スロット追加警告配置ビットマップラベルをボタンの下に揃える。WIN32のみ。ビットマップラベルをボタンの上に揃える。WIN32のみ。ラベルをボタンの下に揃える。WindowsとGTK+のみ。ラベルをボタンの上に揃える。WindowsとGTK+のみ。全てのファイル|*全てのファイル|*Widget名の重複を許可ユーザがスライダーの範囲を選択可能にする。Windowsのみ。常に垂直スクロールバーを表示する。このアプリケーションのコード生成時に例外が発生しました。 これは、以下に関連したエラーメッセージです: %s 詳細は、コンソールに出力された完全なトレースバックを参照してください。 wxGladeのバグとお思いならばぜひ報告をお願いします。"%s"ファイルのインポート時に例外が発生しました。 これは、以下に関連したエラーメッセージです: %s 詳細は、コンソールに出力された完全なトレースバックを参照してください。 wxGladeのバグとお思いならばぜひ報告をお願いします。"%s"ファイルの読み込み時に例外が発生しました。 これは、以下に関連したエラーメッセージです: %s 詳細は、コンソールに出力された完全なトレースバックを参照してください。 wxGladeのバグとお思いならばぜひ報告をお願いします。"%s"ファイルの保存時に例外が発生しました。 これは、以下に関連したエラーメッセージです: %s 詳細は、コンソールに出力された完全なトレースバックを参照してください。 wxGladeのバグとお思いならばぜひ報告をお願いします。アプリケーション適用よろしいですか?作者自動保存を検出しましたwxgファイルを指定時間毎に自動保存する 自動保存... 完了利用可能なテンプレートバックアップオプション基底クラスボーダー下クレジットファイルが見つかりません! ライセンスが見つかりません! 以下でコピーを入手できます http://www.opensource.org/licenses/mit-license.phpテンプレートを空の名前で保存できませんキャンセル変更はwxGlade再起動後に有効になりますチェック化ディレクトリを選択してくださいファイルを選択してくださいクリッククリップボードを開けません。プレビューを閉じるプレビューを閉じるコードコード生成が完了しました共通確認ヘルプの表示 F1コピー Ctrl+Cコアコンポーネント生成ソースのバックアップファイルを作成するwxgファイルのバックアップを作成する幅を超えた場合水平スクロールバーを作成する(Windowsのみ)。ドロップダウンリストを持つコンボボックスを作成常時表示リストを持つコンボボックスを作成。Windowsのみ。二重ボーダを表示する。WindowsとMacのみ。水平ゲージを作成する垂直ゲージを作成する1ピクセル幅の更新間隔を持つスムースプログレスバーを作成する全てのプラットフォームでサポートされているわけではありません出来る限り小さいボタンを作成する。ディフォルトでは標準サイズカスタムWidget: %sカスタムカラーカスタムコンポーネント切り取り Ctrl+Xクリップボードからデータをコピーできません。クリップボードにデータをコピーできません。Widgetのディフォルトボーダー幅テンプレート '%s'を削除しますか? 詳細月(暗黙に年)の変更を禁止年の変更を禁止ウィンドウ周りにリサイズ可能なフレームを表示システムメニューを表示ウィンドウ周りに薄いフレームを表示スタティックコントロール用に適したボーダを表示する。Windowsのみ。クローズボックスをフレーム上に表示する二重ボーダを表示する。WindowsとMacのみ。ダイアログに最大ボックスを表示ダイアログに最小ボックスを表示浮き彫り型ボーダを表示する窪んだボーダを表示するウィンドウに薄いボーダーを表示する。wxBORDERはこのスタイルの古い名前です。ラベルの最小値・最大値・値ラベルを表示するボーダを表示しない。ウィンドウのディフォルトボーダスタイルを上書きします。スライダを水平に表示(ディフォルト設定)スライダを垂直に表示メモリを表示メモリを下に表示する目盛りを左に表示し、スライダーを垂直にします目盛りを右に表示し、スライダーを垂直にしますメモリを上に表示するこのカスタムクラスではコードを生成しない下へレポートモードで行間に細い水平の罫線を絵画するレポートモードで列間に細い垂直の罫線を絵画する終了(&X) Ctrl+Qエラー:%s 作成エラー: %s"%s"の読み込みエラー編集メニューの編集...ツールの編集...EditBaseまたはSizerBaseオブジェクトが必要ですエディットパネル:イベントハンドラを切断できませんgettextサポートを有効化サイズを入力してくださいエラーコード生成エラー: %sファイル%s読み込みエラー: %sコンフィグファイルの読み込みに失敗しました: %sアプリ保存エラー: %s設定保存エラー: %sエラー: %sエラー: "%s"言語用のライターは利用可能ではありませんイベントイベントハンドライベントハンドラ イベントハンドラ `on_delete' が実装されていません!イベントハンドラ `on_edit' が実装されていません!イベントハンドラ `on_open' が実装されていません!イベントハンドラ `on_select_template' が実装されていません!イベント例外! オブジェクト: %s拡張選択リスト: ユーザはシフトキー、マウス、特殊なキー操作を使用することで複数項目を選択することができますこのWidget特有のコードこのWidget特有のプロパティファミリー:ファイル '%s' は既に存在します:本当に上書きしたいですか?親に合わせる伸縮可能フォークエラーWidgetsリストが見つかりました -> %sコード生成グリッド伸張可能列伸張可能行ハンドラメニューバーを保持ステータスバーを保持ツールバーを保持スタティックボックスを保持ヘルプ文字列ヘルプ文字列 "引数"プロパティのヘルプ隠すカレンダーで休日を強調水平アイコンを左に寄せますアイコンを上に寄せます。Win32のディフォルトです。Win32のみ。アイコン自身で整列。Win32のみ。これがカスタムクラスなら、このプロパティをセットすることで wxGladeがクラス定義コードを生成するのを抑制します。ディフォルト値を変更した場合は、そのWidgetのサブクラスの名前と解釈されます。この名前がコード生成にどう影響を与えるかは、出力方式(言語など)によります。詳細はドキュメントを参照してください。ファイルのインポート保存されていないアプリは再読み込みできません情報コード生成ファイルダイアログの 初期パス:ファイル読み込み/保存ダイアログの 初期パス:生成ソースファイルに.wxgファイル名を挿入する列の挿入...行の挿入...スロット挿入...生成ソースファイルにタイムスタンプを挿入する説明インターフェースクリップボードのデータは有効ではありませんスライダーの最小値と最大値を反転する。wxSL_SELRANGEと" "互換性がありません。ラベル ラベル ラベル: ラベルは編集可能: アプリケーションは編集開始時に通知を受けます。オプションラベルを持つ大きいアイコンビューレイアウト左ラベルを左に揃える。WindowsとGTK+のみ。リストコンロトール %sを読み込みました (%.2f 秒)テンプレートを読み込みました読み込み時間: %.5f読み込み中...ローカルWidgetパス長いヘルプ長いヘルプ新規ラジオボタングループの開始を指定してくださいメニューエディタメニューアイテム:オプションの小さいアイコンを持つ複数列リストビュー。列は自動的に計算されます(wxLC_REPORTをセットしなくて良い)。言い換えると、wxListBoxと違い一巡します。複数選択リスト: ユーザは複数のアイテムをオンオフ出来ます。詳細なし名前名前 名前"%s"は既に使われています。 別の名前を入力してください。テンプレートから新規作成(&T)... Shift+Ctrl+N%sコードジェネレータは利用できません:%s (タイプ%s)ファイルが選択されませんでした!レポートモード内にヘッダ無しwxAppはまだ生成されていません_find_toplevel内にノードがありません通常のビットマップメインパレットにおける" "一行当たりのボタンの数ファイル履歴の項目数OK過去Windowsでは、サイズが変わったときに、このスタイルを使ってウィンドウの完全な再絵画を禁止していました。今ではこの動作がディフォルトです。このスタイルは現在削除されており、何の効果もありません。必要な時のみ垂直スクロールバーを表示する。おっと!ファイルのインポートオプション 方向その他出力パス単一ファイル生成時の出力パスはディレクトリにできません複数ファイル生成時の出力パスは存在するディレクトでなければなりません既存のソースを上書きする貼り付け Ctrl+V同時に1ファイルのみドロップ可能ですアプリケーション用のトップウィンドウを選択してくださいアプリを読み込む間お待ちください位置設定が保存されました設定...プレビューGUIのプレビューに問題が発生しました: %sプロパティ - <%s>プロパティ - <>プロパティ - プロパティプロポーションダイアログボックスにキャプションを入れるPythonファイル|*.py;*.pyc|全てのファイル|*質問自動保存から完全に回復wxGladeウィンドウズの位置とサイズを記憶削除削除 Del右ビットマップラベルを右に揃える。WIN32のみ。ぶっとマップラベルを右に揃える。WindowsとGTK+のみ。テンプレートとして保存...名前を付けて保存... Shift+Ctrl+S現在のアプリへの変更を保存しますか?名前をつけてプロジェクトを保存...%sを保存しました二番目のビットマップ位置を選択してくださいフォント属性を選択してくださいメニューバークラスを選択してください伸張可能列を選択してください伸張可能行を選択してくださいメニューバークラスを選択してください出力ディレクトリを選択してください:出力ファイルを選択してくださいサイザー属性を選択してくださいサイザータイプを選択してくださいスタイルを選択してくださいタブの位置を選択してくださいボタンのイメージを選択してくださいツールバークラスを選択してくださいメニューバークラスを選択してくださいWidgetカラーを選択してくださいクラス別にファイルを分ける短いヘルプ短いヘルプ表示サイザーの"ハンドル"を表示プロパティを表示(&P) F3ツリーを表示(&T) F2月曜を週の最初に表示日曜を週の最初に表示wxgファイルの読み込み時に進行ダイアログを表示プロパティとツリーウィンドウをスモールフレームとして表示前と次の月の近隣週を表示単一ファイルオプションヘッダを持つ単一・複数列のレポート単一選択(ディフォルト設定)単一選択リストサイズ(ポイント)スロット: オプションのラベルを持つ小さいアイコンビュー昇順でソート(SortItems内で比較コールバックを提供する必要があります)。降順でソート(SortItems内で比較コールバックを提供する必要があります)。リスト内エントリをアルファベット順にソートスペーサー範囲フォント指定...属性として保存スタイルスタイル:システムカラーテンプレートマネージャ...アプリケーションはオンデマンドで項目テキストを提供する。" "wxLC_REPORTと一緒の時のみ使われるでしょう。ダイアログを他の全てのウィンドウより前に表示以下のプロパティは'グリッドを作成する'が選択されている場合のみ有効ですリストボックスの内容はアルファベット順にソート。このファイルには自動保存されたデータがあるようです:" "回復しますか?最後のwxGladeセッションでの自動保存データがあるようです。 回復しますか?:テンプレートへの変更を保存する場合、GUIを通常通り編集し、 ファイル->テンプレートとして保存...をクリックしてくださいツール:ツールバーエディタ上トップウィンドウタイプWindows 95では、水平プログレスバーを作成する。下線上へラジオボタンの代わりにチェックボックスボタンを使用してください(現在ではPalmOSでのみサポートされています)月と年の選択に別のよりコンパクトなスタイルを使用サイズプロパティではディフォルトでダイアログユニットを使用メニューアイテムにアイコンを使うKDEでネイティブのファイルダイアログを使用古い形式の"wxPython.wx"を使用する インポート(出力はpythonのみ)有効なLANGUAGE値:値垂直警告警告: '%s'プロパティはこのオブジェクト('%s')ではサポートされていません 幅:コード出力をする前に 出力ファイルを指定してください次のファイルを選択しました: %sファイル名に.bakを追加ファイル名に~を追加引数バックグラウンド基底クラスビットマップビットマップサイズボーダー中央キャラクタデータはproperty内にのみ存在可能ですキャラクタデータはproperty内にのみ存在可能です選択クラスコード生成列ラベルサイズ列列グリッドを作成するディフォルト次元禁止禁止時ビットマップ列のリサイズを有効化編集を有効化グリッドラインを有効化グリッドのリサイズを有効化行のリサイズを有効化エンコーディングプロパティ値エラー "%s"イベントフォーカスフォントフォアグラウンド高さ水平ギャップ隠すアイコンラベルラベルバックグラウンドカラー言語線の色%s 用のコードジェネレータを読み込みましたWidgetモジュールを読み込み中:不正なwxgファイルです:slotはsizer内にのみ存在可能ですマージンメニュー外のメニュー項目名前方向パッキング位置'%s'プロパティは、'%s'クラスでサポートされていません範囲行ラベルサイズ行行の数窓枠位置スクロールレートスクロール可能選択選択モードセパレーションサイズSizerまたはSizerItemオブジェクトが無いことは許されませんストックアイテムスタイルタブ配置タブツリーのルートはでなければなりませんタイトルツールチップ値垂直ギャップ幅wxGlade - クレジットwxGlade - ライセンスwxGladeメッセージwxGladeテンプレート情報wxGladeテンプレートリストwxGladeテンプレート: wxGladeテンプレート: wxGlade 使用法: - GUIを開始する: python wxglade.py [WXG_FILE] - コマンドラインからコードを生成する: python wxglade.py オプション... FILE オプションには以下の物があります: -g, --generate-code=LANGUAGE (必須) 出力言語を指定する -o, --output=PATH (オプション) 出力ファイル名(単一ファイルモード) ディレクトリ(複数ファイルモード) wxGlade: ツリーwxGlade: ツリー %swxGlade: 設定wxWidgets互換性spe-0.8.4.h/_spe/plugins/wxGlade/locale/en/LC_MESSAGES/0000755000175000017500000000000011004131465021201 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/locale/en/LC_MESSAGES/wxglade.mo0000644000175000017500000000055710743421035023204 0ustar stanistani$,859Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2007-01-27 15:20+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spe-0.8.4.h/_spe/plugins/wxGlade/widgets/ChoicesCodeHandler.py0000644000175000017500000000361710743421035023254 0ustar stanistani# ChoicesCodeHandler.py: handler for the 'choices' property of various elements # $Id: ChoicesCodeHandler.py,v 1.8 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY class ChoicesCodeHandler: """\ handler for the 'choices' property of various elements """ def __init__(self): self.choices = [] self.curr_choice = [] self.cur_checked = None def start_elem(self, name, attrs): if name == 'choice': try: self.cur_checked = int(attrs['checked']) except (KeyError, ValueError): self.cur_checked = None def end_elem(self, name, code_obj): if name == 'choice': c = "".join(self.curr_choice) if self.cur_checked is None: self.choices.append(c) else: self.choices.append((c, self.cur_checked)) self.curr_choice = [] self.cur_checked = None elif name == 'choices': code_obj.properties['choices'] = self.choices return True def char_data(self, data): self.curr_choice.append(data) # end of class ChoicesCodeHandler def xrc_write_choices_property(xrc_obj, outfile, tabs): """\ function used to write the XRC code for a ``choices'' property """ from xml.sax.saxutils import escape choices = xrc_obj.properties['choices'] write = outfile.write write(' '*tabs + '\n') tab_s = ' ' * (tabs+1) for choice in choices: if isinstance(choice, tuple): write(tab_s + '%s\n' % \ (choice[1], escape(choice[0]))) else: write(tab_s + '%s\n' % escape(choice)) write(' '*tabs + '\n') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/MenuTree.py0000644000175000017500000000612110743421035021323 0ustar stanistani# MenuTree.py: A class to represent a menu on a wxMenuBar # $Id: MenuTree.py,v 1.12 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY class MenuTree: """\ A class to represent a menu on a wxMenuBar """ class Node: def __init__(self, label="", id="", name="", help_str="", checkable="", radio="", handler=""): self.label = label self.id = id self.name = name self.help_str = help_str self.checkable = checkable self.radio = radio self.handler = handler self.children = [] self.parent = None def write(self, outfile, tabs, top=False): from xml.sax.saxutils import escape, quoteattr import common fwrite = outfile.write tstr = ' ' * (tabs+1) label = common._encode_to_xml(self.label) help_str = common._encode_to_xml(self.help_str) if not top and not self.children: fwrite('%s\n' % (' ' * tabs)) label = escape(label) if label: fwrite('%s\n' % (tstr, label)) id = escape(self.id) if id: fwrite('%s%s\n' % (tstr, id)) name = escape(self.name) if name: fwrite('%s%s\n' % (tstr, name)) help_str = escape(help_str) if help_str: fwrite('%s%s\n' % (tstr, help_str)) try: checkable = int(self.checkable) except: checkable = 0 if checkable: fwrite('%s%s\n' % (tstr, checkable)) try: radio = int(self.radio) except: radio = 0 if radio: fwrite('%s%s\n' % (tstr, radio)) # ALB 2004-12-05 handler = escape(self.handler.strip()) if handler: fwrite('%s%s\n' % (tstr, handler)) fwrite('%s\n' % (' ' * tabs)) else: name = quoteattr(self.name) fwrite(' ' * tabs + '\n' % (quoteattr(label))) for c in self.children: c.write(outfile, tabs+1) fwrite(' ' * tabs + '\n') #end of class Node def __init__(self, name, label, id="", help_str="", handler=""): self.root = self.Node(label, id, name, help_str, handler=handler) def write(self, outfile, tabs): self.root.write(outfile, tabs, top=True) #end of class MenuTree spe-0.8.4.h/_spe/plugins/wxGlade/widgets/widgets.txt0000644000175000017500000000064610743421035021442 0ustar stanistani# list of widget modules available (one per line, without extension) # lines starting with a '#' are comments frame dialog panel splitter_window notebook button toggle_button bitmap_button spin_button text_ctrl spin_ctrl slider gauge static_text checkbox radio_button radio_box choice combo_box list_box calendar_ctrl datepicker_ctrl static_line static_bitmap list_ctrl tree_ctrl grid custom_widget menubar toolbar spacer spe-0.8.4.h/_spe/plugins/wxGlade/widgets/__init__.py0000644000175000017500000000036510743421035021342 0ustar stanistani# __init__.py: here to please SPE... # $Id: __init__.py,v 1.2 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY spe-0.8.4.h/_spe/plugins/wxGlade/widgets/ChoicesProperty.py0000644000175000017500000000433710743421035022730 0ustar stanistani# ChoicesProperty.py: defines a Property and two handlers used by choice, # combo_box, radio_box, list_box # $Id: ChoicesProperty.py,v 1.8 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import widget_properties class ChoicesProperty(widget_properties.GridProperty): def write(self, outfile, tabs): from xml.sax.saxutils import escape write = outfile.write write(' ' * tabs + '\n') tab_s = ' ' * (tabs+1) for val in self.get_value(): v = widget_properties._encode(val[0]) try: checked = int(val[1]) except (IndexError, ValueError): checked = None if checked is None: write('%s%s\n' % (tab_s, escape(v))) else: write('%s%s\n' % \ (tab_s, checked, escape(v))) write(' ' * tabs + '\n') # end of class ChoicesProperty class ChoicesHandler: def __init__(self, owner): self.choices = [] self.curr_choice = [] self.cur_checked = None self.owner = owner def start_elem(self, name, attrs): if name == 'choice': try: self.cur_checked = int(attrs['checked']) except (KeyError, ValueError): self.cur_checked = None def end_elem(self, name): if name == 'choice': if self.cur_checked is None: self.choices.append(["".join(self.curr_choice)]) else: self.choices.append(["".join(self.curr_choice), self.cur_checked]) self.curr_choice = [] self.cur_checked = None elif name == 'choices': self.owner.set_choices(self.choices) self.owner.properties['choices'].set_value( self.owner.get_choices()) self.choices = [] return True # remove the handler def char_data(self, data): self.curr_choice.append(data) # end of class ChoicesHandler spe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/0000755000175000017500000000000011004131465020453 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/0000755000175000017500000000000011004131465022075 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/0000755000175000017500000000000011004131465022456 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/0000755000175000017500000000000011004131465020311 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/0000755000175000017500000000000011004131465021007 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/0000755000175000017500000000000011004131465020652 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/0000755000175000017500000000000011004131465021712 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/0000755000175000017500000000000011004131465020313 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/0000755000175000017500000000000011004131465021565 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/0000755000175000017500000000000011004131465021517 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/0000755000175000017500000000000011004131465021220 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/0000755000175000017500000000000011004131465021044 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/0000755000175000017500000000000011004131465021231 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/datepicker_ctrl/0000755000175000017500000000000011004131465022360 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/calendar_ctrl/0000755000175000017500000000000011004131465022016 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/0000755000175000017500000000000011004131465021041 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/0000755000175000017500000000000011004131465021554 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/0000755000175000017500000000000011004131465020534 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/0000755000175000017500000000000011004131465020320 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/0000755000175000017500000000000011004131465020663 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/0000755000175000017500000000000011004131465021167 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/0000755000175000017500000000000011004131465020503 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/0000755000175000017500000000000011004131465020146 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/0000755000175000017500000000000011004131465022044 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/0000755000175000017500000000000011004131465022070 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/0000755000175000017500000000000011004131465021204 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/0000755000175000017500000000000011004131465021216 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/0000755000175000017500000000000011004131465020476 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/0000755000175000017500000000000011004131465020460 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/0000755000175000017500000000000011004131465022076 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/0000755000175000017500000000000011004131465021170 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/codegen.py0000644000175000017500000000764010743421035022444 0ustar stanistani# codegen.py: code generator functions for wxChoice objects # $Id: codegen.py,v 1.14 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) choices = ', '.join([pygen.quote_str(c) for c in choices]) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, choices=[%s]%s)\n' % (obj.name, klass, parent, id, choices, style)) props_buf = pygen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and len(prop.get('choices', [])): props_buf.append('self.%s.SetSelection(%s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class ChoiceXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'choices': xrc_write_choices_property(self, outfile, tabs) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class ChoiceXrcObject return ChoiceXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxChoice objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' number = len(choices) ch_arr = '{\n %s\n };\n' % \ ',\n '.join([cppgen.quote_str(c) for c in choices]) style = prop.get("style", "0") init = [] if number: init.append('const wxString %s_choices[] = %s' % (obj.name, ch_arr)) else: init.append('const wxString *%s_choices = NULL;\n' % obj.name) init.append('%s = new %s(%s, %s, wxDefaultPosition, wxDefaultSize, ' '%s, %s_choices, %s);\n' % \ (obj.name, obj.klass, parent, id, number, obj.name, style)) props_buf = cppgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and len(prop.get('choices', [])): props_buf.append('%s->SetSelection(%s);\n' % (obj.name, selection)) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditChoice'] = 'wxChoice' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxChoice', PythonCodeGenerator()) pygen.add_property_handler('choices', ChoicesCodeHandler) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxChoice', xrc_code_generator) xrcgen.add_property_handler('choices', ChoicesCodeHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxChoice', CppCodeGenerator()) cppgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/perl_codegen.py0000644000175000017500000000334510743421035023464 0ustar stanistani# perl_codegen.py : perl generator functions for wxChoice objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:36:21 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = '' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); choices = ', '.join([plgen.quote_str(c) for c in choices]) init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, \ wxDefaultSize, [%s], %s);\n' % (obj.name, klass, parent, id, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('$self->{%s}->SetSelection(%s);\n' % (obj.name, selection)) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditChoice'] = 'wxChoice' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxChoice', PerlCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/lisp_codegen.py0000644000175000017500000000346710743421035023476 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxChoice objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:58:29 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) length = len(choices) choices = ' '.join([plgen.quote_str(c) for c in choices]) init.append('(setf (slot-%s obj) (wxChoice_Create %s %s -1 -1 -1 -1 %s (vector %s) %s))\n' % (obj.name, parent, id, length, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('(wxChoice_SetSelection (slot-%s obj) %s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditChoice'] = 'wxChoice' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxChoice', LispCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/choice.py0000644000175000017500000001332010743421035022262 0ustar stanistani# choice.py: wxChoice objects # $Id: choice.py,v 1.18 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from ChoicesProperty import * if wx.Platform == '__WXMSW__': # On windows GetBestSize considers also the drop down menu, while we # don't want it to be included. class wxChoice2(wx.Choice): def GetBestSize(self): w, h = wx.Choice.GetBestSize(self) n = self.GetCount() return w, h/(n+1) def GetSize(self): return self.GetClientSize() else: wxChoice2 = wx.Choice class EditChoice(ManagedBase): events = ['EVT_CHOICE'] def __init__(self, name, parent, id, choices, sizer, pos, property_window, show=True): """\ Class to handle wxChoice objects """ import config ManagedBase.__init__(self, name, 'wxChoice', parent, id, sizer, pos, property_window, show=show) self.choices = choices self.selection = 0 self.access_functions['choices'] = (self.get_choices, self.set_choices) self.properties['choices'] = ChoicesProperty(self, 'choices', None, [('Label', GridProperty.STRING)], len(choices),label=_('choices')) self.access_functions['selection'] = (self.get_selection, self.set_selection) self.properties['selection'] = SpinProperty(self, 'selection', None, r=(0, len(choices)-1), label=_('selection')) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wxChoice2(self.parent.widget, self.id, choices=self.choices) self.set_selection(self.selection) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['choices'].display(panel) self.properties['selection'].display(panel) szr.Add(self.properties['selection'].panel, 0, wx.EXPAND) szr.Add(self.properties['choices'].panel, 1, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') self.properties['choices'].set_col_sizes([-1]) def get_choices(self): return zip(self.choices) def set_choices(self, values): self.choices = [ misc.wxstr(v[0]) for v in values ] self.properties['selection'].set_range(0, len(self.choices)-1) if self.widget: self.widget.Clear() for c in self.choices: self.widget.Append(c) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) self.widget.SetSelection( int(self.properties['selection'].get_value())) def get_property_handler(self, prop_name): if prop_name == 'choices': return ChoicesHandler(self) return ManagedBase.get_property_handler(self, prop_name) def get_selection(self): return self.selection def set_selection(self, value): value = int(value) if value != self.selection: self.selection = value if self.widget: self.widget.SetSelection(value) # end of class EditChoice def builder(parent, sizer, pos, number=[1]): """\ factory function for EditChoice objects. """ name = 'choice_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'choice_%d' % number[0] choice = EditChoice(name, parent, wx.NewId(), [], #[misc._encode('choice 1')], sizer, pos, common.property_panel) node = Tree.Node(choice) #sizer.set_item(pos, size=choice.GetBestSize()) choice.node = node choice.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditChoice objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") choice = EditChoice(name, parent, wx.NewId(), [], sizer, pos, common.property_panel) #, show=False) sizer.set_item(choice.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=choice.GetBestSize()) node = Tree.Node(choice) choice.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return choice def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditChoice'] = builder common.widgets_from_xml['EditChoice'] = xml_builder return common.make_object_button('EditChoice', 'icons/choice.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/choice/__init__.py0000644000175000017500000000064410743421035022574 0ustar stanistani# __init__.py: choice widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import choice return choice.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/codegen.py0000644000175000017500000000455610743421035024071 0ustar stanistani# codegen.py: code generator functions for wxToggleButton objects # $Id: codegen.py,v 1.13 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s)\n' % (obj.name, klass, parent, id, label)) props_buf = pygen.generate_common_properties(obj) value = prop.get('value') if value: props_buf.append('self.%s.SetValue(%s)\n' % (obj.name, value)) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxToggleButton objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] label = cppgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' init = [ '%s = new %s(%s, %s, %s);\n' % (obj.name, obj.klass, parent, id, label) ] props_buf = cppgen.generate_common_properties(obj) value = prop.get('value') if value: props_buf.append('%s->SetValue(%s);\n' % (obj.name, value)) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditToggleButton'] = 'wxToggleButton' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxToggleButton', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxToggleButton', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/perl_codegen.py0000644000175000017500000000266610743421035025113 0ustar stanistani# perl_codegen.py : perl generator functions for wxToggleButton objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:53:15 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s);\n' % (obj.name, klass, parent, id, label)) props_buf = plgen.generate_common_properties(obj) value = prop.get('value') if value: props_buf.append('$self->{%s}->SetValue(%s);\n' % (obj.name, value)) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditToggleButton'] = 'wxToggleButton' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxToggleButton', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/lisp_codegen.py0000644000175000017500000000256710743421035025120 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxToggleButton objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:41:28 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxToggleButton_Create %s %s %s -1 -1 -1 -1 0))\n' % (obj.name, parent, id, label)) props_buf = plgen.generate_common_properties(obj) value = prop.get('value') if value: props_buf.append('(wxToggleButton_SetValue (slot-%s obj) %s)\n' % (obj.name, value)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditToggleButton'] = 'wxToggleButton' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxToggleButton', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/__init__.py0000644000175000017500000000067110743421035024216 0ustar stanistani# __init__.py: toggle button widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import toggle_button return toggle_button.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toggle_button/toggle_button.py0000644000175000017500000001137210743421035025333 0ustar stanistani# toggle_button.py: wxToggleButton objects # $Id: toggle_button.py,v 1.14 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditToggleButton(ManagedBase): events = ['EVT_TOGGLEBUTTON'] def __init__(self, name, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxToggleButton objects """ import config ManagedBase.__init__(self, name, 'wxToggleButton', parent, id, sizer, pos, property_window, show=show) self.label = label self.value = 0 self.access_functions['label'] = (self.get_label, self.set_label) self.access_functions['value'] = (self.get_value, self.set_value) self.properties['label'] = TextProperty(self, 'label', None, multiline=True, label=_("label")) self.properties['value'] = CheckBoxProperty(self, 'value', None, _('Clicked')) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wx.ToggleButton(self.parent.widget, self.id, self.label) self.widget.SetValue(self.value) wx.EVT_TOGGLEBUTTON(self.widget, self.id, self.on_set_focus) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['label'].display(panel) self.properties['value'].display(panel) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['value'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_label(self): return self.label def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): self.label = value if self.widget: self.widget.SetLabel(value.replace('\\n', '\n')) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_value(self): return self.value def set_value(self, value): # !!! This should be done with bool. # 2003-03-21 NO! bools are evil here: bool('0') == True != int('0') value = int(value) if value != self.value: self.value = value if self.widget: self.widget.SetValue(value) # end of class EditToggleButton def builder(parent, sizer, pos, number=[1]): """\ factory function for EditToggleButton objects. """ label = 'button_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'button_%d' % number[0] button = EditToggleButton(label, parent, wx.NewId(), misc._encode(label), sizer, pos, common.property_panel) node = Tree.Node(button) button.node = node button.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditToggleButton objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") button = EditToggleButton(label, parent, wx.NewId(), '', sizer, pos, common.property_panel) sizer.set_item(button.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) #, size=button.GetBestSize()) node = Tree.Node(button) button.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return button def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditToggleButton'] = builder common.widgets_from_xml['EditToggleButton'] = xml_builder return common.make_object_button('EditToggleButton', 'icons/toggle_button.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/splitter_window.py0000644000175000017500000003607310743421035026302 0ustar stanistani# splitter_window.py: wxSplitterWindow objects # $Id: splitter_window.py,v 1.28 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase, WindowBase, EditBase from edit_sizers.edit_sizers import Sizer, SizerSlot class SplitterWindowSizer(Sizer): """\ "Virtual sizer" responsible for the management of a SplitterWindow. """ def set_item(self, pos, option=None, flag=None, border=None, size=None, force_layout=True): """\ Updates the layout of the item at the given pos. """ #print 'set_item' if self.window.widget and \ self.window.window_old and self.window.window_old.widget: self.window.widget.Unsplit(self.window.window_old.widget) self.window.window_old = None if self.window.window_1 and self.window.window_2: self.window.split() def add_item(self, item, pos=None, option=0, flag=0, border=0, size=None, force_layout=True): """\ Adds an item to self.window. """ #print 'add_item', item.name if pos == 1: self.window.window_old = self.window.window_1 self.window.window_1 = item self.window.properties['window_1'].set_value(item.name) else: self.window.window_old = self.window.window_2 self.window.window_2 = item self.window.properties['window_2'].set_value(item.name) def free_slot(self, pos, force_layout=True): """\ Replaces the element at pos with an empty slot """ if pos == 1: if self.window.widget and \ self.window.window_1 and self.window.window_1.widget: self.window.widget.Unsplit(self.window.window_1.widget) self.window.window_1 = SizerSlot(self.window, self, pos) w = self.window.window_1 else: if self.window.widget and \ self.window.window_2 and self.window.window_2.widget: self.window.widget.Unsplit() self.window.window_2 = SizerSlot(self.window, self, pos) w = self.window.window_2 self.window.split() w.widget.SetFocus() def get_itempos(self, attrs): """\ Get position of sizer item (used in xml_parse) """ if hasattr(self.window.properties['window_1'], 'value') and \ attrs['name'] == self.window.properties['window_1'].value: pos = 1 else: pos = 2 return pos def is_virtual(self): return True # end of class SplitterWindowSizer class EditSplitterWindow(ManagedBase): _custom_base_classes = True events = [ 'EVT_SPLITTER_SASH_POS_CHANGING', 'EVT_SPLITTER_SASH_POS_CHANGED', 'EVT_SPLITTER_UNSPLIT', 'EVT_SPLITTER_DCLICK', ] def __init__(self, name, parent, id, style, win_1, win_2, orientation, sizer, pos, property_window, show=True): """\ Class to handle wxSplitterWindow objects """ ManagedBase.__init__(self, name, 'wxSplitterWindow', parent, id, sizer, pos, property_window, show=show) self.virtual_sizer = SplitterWindowSizer(self) if style is None: style = wx.SP_3D self.style = style self.window_1 = win_1 self.window_2 = win_2 self.orientation = orientation self.sash_pos = 0 self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['sash_pos'] = (self.get_sash_pos, self.set_sash_pos) self.style_pos = (wx.SP_3D, wx.SP_3DSASH, wx.SP_3DBORDER, #wx.SP_FULLSASH, wx.SP_BORDER, wx.SP_NOBORDER, wx.SP_PERMIT_UNSPLIT, wx.SP_LIVE_UPDATE, wx.CLIP_CHILDREN) style_labels = ('#section#' + _('Style'), 'wxSP_3D', 'wxSP_3DSASH', 'wxSP_3DBORDER', #'wxSP_FULLSASH', 'wxSP_BORDER', 'wxSP_NOBORDER', 'wxSP_PERMIT_UNSPLIT', 'wxSP_LIVE_UPDATE', 'wxCLIP_CHILDREN') self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) if self.orientation == wx.SPLIT_HORIZONTAL: od = 'wxSPLIT_HORIZONTAL' else: od = 'wxSPLIT_VERTICAL' self.access_functions['orientation'] = (self.get_orientation, self.set_orientation) self.properties['orientation'] = HiddenProperty(self, 'orientation', label=_("orientation")) self.access_functions['window_1'] = (self.get_win_1, lambda v: None) self.access_functions['window_2'] = (self.get_win_2, lambda v: None) self.properties['window_1'] = HiddenProperty(self, 'window_1') self.properties['window_2'] = HiddenProperty(self, 'window_2') self.window_1 = SizerSlot(self, self.virtual_sizer, 1) self.window_2 = SizerSlot(self, self.virtual_sizer, 2) self.properties['sash_pos'] = SpinProperty(self, 'sash_pos', None, r=(0, 20), can_disable=True, label=_("sash_pos")) self.no_custom_class = False self.access_functions['no_custom_class'] = (self.get_no_custom_class, self.set_no_custom_class) self.properties['no_custom_class'] = CheckBoxProperty( self, 'no_custom_class', label=_("Don't generate code for this custom class")) def create_widget(self): self.widget = wx.SplitterWindow(self.parent.widget, self.id, style=self.style) self.split() def finish_widget_creation(self): ManagedBase.finish_widget_creation(self, sel_marker_parent=self.widget) sp = self.properties['sash_pos'] if sp.is_active(): sp.set_value(self.sash_pos) self.widget.SetSashPosition(self.sash_pos) else: sp.set_value(self.widget.GetSashPosition()) wx.EVT_SPLITTER_SASH_POS_CHANGED(self.widget, self.widget.GetId(), self.on_sash_pos_changed) def on_set_focus(self, event): self.show_properties() # here we must call event.Skip() also on Win32 as this we should be # able to move the sash event.Skip() def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) sizer = wx.BoxSizer(wx.VERTICAL) self.properties['no_custom_class'].display(panel) self.properties['style'].display(panel) self.properties['sash_pos'].display(panel) sizer.Add(self.properties['no_custom_class'].panel, 0, wx.ALL|wx.EXPAND, 3) sizer.Add(self.properties['style'].panel, 0, wx.EXPAND) sizer.Add(self.properties['sash_pos'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(sizer) sizer.Fit(panel) self.notebook.AddPage(panel, 'Widget') def split(self): if not self.widget: return if self.window_1 and self.window_2: self.window_1.show_widget(True) self.window_2.show_widget(True) sp = self.properties['sash_pos'].get_value() if not self.properties['sash_pos'].is_active(): if self.orientation == wx.SPLIT_VERTICAL: max_pos = self.widget.GetClientSize()[0] else: max_pos = self.widget.GetClientSize()[1] sp = max_pos/2 if self.orientation == wx.SPLIT_VERTICAL: self.widget.SplitVertically(self.window_1.widget, self.window_2.widget, sp) else: self.widget.SplitHorizontally(self.window_1.widget, self.window_2.widget, sp) for w in self.window_1, self.window_2: if hasattr(w, 'sel_marker'): w.sel_marker.update() def get_style(self): retval = [0] * len(self.style_pos) if not self.style: # style is wxSP_NOBORDER #retval[5] = 1 retval[4] = 1 try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass if retval[1] and retval[2]: # wx.SP_3D == wx.SP_3DSASH | wx.SP_3DBORDER retval[0] = 1 retval[1] = retval[2] = 0 elif retval[1] or retval[2]: retval[0] = 0 return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_sash_pos(self): return self.sash_pos def set_sash_pos(self, value): try: value = int(value) except ValueError: return self.sash_pos = value if self.widget: self.widget.SetSashPosition(value) def on_size(self, event): if not self.widget: return try: if self.orientation == wx.SPLIT_VERTICAL: max_pos = self.widget.GetClientSize()[0] else: max_pos = self.widget.GetClientSize()[1] self.properties['sash_pos'].set_range(-max_pos, max_pos) if not self.properties['sash_pos'].is_active(): self.widget.SetSashPosition(max_pos/2) self.sash_pos = self.widget.GetSashPosition() self.properties['sash_pos'].set_value(self.sash_pos) except (AttributeError, KeyError): pass ManagedBase.on_size(self, event) def on_sash_pos_changed(self, event): self.sash_pos = self.widget.GetSashPosition() self.properties['sash_pos'].set_value(self.sash_pos) event.Skip() def get_orientation(self): od = { wx.SPLIT_HORIZONTAL: 'wxSPLIT_HORIZONTAL', wx.SPLIT_VERTICAL: 'wxSPLIT_VERTICAL' } return od.get(self.orientation, 'wxSPLIT_VERTICAL') def set_orientation(self, value): od = { 'wxSPLIT_HORIZONTAL': wx.SPLIT_HORIZONTAL, 'wxSPLIT_VERTICAL': wx.SPLIT_VERTICAL } self.orientation = od.get(value, wx.SPLIT_VERTICAL) def get_win_1(self): if not isinstance(self.window_1, SizerSlot): return self.window_1.name return '' def get_win_2(self): if not isinstance(self.window_2, SizerSlot): return self.window_2.name return '' def get_no_custom_class(self): return self.no_custom_class def set_no_custom_class(self, value): self.no_custom_class = bool(int(value)) # end of class EditSplitterWindow def builder(parent, sizer, pos, number=[1]): """\ factory function for EditSplitterWindow objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, 'Select orientation') self.orientations = [ wx.SPLIT_VERTICAL, wx.SPLIT_HORIZONTAL ] self.orientation = wx.SPLIT_VERTICAL prop = RadioProperty(self, 'orientation', self, ['wxSPLIT_VERTICAL', 'wxSPLIT_HORIZONTAL'], label=_("orientation")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop.panel, 0, wx.ALL|wx.EXPAND, 10) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.BOTTOM|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, value): def set_orientation(o): self.orientation = self.orientations[o] return (lambda: self.orientation, set_orientation) # end of inner class dialog = Dialog() dialog.ShowModal() name = 'window_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'window_%d' % number[0] window = EditSplitterWindow(name, parent, wx.NewId(), None, None, None, dialog.orientation, sizer, pos, common.property_panel, show=False) try: from panel import EditPanel have_panels = True except ImportError: have_panels = False if have_panels: pane1 = EditPanel(name + '_pane_1', window, wx.NewId(), window.virtual_sizer, 1, common.property_panel) pane2 = EditPanel(name + '_pane_2', window, wx.NewId(), window.virtual_sizer, 2, common.property_panel) window.window_1 = pane1 window.window_2 = pane2 node = Tree.Node(window) window.node = node window.virtual_sizer.node = node window.set_option(1) window.set_flag("wxEXPAND") window.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) if have_panels: node2 = Tree.Node(window.window_1) window.window_1.node = node2 common.app_tree.add(node2, window.node) node3 = Tree.Node(window.window_2) window.window_2.node = node3 common.app_tree.add(node3, window.node) sizer.set_item(window.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditSplitterWindow objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if not sizer or not sizeritem: raise XmlParsingError, _("sizer or sizeritem object cannot be None") window = EditSplitterWindow(name, parent, wx.NewId(), None, None, None, wx.SPLIT_VERTICAL, sizer, pos, common.property_panel, True) sizer.set_item(window.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(window) window.node = node window.virtual_sizer.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return window def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditSplitterWindow'] = builder common.widgets_from_xml['EditSplitterWindow'] = xml_builder return common.make_object_button('EditSplitterWindow', 'icons/splitter_window.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/codegen.py0000644000175000017500000002034710743421035024446 0ustar stanistani# codegen.py: code generator functions for wxSplitterWindow objects # $Id: codegen.py,v 1.18 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, window): pygen = common.code_writers['python'] prop = window.properties id_name, id = pygen.generate_code_id(window) if not window.parent.is_toplevel: parent = 'self.%s' % window.parent.name else: parent = 'self' if window.is_toplevel: l = [] if id_name: l.append(id_name) l.append('self.%s = %s(%s, %s)\n' % (window.name, pygen.without_package(window.klass), parent,id)) return l, [], [] style = prop.get("style") if style and style != 'wxSP_3D': style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = window.klass if window.preview: klass = 'wxSplitterWindow' init.append(('self.%s = ' + pygen.cn(klass) + '(%s, %s%s)\n') % (window.name, parent, id, style)) props_buf = pygen.generate_common_properties(window) layout_buf = [] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if sash_pos: sash_pos = ', %s' % sash_pos if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' layout_buf.append('self.%s.%s(self.%s, self.%s%s)\n' % \ (window.name, f_name, win_1, win_2, sash_pos)) else: def add_sub(win): layout_buf.append('self.%s.SetSplitMode(%s)\n' % \ (window.name, pygen.cn(orientation))) layout_buf.append('self.%s.Initialize(self.%s)\n' % \ (window.name, win)) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return init, props_buf, layout_buf def get_layout_code(self, obj): prop = obj.properties pygen = common.code_writers['python'] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') props_buf = [] if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if sash_pos: sash_pos = ', %s' % sash_pos if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' props_buf.append('self.%s(self.%s, self.%s%s)\n' % (f_name, win_1, win_2, sash_pos)) else: def add_sub(win): props_buf.append('self.SetSplitMode(%s)\n' % pygen.cn(orientation)) props_buf.append('self.Initialize(self.%s)\n' % win) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return props_buf # end of class PythonCodeGenerator class CppCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', 'wxSP_3D')] extra_headers = [''] def get_code(self, window): """\ generates the C++ code for wxSplitterWindow """ cppgen = common.code_writers['C++'] prop = window.properties id_name, id = cppgen.generate_code_id(window) if id_name: ids = [ id_name ] else: ids = [] if not window.parent.is_toplevel: parent = '%s' % window.parent.name else: parent = 'this' if window.is_toplevel: l = ['%s = new %s(%s, %s);\n' % (window.name, window.klass, parent, id)] return l, ids, [], [] extra = '' style = prop.get("style") if style and style != 'wxSP_3D': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s%s);\n' % (window.name, window.klass, parent, id, extra) ] props_buf = cppgen.generate_common_properties(window) layout_buf = [] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if sash_pos: sash_pos = ', %s' % sash_pos if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' layout_buf.append('%s->%s(%s, %s%s);\n' % \ (window.name, f_name, win_1, win_2, sash_pos)) else: def add_sub(win): layout_buf.append('%s->SetSplitMode(%s);\n' % (window.name, orientation)) layout_buf.append('%s->Initialize(%s);\n' % (window.name, win)) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return init, ids, props_buf, layout_buf def get_layout_code(self, obj): prop = obj.properties cppgen = common.code_writers['C++'] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') props_buf = [] if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if sash_pos: sash_pos = ', %s' % sash_pos if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' props_buf.append('%s(%s, %s%s);\n' % \ (f_name, win_1, win_2, sash_pos)) else: def add_sub(win): props_buf.append('SetSplitMode(%s);\n' % orientation) props_buf.append('Initialize(%s);\n' % win) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return props_buf def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxSplitterEvent') # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): props_map = { 'sash_pos': 'sashpos', 'window_1': '', 'window_2': '', } orient_map = { 'wxSPLIT_VERTICAL': 'vertical', 'wxSPLIT_HORIZONTAL': 'horizontal', } def write_property(self, name, val, outfile, ntabs): try: prop = self.props_map.get(name, name) if not prop: return if prop == 'orientation': val = self.orient_map[val] xrcgen.DefaultXrcObject.write_property( self, prop, val, outfile, ntabs) except KeyError: return def write(self, *args, **kwds): if 'no_custom_class' in self.properties: del self.properties['no_custom_class'] xrcgen.DefaultXrcObject.write(self, *args, **kwds) # end of class XrcCodeGenerator return XrcCodeGenerator(obj) def initialize(): common.class_names['EditSplitterWindow'] = 'wxSplitterWindow' common.class_names['SplitterPane'] = 'wxPanel' common.toplevels['EditSplitterWindow'] = 1 common.toplevels['SplitterPane'] = 1 pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxSplitterWindow', PythonCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxSplitterWindow', xrc_code_generator)#xrcgen.NotImplementedXrcObject) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxSplitterWindow', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/perl_codegen.py0000644000175000017500000000757010743421035025473 0ustar stanistani# perl_codegen.py : perl generator functions for wxSplitterWindow objects # $Id: perl_codegen.py,v 1.8 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: #wxSplitterWindow( parent, id, pos , size , style , name ) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, window): plgen = common.code_writers['perl'] prop = window.properties id_name, id = plgen.generate_code_id(window) if not window.parent.is_toplevel: parent = '$self->{%s}' % window.parent.name else: parent = '$self' if window.is_toplevel: l = [] if id_name: l.append(id_name) klass = window.base if klass != window.klass: klass = window.klass else: klass = klass.replace('wx','Wx::',1) l.append('$self->{%s} = %s->new(%s, %s);\n' % (window.name, plgen.cn(klass), parent,id)) return l, [], [] style = prop.get("style") if not( style and style != 'wxSP_3D' ): # default style style = '' init = [] if id_name: init.append(id_name) init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, ' 'wxDefaultSize, %s);\n' % (window.name, plgen.cn(window.klass), parent, id, style)) props_buf = plgen.generate_common_properties(window) layout_buf = [] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' layout_buf.append('$self->{%s}->%s($self->{%s}, $self->{%s}, %s);\n' % (window.name, f_name, win_1, win_2, sash_pos)) else: def add_sub(win): layout_buf.append('$self->{%s}->SetSplitMode(%s);\n' % (window.name, orientation)) layout_buf.append('$self->{%s}->Initialize($self->{%s});\n' % (window.name, win)) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return init, props_buf, layout_buf def get_layout_code(self, obj): plgen = common.code_writers['perl'] props_buf = [] prop = obj.properties orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') win_1 = prop.get('window_1') win_2 = prop.get('window_2') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' props_buf.append('$self->%s($self->{%s}, $self->{%s}, %s);\n' % (f_name, win_1, win_2, sash_pos)) else: def add_sub(win): props_buf.append('$self->SetSplitMode(%s);\n' % orientation) props_buf.append('$self->Initialize($self->{%s});\n' % win) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return props_buf # end of class PerlCodeGenerator def initialize(): common.class_names['EditSplitterWindow'] = 'wxSplitterWindow' common.class_names['SplitterPane'] = 'wxPanel' common.toplevels['EditSplitterWindow'] = 1 common.toplevels['SplitterPane'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxSplitterWindow', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/lisp_codegen.py0000644000175000017500000000777610743421035025510 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxSplitterWindow objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:47 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: #wxSplitterWindow( parent, id, pos , size , style , name ) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, window): plgen = common.code_writers['lisp'] prop = window.properties id_name, id = plgen.generate_code_id(window) if not window.parent.is_toplevel: parent = '(slot-%s obj)' % window.parent.name else: parent = '(slot-top-window obj)' if window.is_toplevel: l = [] if id_name: l.append(id_name) l.append('(setf (slot-%s obj) (wxSplitterWindow_Create %s %s))\n' % (window.name, parent,id)) return l, [], [] style = prop.get("style") if not( style and style != 'wxSP_3D' ): # default style style = '' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxSplitterWindow_Create %s %s -1 -1 -1 -1 %s))\n' % (window.name, parent, id, style)) props_buf = plgen.generate_common_properties(window) layout_buf = [] win_1 = prop.get('window_1') win_2 = prop.get('window_2') orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' layout_buf.append('(%s %s %s %s %s)\n' % (f_name, window.name, win_1, win_2, sash_pos)) else: def add_sub(win): layout_buf.append('(wxSplitterWindow_SetSplitMode (slot-%s obj) %s)\n' % (window.name, orientation)) layout_buf.append('(wxSplitterWindow_Initialize (slot-%s obj) %s)\n' % (window.name, win)) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return init, props_buf, layout_buf def get_layout_code(self, obj): plgen = common.code_writers['lisp'] props_buf = [] prop = obj.properties orientation = prop.get('orientation', 'wxSPLIT_VERTICAL') win_1 = prop.get('window_1') win_2 = prop.get('window_2') if win_1 and win_2: sash_pos = prop.get('sash_pos', '') if orientation == 'wxSPLIT_VERTICAL': f_name = 'SplitVertically' else: f_name = 'SplitHorizontally' props_buf.append('$self->%s($self->{%s}, $self->{%s}, %s);\n' % (f_name, win_1, win_2, sash_pos)) else: def add_sub(win): props_buf.append('(wxSplitterWindow_SetSplitMode (slot-%s obj) %s)\n' % (obj.name,orientation)) props_buf.append('(wxSplitterWindow_Initialize (slot-%s obj) %s)\n' % (obj.name,win)) if win_1: add_sub(win_1) elif win_2: add_sub(win_2) return props_buf # end of class LispCodeGenerator def initialize(): common.class_names['EditSplitterWindow'] = 'wxSplitterWindow' common.class_names['SplitterPane'] = 'wxPanel' common.toplevels['EditSplitterWindow'] = 1 common.toplevels['SplitterPane'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxSplitterWindow', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/splitter_window/__init__.py0000644000175000017500000000067710743421035024605 0ustar stanistani# __init__.py: splitter window widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import splitter_window return splitter_window.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/codegen.py0000644000175000017500000000451210743421035022275 0ustar stanistani# codegen.py: code generator functions for wxGauge objects # $Id: codegen.py,v 1.10 2007/03/27 07:01:59 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) g_range = prop.get('range', '10') if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style and style != 'wxGA_HORIZONTAL': style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, g_range, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxGauge objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] g_range = prop.get('range', '10') if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style and style != 'wxGA_HORIZONTAL': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, g_range, extra)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditGauge'] = 'wxGauge' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxGauge', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxGauge', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/perl_codegen.py0000644000175000017500000000257310743421035023324 0ustar stanistani# perl_codegen.py : perl generator functions for wxGauge objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:38:14 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) g_range = prop.get('range', '10') if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style : style = '' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, g_range, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditGauge'] = 'wxGauge' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxGauge', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/lisp_codegen.py0000644000175000017500000000261610743421035023327 0ustar stanistani# perl_codegen.py : perl generator functions for wxGauge objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:38 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) g_range = prop.get('range', '10') if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxGauge_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, g_range, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditGauge'] = 'wxGauge' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxGauge', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/__init__.py0000644000175000017500000000064110743421035022427 0ustar stanistani# __init__.py: gauge widget module initialization # $Id: __init__.py,v 1.6 2007/03/27 07:01:59 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import gauge return gauge.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/gauge/gauge.py0000644000175000017500000001547310743421035021771 0ustar stanistani# gauge.py: wxGauge objects # $Id: gauge.py,v 1.12 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditGauge(ManagedBase): def __init__(self, name, parent, id, style, sizer, pos, property_window, show=True): """\ Class to handle wxGauge objects """ ManagedBase.__init__(self, name, 'wxGauge', parent, id, sizer, pos, property_window, show=show) self.style = style self.range = 10 prop = self.properties self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['range'] = (self.get_range, self.set_range) style_labels = ('#section#' + _('Style'), 'wxGA_HORIZONTAL', 'wxGA_VERTICAL', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH') self.style_pos = (wx.GA_HORIZONTAL, wx.GA_VERTICAL, wx.GA_PROGRESSBAR, wx.GA_SMOOTH) self.tooltips = (_("Creates a horizontal gauge."), _("Creates a vertical gauge."), _("Under Windows 95, creates a horizontal progress bar."), _("Creates smooth progress bar with one pixel wide update step (not supported by all platforms).")) prop['style'] = CheckListProperty(self, 'style', None, style_labels,tooltips=self.tooltips) prop['range'] = SpinProperty(self, 'range', None, label=_("range")) def create_widget(self): self.widget = wx.Gauge(self.parent.widget, self.id, self.range, style=self.style) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop = self.properties szr = wx.BoxSizer(wx.VERTICAL) prop['range'].display(panel) prop['style'].display(panel) szr.Add(prop['range'].panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_range(self): return self.range def set_range(self, val): self.range = int(val) self.properties['range'].set_value(self.range) if self.widget: self.widget.SetRange(self.range) # end of class EditGauge def builder(parent, sizer, pos, number=[1]): """\ factory function for EditStaticLine objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select style')) self.orientations = [ wx.GA_HORIZONTAL, wx.GA_VERTICAL ] self.orientation = wx.GA_HORIZONTAL prop = RadioProperty(self, 'orientation', self, ['wxGA_HORIZONTAL', 'wxGA_VERTICAL'], label=_("orientation")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop.panel, 0, wx.ALL|wx.EXPAND, 10) style_labels = ('#section#', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH') self.style_pos = (wx.GA_PROGRESSBAR, wx.GA_SMOOTH) self.style = 0 self.style_prop = CheckListProperty(self, 'style', self, style_labels) szr.Add(self.style_prop.panel, 0, wx.ALL|wx.EXPAND, 10) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.BOTTOM|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, value): if value == 'orientation': def set_orientation(o): self.orientation = self.orientations[o] return (lambda: self.orientation, set_orientation) else: return (self.get_style, self.set_style) def get_style(self): retval = [0] * len(self.style_pos) try: style = self.style for i in range(len(self.style_pos)): if style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.style_prop.prepare_value(value) style = 0 for v in range(len(value)): if value[v]: style |= self.style_pos[v] self.style = style # end of inner class dialog = Dialog() dialog.ShowModal() label = 'gauge_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'gauge_%d' % number[0] gauge = EditGauge(label, parent, wx.NewId(), dialog.orientation | dialog.style, sizer, pos, common.property_panel) node = Tree.Node(gauge) gauge.node = node gauge.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditGauge objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") style = 0 if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") gauge = EditGauge(name, parent, wx.NewId(), style, sizer, pos, common.property_panel) sizer.set_item(gauge.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(gauge) gauge.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return gauge def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditGauge'] = builder common.widgets_from_xml['EditGauge'] = xml_builder return common.make_object_button('EditGauge', 'icons/gauge.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/codegen.py0000644000175000017500000000473410743421035023001 0ustar stanistani# codegen.py: code generator functions for wxCheckBox objects # $Id: codegen.py,v 1.13 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % style else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, label, style)) props_buf = pygen.generate_common_properties(obj) checked = prop.get('checked') if checked: props_buf.append('self.%s.SetValue(1)\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxCheckBox objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] label = cppgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, label, extra) ] props_buf = cppgen.generate_common_properties(obj) checked = prop.get('checked') if checked: props_buf.append('%s->SetValue(1);\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditCheckBox'] = 'wxCheckBox' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxCheckBox', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxCheckBox', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/checkbox.py0000644000175000017500000001133510743421035023156 0ustar stanistani# checkbox.py: wxCheckBox objects # $Id: checkbox.py,v 1.14 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditCheckBox(ManagedBase): events = ['EVT_CHECKBOX'] def __init__(self, name, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxCheckBox objects """ import config ManagedBase.__init__(self, name, 'wxCheckBox', parent, id, sizer, pos, property_window, show=show) self.label = label self.value = 0 # if nonzero, che checkbox is checked self.access_functions['label'] = (self.get_label, self.set_label) self.access_functions['checked'] = (self.get_value, self.set_value) self.properties['label'] = TextProperty(self, 'label', None, multiline=True, label=_("label")) self.properties['checked'] = CheckBoxProperty(self, 'checked', None, _('Checked')) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wx.CheckBox(self.parent.widget, self.id, self.label) self.widget.SetValue(self.value) def on_checkbox(event): self.set_value(self.value) wx.EVT_CHECKBOX(self.widget, self.id, on_checkbox) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) self.properties['label'].display(panel) self.properties['checked'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['checked'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_label(self): return self.label def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): self.label = value if self.widget: self.widget.SetLabel(value.replace('\\n', '\n')) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_value(self): return self.value def set_value(self, value): self.value = int(value) if self.widget: self.widget.SetValue(self.value) self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) # end of class EditCheckBox def builder(parent, sizer, pos, number=[1]): """\ factory function for EditCheckBox objects. """ label = 'checkbox_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'checkbox_%d' % number[0] checkbox = EditCheckBox(label, parent, wx.NewId(), label, sizer, pos, common.property_panel) node = Tree.Node(checkbox) checkbox.node = node checkbox.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditCheckBox objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") checkbox = EditCheckBox(label, parent, wx.NewId(), "", sizer, pos, common.property_panel, show=False) sizer.set_item(checkbox.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) #, ## size=checkbox.GetBestSize()) node = Tree.Node(checkbox) checkbox.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return checkbox def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditCheckBox'] = builder common.widgets_from_xml['EditCheckBox'] = xml_builder return common.make_object_button('EditCheckBox', 'icons/checkbox.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/perl_codegen.py0000644000175000017500000000300410743421035024010 0ustar stanistani# perl_codegen.py : perl generator functions for wxCheckBox objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:35:44 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = '' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s, \ wxDefaultPosition, wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) checked = prop.get('checked') if checked: props_buf.append('$self->{%s}->SetValue(1);\n' % obj.name) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditCheckBox'] = 'wxCheckBox' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxCheckBox', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/lisp_codegen.py0000644000175000017500000000325710743421035024027 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxCheckBox objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:58:25 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('(setf (slot-%s obj) (wxCheckBox_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) checked = prop.get('checked') if checked: props_buf.append('(wxCheckBox_SetValue (slot-%s obj) 1);\n' % obj.name) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditCheckBox'] = 'wxCheckBox' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxCheckBox', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/checkbox/__init__.py0000644000175000017500000000065210743421035023127 0ustar stanistani# __init__.py: checkbox widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:03 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import checkbox return checkbox.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/codegen.py0000644000175000017500000004021210743421035022633 0ustar stanistani# codegen.py: code generator functions for wxMenuBar objects # $Id: codegen.py,v 1.21 2007/03/27 07:01:57 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * class PythonCodeGenerator: def get_properties_code(self, obj): return [] def get_init_code(self, obj): prop = obj.properties pygen = common.code_writers['python'] cn = pygen.cn out = [] append = out.append menus = obj.properties['menubar'] ids = [] def append_items(menu, items): for item in items: if item.name == '---': # item is a separator append('%s.AppendSeparator()\n' % menu) continue name, val = pygen.generate_code_id(None, item.id) if obj.preview or (not name and ( not val or val == '-1')): id = cn('wxNewId()') else: if name: ids.append(name) id = val if item.children: if item.name: name = item.name else: name = '%s_sub' % menu append(('%s = ' + cn('wxMenu') + '()\n') % name) ## if not obj.preview and item.id: # generating id ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## ids.append(' = '.join(tokens) + '\n') ## else: ## id = item.id ## else: id = 'wxNewId()' append_items(name, item.children) append('%s.AppendMenu(%s, %s, %s, %s)\n' % (menu, id, pygen.quote_str(item.label), name, pygen.quote_str(item.help_str))) else: ## if not obj.preview and item.id: # no ids for preview ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## ids.append(' = '.join(tokens) + '\n') ## else: ## id = item.id ## else: id = 'wxNewId()' item_type = cn('wxITEM_NORMAL') if item.checkable == '1': item_type = cn('wxITEM_CHECK') elif item.radio == '1': item_type = cn('wxITEM_RADIO') if item.name: # ALB 2004-18-07 name = 'self.%s' % item.name if item_type: append('%s = %s(%s, %s, %s, %s, %s)\n' % (name, cn('wxMenuItem'), menu, id, pygen.quote_str(item.label), pygen.quote_str(item.help_str), item_type)) else: append('%s = %s(%s, %s, %s, %s)\n' % (name, cn('wxMenuItem'), menu, id, pygen.quote_str(item.label), pygen.quote_str(item.help_str))) append('%s.AppendItem(%s)\n' % (menu, name)) else: if item_type: append('%s.Append(%s, %s, %s, %s)\n' % (menu, id, pygen.quote_str(item.label), pygen.quote_str(item.help_str), item_type)) else: append('%s.Append(%s, %s, %s)\n' % (menu, id, pygen.quote_str(item.label), pygen.quote_str(item.help_str))) #print 'menus = %s' % menus if obj.is_toplevel: obj_name = 'self' else: obj_name = 'self.' + obj.name for m in menus: menu = m.root if menu.name: name = 'self.' + menu.name else: name = 'wxglade_tmp_menu' append(('%s = ' + cn('wxMenu') + '()\n') % name) if menu.children: append_items(name, menu.children) append('%s.Append(%s, %s)\n' % (obj_name, name, pygen.quote_str(menu.label))) return ids + out def get_code(self, obj): """\ function that generates Python code for the menubar of a wxFrame. """ pygen = common.code_writers['python'] if obj.klass == obj.base: klass = pygen.cn(obj.klass) else: klass = obj.klass init = [ '\n', '# Menu Bar\n', 'self.%s = %s()\n' % (obj.name, klass) ] ## 'self.SetMenuBar(self.%s)\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append('self.SetMenuBar(self.%s)\n' % obj.name) init.append('# Menu Bar end\n') return init, [], [] # 2004-12-05 def get_events(self, obj): pygen = common.code_writers['python'] cn = pygen.cn out = [] #print 'get_events', obj.properties['menubar'] def do_get(item): ret = [] if item.name and pygen.for_version > (2, 4): val = '#self.%s' % item.name # see py_codegen.py, ~480 else: name, val = pygen.generate_code_id(None, item.id) if not val: val = '-1' # but this is wrong anyway... if item.handler: ret.append((val, 'EVT_MENU', item.handler)) if item.children: for c in item.children: ret.extend(do_get(c)) return ret for menu in obj.properties['menubar']: out.extend(do_get(menu.root)) return out # end of class PythonCodeGenerator class MenuHandler: """Handler for menus and menu items of a menubar""" item_attrs = ('label', 'id', 'name', 'help_str', 'checkable', 'radio', 'handler') def __init__(self): self.menu_depth = 0 self.menus = [] self.curr_menu = None self.curr_item = None self.attr_val = [] def start_elem(self, name, attrs): if name == 'menu': self.menu_depth += 1 label = attrs['label'] if self.menu_depth == 1: t = MenuTree(attrs['name'], label) self.curr_menu = t.root self.menus.append(t) return id = attrs.get('itemid', '') handler = attrs.get('handler', '') node = MenuTree.Node(label=label, name=attrs['name'], id=id, handler=handler) node.parent = self.curr_menu self.curr_menu.children.append(node) self.curr_menu = node elif name == 'item': self.curr_item = MenuTree.Node() def end_elem(self, name, code_obj): if name == 'menus': code_obj.properties['menubar'] = self.menus return True if name == 'item' and self.curr_menu: self.curr_menu.children.append(self.curr_item) self.curr_item.parent = self.curr_menu elif name == 'menu': self.menu_depth -= 1 self.curr_menu = self.curr_menu.parent elif name in self.item_attrs: setattr(self.curr_item, name, "".join(self.attr_val)) self.attr_val = [] def char_data(self, data): self.attr_val.append(data) # end of class MenuHandler def xrc_code_generator(obj): """\ function that generates XRC code for the menubar of a wxFrame. """ from xml.sax.saxutils import escape, quoteattr xrcgen = common.code_writers['XRC'] class MenuBarXrcObject(xrcgen.DefaultXrcObject): def append_item(self, item, outfile, tabs): write = outfile.write if item.name == '---': # item is a separator write(' '*tabs + '\n') else: if item.children: name = self.get_name(item) if name: write(' '*tabs + '\n' % quoteattr(name)) else: write(' '*tabs + '\n') else: name = self.get_name(item) if name: write(' '*tabs + '\n' % quoteattr(name)) else: write(' '*tabs + '\n') if item.label: # translate & into _ as accelerator marker val = item.label.replace('&', '_') write(' '*(tabs+1) + '\n' % \ escape(val)) if item.help_str: write(' '*(tabs+1) + '%s\n' % \ escape(item.help_str)) if item.children: for c in item.children: self.append_item(c, outfile, tabs+1) elif item.checkable == '1': write(' '*(tabs+1) + '1\n') elif item.radio == '1': write(' '*(tabs+1) + '1\n') write(' '*tabs + '\n') def get_name(self, item): if item.name: return item.name.strip() tokens = item.id.split('=') if tokens: return tokens[0].strip() def write(self, outfile, tabs): menus = self.code_obj.properties['menubar'] write = outfile.write write(' '*tabs + '\n' % \ quoteattr(self.name)) for m in menus: self.append_item(m.root, outfile, tabs+1) write(' '*tabs + '\n') # end of class MenuBarXrcObject return MenuBarXrcObject(obj) class CppCodeGenerator: constructor = [] def get_code(self, obj): """\ generates C++ code for the menubar of a wxFrame. """ cppgen = common.code_writers['C++'] menus = obj.properties['menubar'] init = [ '%s = new %s();\n' % (obj.name, obj.klass) ] init.extend(self.get_properties_code(obj)) init.append('SetMenuBar(%s);\n' % obj.name) ids = self.get_ids_code(obj) return init, ids, [], [] def get_properties_code(self, obj): cppgen = common.code_writers['C++'] menus = obj.properties['menubar'] out = [] append = out.append def append_items(menu, items): for item in items: if item.name == '---': # item is a separator append('%s->AppendSeparator();\n' % menu) continue name, val = cppgen.generate_code_id(None, item.id) if not name and val == '-1': id = 'wxNewId()' else: #if name: ids.append(name) id = val if item.children: if item.name: name = item.name else: name = '%s_sub' % menu append('wxMenu* %s = new wxMenu();\n' % name) ## if item.id: # generating id ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## else: ## id = item.id ## else: id = 'wxNewId()' append_items(name, item.children) append('%s->Append(%s, %s, %s, %s);\n' % (menu, id, cppgen.quote_str(item.label), name, cppgen.quote_str(item.help_str))) else: ## if item.id: ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## else: ## id = item.id ## else: ## id = 'wxNewId()' item_type = 'wxITEM_NORMAL' if item.checkable == '1': item_type = 'wxITEM_CHECK' elif item.radio == '1': item_type = 'wxITEM_RADIO' if item_type: append('%s->Append(%s, %s, %s, %s);\n' % (menu, id, cppgen.quote_str(item.label), cppgen.quote_str(item.help_str), item_type)) else: append('%s->Append(%s, %s, %s);\n' % (menu, id, cppgen.quote_str(item.label), cppgen.quote_str(item.help_str))) #print 'menus = %s' % menus if obj.is_toplevel: obj_name = '' else: obj_name = obj.name + '->' i = 1 for m in menus: menu = m.root if menu.name: name = menu.name else: name = 'wxglade_tmp_menu_%s' % i i += 1 append('wxMenu* %s = new wxMenu();\n' % name) if menu.children: append_items(name, menu.children) append('%sAppend(%s, %s);\n' % (obj_name, name, cppgen.quote_str(menu.label))) return out def get_ids_code(self, obj): cppgen = common.code_writers['C++'] ids = [] menus = obj.properties['menubar'] def collect_ids(items): for item in items: if item.name == '---': # item is a separator continue # do nothing name, val = cppgen.generate_code_id(None, item.id) if name.find('=') != -1: ids.append(name) if item.children: ## if item.id: # generating id ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## ids.append(' = '.join(tokens)) collect_ids(item.children) ## else: ## if item.id: ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## ids.append(' = '.join(tokens)) for m in menus: if m.root.children: collect_ids(m.root.children) return ids def get_events(self, obj): cppgen = common.code_writers['C++'] out = [] def do_get(item): ret = [] name, val = cppgen.generate_code_id(None, item.id) if not val: val = '-1' # but this is wrong anyway... if item.handler: ret.append((val, 'EVT_MENU', item.handler, 'wxCommandEvent')) if item.children: for c in item.children: ret.extend(do_get(c)) return ret for menu in obj.properties['menubar']: out.extend(do_get(menu.root)) return out # end of class CppCodeGenerator def initialize(): common.class_names['EditMenuBar'] = 'wxMenuBar' common.toplevels['EditMenuBar'] = 1 pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxMenuBar', PythonCodeGenerator()) pygen.add_property_handler('menus', MenuHandler) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxMenuBar', xrc_code_generator) xrcgen.add_property_handler('menus', MenuHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxMenuBar', CppCodeGenerator()) cppgen.add_property_handler('menus', MenuHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/perl_codegen.py0000644000175000017500000001213110743421035023654 0ustar stanistani# perl_codegen.py : perl generator functions for wxMenuBar objects # $Id: perl_codegen.py,v 1.11 2007/06/23 10:57:58 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * from codegen import MenuHandler class PerlCodeGenerator: def get_properties_code(self, obj): return [] def get_init_code(self, obj): prop = obj.properties plgen = common.code_writers['perl'] out = [] append = out.append menus = obj.properties['menubar'] ids = [] # We need to keep track of tmpnames used. tmpsused = {} def append_items(menu, items): for item in items: if item.name == '---': # item is a separator append('%s->AppendSeparator();\n' % menu) continue name, val = plgen.generate_code_id(None, item.id) if not name and ( not val or val == '-1'): id = 'Wx::NewId()' else: if name: ids.append(name) id = val if item.children: if item.name: name = item.name else: name = '%s_sub' % menu if not tmpsused.has_key(name): tmpsused[name] = 1 append('my %s;\n' % name) append('%s = Wx::Menu->new();\n' % name) append_items(name, item.children) append('%s->Append(%s, %s, %s, %s);\n' % (menu, id, plgen.quote_str(item.label), name, plgen.quote_str(item.help_str))) else: item_type = 0 if item.checkable == '1': item_type = 1 elif item.radio == '1': item_type = 2 if item.name: itemname = '$self->{%s} = ' % item.name else: itemname = '' if item_type: append('%s%s->Append(%s, %s, %s, %s);\n' % (itemname, menu, id, plgen.quote_str(item.label), plgen.quote_str(item.help_str), item_type)) else: append('%s%s->Append(%s, %s, %s);\n' % (itemname, menu, id, plgen.quote_str(item.label), plgen.quote_str(item.help_str))) #print 'menus = %s' % menus if obj.is_toplevel: obj_name = '$self' else: obj_name = '$self->{%s}' % obj.name append('my $wxglade_tmp_menu;\n') # NOTE below name = for m in menus: menu = m.root if menu.name: name = '$self->{%s}' % menu.name else: name = '$wxglade_tmp_menu' append('%s = Wx::Menu->new();\n' % name) if menu.children: append_items(name, menu.children) append('%s->Append(%s, %s);\n' % (obj_name, name, plgen.quote_str(menu.label))) return ids + out def get_code(self, obj): """\ function that generates Perl code for the menubar of a wxFrame. """ klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); plgen = common.code_writers['perl'] init = [ '\n\n', '# Menu Bar\n\n', '$self->{%s} = %s->new();\n' % (obj.name, klass) ] ## '$self->SetMenuBar($self->{%s});\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append('$self->SetMenuBar($self->{%s});\n' % obj.name) init.append('\n# Menu Bar end\n\n') return init, [], [] # 2004-12-05 def get_events(self, obj): pygen = common.code_writers['perl'] cn = pygen.cn out = [] #print 'get_events', obj.properties['menubar'] def do_get(item): ret = [] if item.name: #val = '#self.%s' % item.name # see py_codegen.py, ~480 val = item.name else: name, val = pygen.generate_code_id(None, item.id) if not val: val = '-1' # but this is wrong anyway... if item.handler: ret.append((val, 'EVT_MENU', item.handler)) if item.children: for c in item.children: ret.extend(do_get(c)) return ret for menu in obj.properties['menubar']: out.extend(do_get(menu.root)) return out # end of class PerlCodeGenerator def initialize(): common.class_names['EditMenuBar'] = 'wxMenuBar' common.toplevels['EditMenuBar'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxMenuBar', PerlCodeGenerator()) plgen.add_property_handler('menus', MenuHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/lisp_codegen.py0000644000175000017500000000711410743421035023666 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxMenuBar objects # $Id: lisp_codegen.py,v 1.2 2005/09/25 08:23:37 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * from codegen import MenuHandler class LispCodeGenerator: def get_properties_code(self, obj): return [] def get_init_code(self, obj): prop = obj.properties plgen = common.code_writers['lisp'] out = [] append = out.append menus = obj.properties['menubar'] ids = [] def append_items(menu, items): for item in items: if item.name == '---': # item is a separator append('(wxMenu_AppendSeparator %s)\n' % menu) continue name, val = plgen.generate_code_id(None, item.id) if not name and ( not val or val == '-1'): id = '-1' else: if name: ids.append(name) id = val if item.children: if item.name: name = item.name else: name = '%s_sub' % menu append('(let ((%s (wxMenu_Create "" 0)))\n' % name) append_items(name, item.children) append('(wxMenuBar_AppendSub %s %s %s %s %s))\n' % (menu, id, plgen.quote_str(item.label), name, plgen.quote_str(item.help_str))) else: item_type = 0 if item.checkable == '1': item_type = 1 elif item.radio == '1': item_type = 2 append('(wxMenu_Append %s %s %s %s %s)\n' % (menu, id, plgen.quote_str(item.label), plgen.quote_str(item.help_str), item_type)) #print 'menus = %s' % menus # if obj.is_toplevel: obj_name = '$self' # else: obj_name = '$self->{%s}' % obj.name # append('my $wxglade_tmp_menu;\n') # NOTE below name = for m in menus: menu = m.root if menu.name: name = menu.name else: name = 'wxglade_tmp_menu' append('(let ((%s (wxMenu_Create "" 0)))\n' % name) if menu.children: append_items(name, menu.children) append('\t\t(wxMenuBar_Append (slot-%s obj) %s %s))\n' % (obj.name, name, plgen.quote_str(menu.label))) return ids + out def get_code(self, obj): """\ function that generates Lisp code for the menubar of a wxFrame. """ plgen = common.code_writers['lisp'] init = [ '\n', ';;; Menu Bar\n', '(setf (slot-%s obj) (wxMenuBar_Create 0))\n' % (obj.name) ] ## '(wxFrame_SetMenuBar (slot-top-window obj) (slot-%s obj))\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append('(wxFrame_SetMenuBar (slot-top-window obj) ' \ '(slot-%s obj))\n' % obj.name) init.append(';;; Menu Bar end\n\n') return init, [], [] # end of class LispCodeGenerator def initialize(): common.class_names['EditMenuBar'] = 'wxMenuBar' common.toplevels['EditMenuBar'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxMenuBar', LispCodeGenerator()) plgen.add_property_handler('menus', MenuHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/__init__.py0000644000175000017500000000074510743421035022775 0ustar stanistani# __init__.py: menubar widget module initialization # $Id: __init__.py,v 1.5 2007/03/27 07:01:57 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import menubar global EditMenuBar; EditMenuBar = menubar.EditMenuBar return menubar.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/menubar/menubar.py0000644000175000017500000010363610743421035022672 0ustar stanistani# menubar.py: wxMenuBar objects # $Id: menubar.py,v 1.28 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, math, misc from tree import Tree from MenuTree import * from widget_properties import * from edit_windows import EditBase, TopLevelBase, PreviewMixin class MenuItemDialog(wx.Dialog): def __init__(self, parent, owner, items=None): wx.Dialog.__init__(self, parent, -1, _("Menu editor"), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) ADD_ID, REMOVE_ID, NAME_ID, LABEL_ID, ID_ID, CHECK_RADIO_ID, LIST_ID, \ ADD_SEP_ID, MOVE_LEFT_ID, MOVE_RIGHT_ID, MOVE_UP_ID, \ MOVE_DOWN_ID, HELP_STR_ID = [wx.NewId() for i in range(13)] self._staticbox = wx.StaticBox(self, -1, _("Menu item:")) self.owner = owner self.menu_items = wx.ListCtrl(self, LIST_ID, style=wx.LC_REPORT | \ wx.LC_SINGLE_SEL|wx.SUNKEN_BORDER) # ALB 2004-09-26: workaround to make the scroll wheel work... wx.EVT_MOUSEWHEEL(self.menu_items, lambda e: e.Skip()) self.menu_items.InsertColumn(0, _("Label")) self.menu_items.InsertColumn(1, _("Id")) self.menu_items.InsertColumn(2, _("Name")) self.menu_items.InsertColumn(3, _("Help String")) self.menu_items.InsertColumn(4, _("Type")) # ALB 2004-12-05 self.menu_items.InsertColumn(5, _("Event Handler")) self.menu_items.SetColumnWidth(0, 250) self.menu_items.SetColumnWidth(2, 250) self.menu_items.SetColumnWidth(3, 250) self.menu_items.SetColumnWidth(5, 250) # menu item fields self.id = wx.TextCtrl(self, ID_ID) self.label = wx.TextCtrl(self, LABEL_ID) self.name = wx.TextCtrl(self, NAME_ID) self.help_str = wx.TextCtrl(self, HELP_STR_ID) # ALB 2004-12-05 self.event_handler = wx.TextCtrl(self, -1) import re self.handler_re = re.compile(r'^\s*\w*\s*$') #self.checkable = wx.CheckBox(self, CHECK_ID, "") #Checkable") self.check_radio = wx.RadioBox( self, CHECK_RADIO_ID, _("Type"), choices=['Normal', 'Checkable', 'Radio'], majorDimension=3) self.add = wx.Button(self, ADD_ID, _("Add")) self.remove = wx.Button(self, REMOVE_ID, _("Remove")) self.add_sep = wx.Button(self, ADD_SEP_ID, _("Add separator")) # menu items navigation self.move_up = wx.Button(self, MOVE_UP_ID, _("Up")) self.move_down = wx.Button(self, MOVE_DOWN_ID, _("Down")) self.move_left = wx.Button(self, MOVE_LEFT_ID, " < ") self.move_right = wx.Button(self, MOVE_RIGHT_ID, " > ") self.ok = wx.Button(self, wx.ID_OK, _("OK")) self.apply = wx.Button(self, wx.ID_APPLY, _("Apply")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.do_layout() self.selected_index = -1 # index of the selected element in the # wx.ListCtrl menu_items # event handlers wx.EVT_BUTTON(self, ADD_ID, self.add_menu_item) wx.EVT_BUTTON(self, REMOVE_ID, self.remove_menu_item) wx.EVT_BUTTON(self, ADD_SEP_ID, self.add_separator) wx.EVT_BUTTON(self, MOVE_LEFT_ID, self.move_item_left) wx.EVT_BUTTON(self, MOVE_RIGHT_ID, self.move_item_right) wx.EVT_BUTTON(self, MOVE_UP_ID, self.move_item_up) wx.EVT_BUTTON(self, MOVE_DOWN_ID, self.move_item_down) wx.EVT_BUTTON(self, wx.ID_APPLY, self.on_apply) wx.EVT_KILL_FOCUS(self.name, self.update_menu_item) wx.EVT_KILL_FOCUS(self.label, self.update_menu_item) wx.EVT_KILL_FOCUS(self.id, self.update_menu_item) wx.EVT_KILL_FOCUS(self.help_str, self.update_menu_item) # ALB 2004-12-05 wx.EVT_KILL_FOCUS(self.event_handler, self.update_menu_item) #wx.EVT_CHECKBOX(self, CHECK_ID, self.update_menu_item) wx.EVT_RADIOBOX(self, CHECK_RADIO_ID, self.update_menu_item) wx.EVT_LIST_ITEM_SELECTED(self, LIST_ID, self.show_menu_item) if items: self.add_items(items) def do_layout(self): self.label.Enable(False) self.id.Enable(False) self.name.Enable(False) self.help_str.Enable(False) self.event_handler.Enable(False) self.check_radio.Enable(False) sizer = wx.BoxSizer(wx.VERTICAL) sizer2 = wx.StaticBoxSizer(self._staticbox, wx.VERTICAL) self.label.SetSize((150, -1)) self.id.SetSize((150, -1)) self.name.SetSize((150, -1)) self.help_str.SetSize((150, -1)) self.event_handler.SetSize((150, -1)) szr = wx.FlexGridSizer(0, 2) if misc.check_wx_version(2, 5, 2): flag = wx.FIXED_MINSIZE else: flag = 0 label_flag = wx.ALIGN_CENTER_VERTICAL szr.Add(wx.StaticText(self, -1, _("Id ")), flag=label_flag) szr.Add(self.id, flag=flag) szr.Add(wx.StaticText(self, -1, _("Label ")), flag=label_flag) szr.Add(self.label, flag=flag) szr.Add(wx.StaticText(self, -1, _("Name ")), flag=label_flag) szr.Add(self.name, flag=flag) szr.Add(wx.StaticText(self, -1, _("Help String ")), flag=label_flag) szr.Add(self.help_str, flag=flag) szr.Add(wx.StaticText(self, -1, _("Event Handler ")), flag=label_flag) szr.Add(self.event_handler, flag=flag) sizer2.Add(szr, 1, wx.ALL|wx.EXPAND, 5) sizer2.Add(self.check_radio, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 4) szr = wx.GridSizer(0, 2, 3, 3) szr.Add(self.add, 0, wx.EXPAND); szr.Add(self.remove, 0, wx.EXPAND) sizer2.Add(szr, 0, wx.EXPAND) sizer2.Add(self.add_sep, 0, wx.TOP|wx.EXPAND, 3) sizer3 = wx.BoxSizer(wx.VERTICAL) sizer3.Add(self.menu_items, 1, wx.ALL|wx.EXPAND, 5) sizer4 = wx.BoxSizer(wx.HORIZONTAL) sizer4.Add(self.move_up, 0, wx.LEFT|wx.RIGHT, 3) sizer4.Add(self.move_down, 0, wx.LEFT|wx.RIGHT, 5) sizer4.Add(self.move_left, 0, wx.LEFT|wx.RIGHT, 5) sizer4.Add(self.move_right, 0, wx.LEFT|wx.RIGHT, 5) sizer3.Add(sizer4, 0, wx.ALIGN_CENTER|wx.ALL, 5) szr = wx.BoxSizer(wx.HORIZONTAL) szr.Add(sizer3, 1, wx.ALL|wx.EXPAND, 5) szr.Add(sizer2, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 5) sizer.Add(szr, 1, wx.EXPAND) sizer2 = wx.BoxSizer(wx.HORIZONTAL) sizer2.Add(self.ok, 0, wx.ALL, 5) sizer2.Add(self.apply, 0, wx.ALL, 5) sizer2.Add(self.cancel, 0, wx.ALL, 5) sizer.Add(sizer2, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(1) self.SetSizer(sizer) sizer.Fit(self) self.SetSize((-1, 350)) self.CenterOnScreen() def _enable_fields(self, enable=True): for s in (self.label, self.id, self.name, self.help_str, self.check_radio, self.event_handler): s.Enable(enable) def add_menu_item(self, event): """\ Event handler called when the Add button is clicked """ index = self.selected_index = self.selected_index+1 if not self.menu_items.GetItemCount(): self._enable_fields() ## for s in (self.label, self.id, self.name, self.help_str, ## self.check_radio, self.event_handler): ## s.Enable(True) if index < 0: index = self.menu_items.GetItemCount() elif index > 0: indent = " " * self.item_level(index-1) else: indent = "" name, label, id, check_radio = "", "item", "", "0" self.menu_items.InsertStringItem(index, indent + label) self.menu_items.SetStringItem(index, 1, id) self.menu_items.SetStringItem(index, 2, name) self.menu_items.SetStringItem(index, 4, check_radio) # fix bug 698074 self.menu_items.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) self.name.SetValue(name) self.label.SetValue(label) self.id.SetValue(id) self.check_radio.SetSelection(int(check_radio)) self.event_handler.SetValue("") def add_separator(self, event): """\ Event handler called when the Add Separator button is clicked """ index = self.selected_index+1 if not self.menu_items.GetItemCount(): self._enable_fields() ## for s in (self.label, self.id, self.name, self.help_str, ## self.check_radio, self.event_handler): ## s.Enable(True) if index < 0: index = self.menu_items.GetItemCount() elif index > 0: label = " " * self.item_level(index-1) + '---' else: label = '---' self.menu_items.InsertStringItem(index, label) self.menu_items.SetStringItem(index, 1, '---') self.menu_items.SetStringItem(index, 2, '---') # fix bug 698074 self.menu_items.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) def show_menu_item(self, event): """\ Event handler called when a menu item in the list is selected """ self.selected_index = index = event.GetIndex() if not misc.streq(self.menu_items.GetItem(index, 2).m_text, '---'): # skip if the selected item is a separator for (s, i) in ((self.label, 0), (self.id, 1), (self.name, 2), (self.help_str, 3), (self.event_handler, 5)): s.SetValue(self.menu_items.GetItem(index, i).m_text) self.label.SetValue(self.label.GetValue().lstrip()) try: self.check_radio.SetSelection( int(self.menu_items.GetItem(index, 4).m_text)) except: self.check_radio.SetSelection(0) event.Skip() def update_menu_item(self, event): """\ Event handler called when some of the properties of the current menu item changes """ set_item = self.menu_items.SetStringItem index = self.selected_index val = self.event_handler.GetValue() if not self.handler_re.match(val): event.GetEventObject().SetFocus() return if index < 0: return event.Skip() set_item(index, 0, " " * self.item_level(index) + \ self.label.GetValue().lstrip()) set_item(index, 1, self.id.GetValue()) set_item(index, 2, self.name.GetValue()) set_item(index, 3, self.help_str.GetValue()) set_item(index, 4, str(self.check_radio.GetSelection())) set_item(index, 5, self.event_handler.GetValue()) event.Skip() def item_level(self, index, label=None): """\ returns the indentation level of the menu item at the given index """ label = self.menu_items.GetItem(index, 0).m_text return (len(label) - len(label.lstrip())) / 4 def remove_menu_item(self, event): """\ Event handler called when the Remove button is clicked """ if self.selected_index >= 0: index = self.selected_index+1 if index < self.menu_items.GetItemCount() and \ (self.item_level(self.selected_index) < self.item_level(index)): self._move_item_left(index) self.selected_index = index-1 for s in (self.name, self.id, self.label, self.help_str, self.event_handler): s.SetValue("") self.check_radio.SetSelection(0) self.menu_items.DeleteItem(self.selected_index) if not self.menu_items.GetItemCount(): self._enable_fields(False) ## for s in (self.name, self.id, self.label, \ ## self.help_str, self.check_radio, self.event_handler): ## s.Enable(False) def add_items(self, menus): """\ adds the content of 'menus' to self.menu_items. menus is a sequence of trees which describes the structure of the menus """ indent = " " * 4 set_item = self.menu_items.SetStringItem add_item = self.menu_items.InsertStringItem index = [0] def add(node, level): i = index[0] add_item(i, misc.wxstr(indent * level + node.label.lstrip())) set_item(i, 1, misc.wxstr(node.id)) set_item(i, 2, misc.wxstr(node.name)) set_item(i, 3, misc.wxstr(node.help_str)) # ALB 2004-12-05 set_item(i, 5, misc.wxstr(node.handler)) item_type = 0 try: if node.checkable and int(node.checkable): item_type = 1 elif int(node.radio): item_type = 2 except ValueError: pass set_item(i, 4, misc.wxstr(item_type)) index[0] += 1 for item in node.children: add(item, level+1) for tree in menus: add(tree.root, 0) if self.menu_items.GetItemCount(): self._enable_fields() ## for s in (self.name, self.id, self.label, \ ## self.help_str, self.check_radio, self.event_handler): ## s.Enable(True) def get_menus(self): """\ returns the contents of self.menu_items as a list of trees which describe the structure of the menus in the format used by EditMenuBar """ def get(i, j): return self.menu_items.GetItem(i, j).m_text trees = [] def add(node, index): label = get(index, 0).lstrip() id = get(index, 1) name = get(index, 2) help_str = get(index, 3) event_handler = get(index, 5) try: item_type = int(get(index, 4)) except ValueError: item_type = 0 checkable = item_type == 1 and misc.wxstr("1") or misc.wxstr("") radio = item_type == 2 and misc.wxstr("1") or misc.wxstr("") n = MenuTree.Node(label, id, name, help_str, checkable, radio, handler=event_handler) node.children.append(n) n.parent = node return n level = 0 curr_item = None for index in range(self.menu_items.GetItemCount()): label = get(index, 0) lvl = self.item_level(index) # get the indentation level if not lvl: t = MenuTree(get(index, 2), label, id=get(index, 1), handler=get(index, 5)) curr_item = t.root level = 1 trees.append(t) continue elif lvl < level: for i in range(level-lvl): curr_item = curr_item.parent level = lvl elif lvl > level: curr_item = curr_item.children[-1] level = lvl add(curr_item, index) return trees def _move_item_left(self, index): if index > 0: if (index+1 < self.menu_items.GetItemCount() and \ (self.item_level(index) < self.item_level(index+1))): return label = self.menu_items.GetItem(index, 0).m_text if misc.streq(label[:4], " " * 4): self.menu_items.SetStringItem(index, 0, label[4:]) self.menu_items.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) def move_item_left(self, event): """\ moves the selected menu item one level up in the hierarchy, i.e. shifts its label 4 spaces left in self.menu_items """ self.menu_items.SetFocus() self._move_item_left(self.selected_index) def _move_item_right(self, index): if index > 0 and (self.item_level(index) <= self.item_level(index-1)): label = self.menu_items.GetItem(index, 0).m_text self.menu_items.SetStringItem(index, 0, misc.wxstr(" " * 4) + label) self.menu_items.SetItemState(index, wx.LIST_STATE_SELECTED, \ wx.LIST_STATE_SELECTED) def move_item_right(self, event): """\ moves the selected menu item one level down in the hierarchy, i.e. shifts its label 4 spaces right in self.menu_items """ self.menu_items.SetFocus() self._move_item_right(self.selected_index) def move_item_up(self, event): """\ moves the selected menu item before the previous one at the same level in self.menu_items """ self.menu_items.SetFocus() index = self._do_move_item(event, self.selected_index, False) if index is not None: state = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED self.menu_items.SetItemState(index, state, state) def _do_move_item(self, event, index, is_down): """\ internal function used by move_item_up and move_item_down. Returns the new index of the moved item, or None if no change occurred """ #index = self.selected_index if index <= 0: return None def get(i, j): return self.menu_items.GetItem(i, j).m_text def getall(i): return [get(i, j) for j in range(6)] level = self.item_level(index) items_to_move = [ getall(index) ] i = index+1 while i < self.menu_items.GetItemCount(): # collect the items to move up if level < self.item_level(i): items_to_move.append(getall(i)) i += 1 else: break i = index-1 while i >= 0: lvl = self.item_level(i) if level == lvl: break elif level > lvl: return None i -= 1 delete = self.menu_items.DeleteItem insert = self.menu_items.InsertStringItem set = self.menu_items.SetStringItem for j in range(len(items_to_move)-1, -1, -1): delete(index+j) items_to_move.reverse() for label, id, name, help_str, check_radio, event_handler in \ items_to_move: i = insert(i, label) set(i, 1, id) set(i, 2, name) set(i, 3, help_str) set(i, 4, check_radio) set(i, 5, event_handler) ret_idx = i if is_down: ret_idx += len(items_to_move) return ret_idx def move_item_down(self, event): """\ moves the selected menu item after the next one at the same level in self.menu_items """ self.menu_items.SetFocus() index = self.selected_index self.selected_index = -1 if index < 0: return def get(i, j): return self.menu_items.GetItem(i, j).m_text def getall(i): return [get(i, j) for j in range(6)] level = self.item_level(index) i = index+1 while i < self.menu_items.GetItemCount(): # collect the items to move down if level < self.item_level(i): i += 1 else: break if i < self.menu_items.GetItemCount(): # _do_move_item works with selected_index, so we must assing to # it the rigth value before the call #self.selected_index = i self.selected_index = self._do_move_item(event, i, True) # fix bug 698071 state = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED self.menu_items.SetItemState(self.selected_index, state, state) else: # restore the selected index self.selected_index = index def on_apply(self, event): self.owner.set_menus(self.get_menus()) common.app_tree.app.saved = False #end of class MenuItemDialog class MenuProperty(Property): """\ Property to edit the menus of an EditMenuBar instance. """ def __init__(self, owner, name, parent): Property.__init__(self, owner, name, parent) self.panel = None self.menu_items = {} if parent is not None: self.display(parent) def display(self, parent): self.panel = wx.Panel(parent, -1) edit_btn_id = wx.NewId() self.edit_btn = wx.Button(self.panel, edit_btn_id, _("Edit menus...")) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.edit_btn, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 4) self.panel.SetAutoLayout(1) self.panel.SetSizer(sizer) self.panel.SetSize(sizer.GetMinSize()) wx.EVT_BUTTON(self.panel, edit_btn_id, self.edit_menus) def bind_event(*args): pass def edit_menus(self, event): dialog = MenuItemDialog(self.panel, self.owner, items=self.owner.get_menus()) if dialog.ShowModal() == wx.ID_OK: self.owner.set_menus(dialog.get_menus()) common.app_tree.app.saved = False # update the status of the app def write(self, outfile, tabs): fwrite = outfile.write fwrite(' ' * tabs + '\n') for menu in self.owner[self.name][0](): menu.write(outfile, tabs+1) fwrite(' ' * tabs + '\n') # end of class MenuProperty class EditMenuBar(EditBase, PreviewMixin): __hidden_frame = None # used on GTK to reparent a menubar before deletion def __init__(self, name, klass, parent, property_window): custom_class = parent is None EditBase.__init__(self, name, klass, parent, wx.NewId(), property_window, custom_class=custom_class, show=False) self.base = 'wxMenuBar' def nil(*args): return () self.menus = [] # list of MenuTree objects self._mb = None # the real menubar self.access_functions['menus'] = (self.get_menus, self.set_menus) prop = self.properties['menus'] = MenuProperty(self, 'menus', None) ## self.node = Tree.Node(self) ## common.app_tree.add(self.node, parent.node) PreviewMixin.__init__(self) def create_widget(self): if wx.Platform == '__WXGTK__' and not EditMenuBar.__hidden_frame: EditMenuBar.__hidden_frame = wx.Frame(common.palette, -1, "") EditMenuBar.__hidden_frame.Hide() if self.parent: self.widget = self._mb = wx.MenuBar() if self.parent.widget: self.parent.widget.SetMenuBar(self.widget) if wx.Platform == '__WXMSW__' or wx.Platform == '__WXMAC__': self.widget.SetFocus = lambda : None else: # "top-level" menubar self.widget = wx.Frame(None, -1, misc.design_title(self.name)) self.widget.SetClientSize((400, 30)) self._mb = wx.MenuBar() self.widget.SetMenuBar(self._mb) self.widget.SetBackgroundColour(self._mb.GetBackgroundColour()) import os icon = wx.EmptyIcon() xpm = os.path.join(common.wxglade_path, 'icons', 'menubar.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) self.widget.SetIcon(icon) wx.EVT_CLOSE(self.widget, lambda e: self.hide_widget()) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) self.set_menus(self.menus) # show the menus def create_properties(self): EditBase.create_properties(self) page = self._common_panel sizer = page.GetSizer() self.properties['menus'].display(page) if not sizer: sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name_prop.panel, 0, wx.EXPAND) sizer.Add(self.klass_prop.panel, 0, wx.EXPAND) page.SetAutoLayout(1) page.SetSizer(sizer) sizer.Add(self.properties['menus'].panel, 0, wx.ALL|wx.EXPAND, 3) sizer.Fit(page) page.SetSize(self.notebook.GetClientSize()) sizer.Layout() self.notebook.AddPage(page, _("Common")) if self.parent is not None: self.property_window.Layout() else: PreviewMixin.create_properties(self) def __getitem__(self, key): return self.access_functions[key] def get_menus(self): return self.menus def set_menus(self, menus): self.menus = menus if not self._mb: return # nothing left to do for i in range(self._mb.GetMenuCount()): self._mb.Remove(0) def append(menu, items): for item in items: if misc.streq(item.name, '---'): # item is a separator menu.AppendSeparator() elif item.children: m = wx.Menu() append(m, item.children) menu.AppendMenu(wx.NewId(), misc.wxstr(item.label), m, misc.wxstr(item.help_str)) else: check_radio = 0 try: if int(item.checkable): check_radio = 1 except: check_radio = 0 if not check_radio: try: if int(item.radio): check_radio = 2 except: check_radio = 0 menu.Append(wx.NewId(), misc.wxstr(item.label), misc.wxstr(item.help_str), check_radio) first = self._mb.GetMenuCount() for menu in self.menus: m = wx.Menu() append(m, menu.root.children) if first: self._mb.Replace(0, m, misc.wxstr(menu.root.label)) first = 0 else: self._mb.Append(m, misc.wxstr(menu.root.label)) self._mb.Refresh() def remove(self, *args, **kwds): if self.parent is not None: self.parent.properties['menubar'].set_value(0) if kwds.get('gtk_do_nothing', False) and wx.Platform == '__WXGTK__': # workaround to prevent some segfaults on GTK: unfortunately, # I'm not sure that this works in all cases, and moreover it # could probably leak some memory (but I'm not sure) self.widget = None else: if self.parent.widget: if wx.Platform == '__WXGTK__' and \ not misc.check_wx_version(2, 5): self.widget.Reparent(EditMenuBar.__hidden_frame) self.widget.Hide() self.parent.widget.SetMenuBar(None) else: if self.widget: self.widget.Destroy() self.widget = None EditBase.remove(self) def popup_menu(self, event): if self.parent is not None: return # do nothing in this case if self.widget: if not self._rmenu: REMOVE_ID, HIDE_ID = [wx.NewId() for i in range(2)] self._rmenu = misc.wxGladePopupMenu(self.name) misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self._rmenu, HIDE_ID, _('Hide')) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, HIDE_ID, bind(self.hide_widget)) self.widget.PopupMenu(self._rmenu, event.GetPosition()) def hide_widget(self, *args): if self.widget and self.widget is not self._mb: self.widget.Hide() common.app_tree.expand(self.node, False) common.app_tree.select_item(self.node.parent) common.app_tree.app.show_properties() ## def show_widget(self, yes): ## EditBase.show_widget(self, yes) ## if self._frame: ## self._frame.Show(yes) def set_name(self, name): EditBase.set_name(self, name) if self.widget is not self._mb: self.widget.SetTitle(misc.design_title(misc.wxstr(self.name))) def get_property_handler(self, name): class MenuHandler: itemattrs = ['label', 'id', 'name', 'help_str', 'checkable', 'radio', 'handler'] def __init__(self, owner): self.owner = owner self.menu_items = [] self.curr_menu = [] self.curr_item = None self.curr_index = 0 self.menu_depth = 0 def start_elem(self, name, attrs): if name == 'menus': return if name == 'menu': self.menu_depth += 1 label = misc._encode(attrs['label']) if self.menu_depth == 1: t = MenuTree(attrs['name'], label, attrs.get('itemid', ''), attrs.get('help_str', ''), handler=attrs.get('handler', '')) self.curr_menu.append( (t.root,) ) self.owner.menus.append(t) return node = MenuTree.Node(label=label, name=attrs['name'], id=attrs.get('itemid', ''), help_str=attrs.get('help_str', ''), handler=attrs.get('handler', '')) cm = self.curr_menu[-1] cm[0].children.append(node) node.parent = cm[0] menu = wx.Menu() self.curr_menu.append( (node, menu) ) elif name == 'item': self.curr_item = MenuTree.Node() else: try: self.curr_index = self.itemattrs.index(name) except ValueError: # ignore unknown attributes... self.curr_index = -1 pass ## from xml_parse import XmlParsingError ## raise XmlParsingError, _("invalid menu item attribute") def end_elem(self, name): if name == 'item': try: cm = self.curr_menu[-1] except IndexError: from xml_parse import XmlParsingError raise XmlParsingError, _("menu item outside a menu") cm[0].children.append(self.curr_item) self.curr_item.parent = cm[0] elif name == 'menu': self.menu_depth -= 1 self.curr_menu.pop() elif name == 'menus': self.owner.set_menus(self.owner.menus) return True def char_data(self, data): setattr(self.curr_item, self.itemattrs[self.curr_index], data) if name == 'menus': return MenuHandler(self) return None # end of class EditMenuBar def builder(parent, sizer, pos, number=[0]): """\ factory function for EditMenuBar objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select menubar class')) if common.app_tree.app.get_language().lower() == 'xrc': self.klass = 'wxMenuBar' else: if not number[0]: self.klass = 'MyMenuBar' else: self.klass = 'MyMenuBar%s' % number[0] number[0] += 1 klass_prop = TextProperty(self, 'class', self, label=_('class')) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(klass_prop.panel, 0, wx.EXPAND) sz2 = wx.BoxSizer(wx.HORIZONTAL) sz2.Add(wx.Button(self, wx.ID_OK, _('OK')), 0, wx.ALL, 3) sz2.Add(wx.Button(self, wx.ID_CANCEL, _('Cancel')), 0, wx.ALL, 3) szr.Add(sz2, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) if self.GetBestSize()[0] < 150: self.SetSize((150, -1)) self.CenterOnScreen() def undo(self): if number[0] > 0: number[0] -= 1 def __getitem__(self, value): if value == 'class': def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) # end of inner class dialog = Dialog() if dialog.ShowModal() == wx.ID_CANCEL: # cancel the operation dialog.undo() dialog.Destroy() return name = 'menubar_%d' % (number[0] or 1) while common.app_tree.has_name(name): number[0] += 1 name = 'menubar_%d' % number[0] mb = EditMenuBar(name, dialog.klass, parent, common.property_panel) mb.node = Tree.Node(mb) common.app_tree.add(mb.node) mb.show_widget(True) mb.show_properties() def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditMenuBar objects from an xml file """ name = attrs.get('name') if parent is not None: if name: parent.menubar.set_name(name) parent.menubar.name_prop.set_value(name) return parent.menubar else: mb = EditMenuBar(name, attrs.get('class', 'wxMenuBar'), None, common.property_panel) mb.node = Tree.Node(mb) common.app_tree.add(mb.node) return mb def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ cwx = common.widgets_from_xml cwx['EditMenuBar'] = xml_builder common.widgets['EditMenuBar'] = builder return common.make_object_button('EditMenuBar', 'icons/menubar.xpm', 1) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/codegen.py0000644000175000017500000000614210743421035023677 0ustar stanistani# codegen.py: code generator functions for wxRadioButton objects # $Id: codegen.py,v 1.14 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, label, style)) props_buf = pygen.generate_common_properties(obj) clicked = prop.get('clicked') if clicked: props_buf.append('self.%s.SetValue(1)\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxRadioButton objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] label = cppgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, label, extra) ] props_buf = cppgen.generate_common_properties(obj) clicked = prop.get('clicked') if clicked: props_buf.append('%s->SetValue(1);\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): def write(self, *args, **kwds): try: self.properties['value'] = self.properties['clicked'] del self.properties['clicked'] except KeyError: pass xrcgen.DefaultXrcObject.write(self, *args, **kwds) return XrcCodeGenerator(obj) def initialize(): common.class_names['EditRadioButton'] = 'wxRadioButton' # python code generation functions pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxRadioButton', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxRadioButton', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxRadioButton', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/perl_codegen.py0000644000175000017500000000277510743421035024731 0ustar stanistani# perl_codegen.py : perl generator functions for wxRadioButton objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:42:18 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = '' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) clicked = prop.get('clicked') if clicked: props_buf.append('$self->{%s}->SetValue(1);\n' % obj.name) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditRadioButton'] = 'wxRadioButton' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxRadioButton', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/lisp_codegen.py0000644000175000017500000000307710743421035024732 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxRadioButton objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:24 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxRadioButton_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) clicked = prop.get('clicked') if clicked: props_buf.append('(wxRadioButton_SetValue (slot-%s obj) 1)\n' % obj.name) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditRadioButton'] = 'wxRadioButton' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxRadioButton', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/__init__.py0000644000175000017500000000066610743421035024037 0ustar stanistani# __init__.py: radio button widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import radio_button return radio_button.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_button/radio_button.py0000644000175000017500000001444210743421035024766 0ustar stanistani# radio_button.py: wxRadioButton objects # $Id: radio_button.py,v 1.20 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from misc import wxGladeRadioButton class EditRadioButton(ManagedBase): events = ['EVT_RADIOBUTTON'] def __init__(self, name, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxRadioButton objects """ import config ManagedBase.__init__(self, name, 'wxRadioButton', parent, id, sizer, pos, property_window, show=show) self.label = label self.value = 0 # if nonzero, che radio button is selected self.style = 0 # label and checked properties self.access_functions['label'] = (self.get_label, self.set_label) self.access_functions['clicked'] = (self.get_value, self.set_value) self.access_functions['style'] = (self.get_style, self.set_style) self.properties['label'] = TextProperty(self, 'label', None, multiline=True, label=_("label")) self.properties['clicked'] = CheckBoxProperty(self, 'clicked', None, _('Clicked')) self.style_pos = [wx.RB_GROUP, wx.RB_SINGLE, wx.RB_USE_CHECKBOX] self.properties['style'] = CheckListProperty( self, 'style', None, ['#section#' + _('Style'), 'wxRB_GROUP', 'wxRB_SINGLE', 'wxRB_USE_CHECKBOX'], tooltips=[_('Marks the beginning of a new group of radio buttons.'), _('In some circumstances, radio buttons that are not consecutive siblings trigger a hang bug in Windows (only). If this happens, add this style to mark the button as not belonging to a group, and implement the mutually-exclusive group behaviour yourself.'), _('Use a checkbox button instead of radio button (currently supported only on PalmOS).')]) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wxGladeRadioButton(self.parent.widget, self.id, self.label) try: self.widget.SetValue(self.value) # self.clicked? except AttributeError: raise wx.EVT_CHECKBOX(self.widget, self.id, lambda e: self.widget.SetValue(self.value)) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['label'].display(panel) self.properties['clicked'].display(panel) self.properties['style'].display(panel) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['clicked'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, _('Widget')) def get_label(self): return self.label def get_value(self): return self.value def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): self.label = value if self.widget: self.widget.SetLabel(value.replace('\\n', '\n')) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def set_value(self, value): self.value = int(value) if self.widget: self.widget.SetValue(self.value) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditRadioButton def builder(parent, sizer, pos, number=[1]): """\ factory function for EditRadioButton objects. """ label = 'radio_btn_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'radio_btn_%d' % number[0] radio = EditRadioButton(label, parent, wx.NewId(), misc._encode(label), sizer, pos, common.property_panel) node = Tree.Node(radio) radio.node = node radio.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditRadioButton objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") radio = EditRadioButton(label, parent, wx.NewId(), "", sizer, pos, common.property_panel) sizer.set_item(radio.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=radio.GetBestSize()) node = Tree.Node(radio) radio.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return radio def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditRadioButton'] = builder common.widgets_from_xml['EditRadioButton'] = xml_builder return common.make_object_button('EditRadioButton', 'icons/radio_button.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/codegen.py0000644000175000017500000002541610743421035022305 0ustar stanistani# codegen.py: code generator functions for wxFrame objects # $Id: codegen.py,v 1.24 2007/03/27 07:02:00 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * class PythonStatusbarCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] labels, widths = obj.properties['statusbar'] style = obj.properties.get("style") if style: style = pygen.cn_f(style) else: style = '0' init = [ 'self.%s = self.CreateStatusBar(%s, %s)\n' % \ (obj.name, len(labels), style) ] props = [] append = props.append append('self.%s.SetStatusWidths(%s)\n' % (obj.name, repr(widths))) append('# statusbar fields\n') append('%s_fields = [%s]\n' % \ (obj.name, ', '.join([pygen.quote_str(l) for l in labels]))) append('for i in range(len(%s_fields)):\n' % obj.name) append(' self.%s.SetStatusText(%s_fields[i], i)\n' % \ (obj.name, obj.name)) return init, props, [] # end of class PythonStatusbarCodeGenerator class PythonFrameCodeGenerator: def get_code(self, obj): return [], [], [] def get_properties_code(self, frame): prop = frame.properties pygen = common.code_writers['python'] cn = pygen.cn out = [] title = prop.get('title') if title: out.append('self.SetTitle(%s)\n' % pygen.quote_str(title)) icon = prop.get('icon') if icon: if icon.startswith('var:'): if not frame.preview: out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(' + cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + '))\n') % \ icon[4:].strip()) out.append('self.SetIcon(_icon)\n') elif icon.startswith('code:'): if not frame.preview: out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(%s)\n') % \ icon[5:].strip()) out.append('self.SetIcon(_icon)\n') else: if frame.preview: import misc icon = misc.get_relative_path(icon, True) out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(' + cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + '))\n') % \ pygen.quote_str(icon, False, False)) out.append('self.SetIcon(_icon)\n') out.extend(pygen.generate_common_properties(frame)) return out def get_layout_code(self, frame): ret = ['self.Layout()\n'] try: if int(frame.properties['centered']): ret.append('self.Centre()\n') except (KeyError, ValueError): pass pygen = common.code_writers['python'] if frame.properties.get('size', '').strip() and \ pygen.for_version < (2, 8): ret.append(pygen.generate_code_size(frame)) return ret # end of class PythonFrameCodeGenerator # property handlers for code generation class StatusFieldsHandler: """Handler for statusbar fields""" def __init__(self): self.labels = [] self.widths = [] self.curr_label = [] def start_elem(self, name, attrs): if name == 'field': self.widths.append(int(attrs.get('width', -1))) def end_elem(self, name, code_obj): if name == 'fields': code_obj.properties['statusbar'] = (self.labels, self.widths) return True self.labels.append("".join(self.curr_label)) self.curr_label = [] def char_data(self, data): self.curr_label.append(data) # end of class StatusFieldsHandler def xrc_frame_code_generator(obj): xrcgen = common.code_writers['XRC'] class FrameXrcObject(xrcgen.DefaultXrcObject): def write(self, outfile, tabs): if 'menubar' in self.properties: del self.properties['menubar'] if 'statusbar' in self.properties: del self.properties['statusbar'] if 'toolbar' in self.properties: del self.properties['toolbar'] xrcgen.DefaultXrcObject.write(self, outfile, tabs) def write_property(self, name, val, outfile, ntabs): if name != 'sizehints': xrcgen.DefaultXrcObject.write_property( self, name, val, outfile, ntabs) # end of class FrameXrcObject return FrameXrcObject(obj) def xrc_statusbar_code_generator(obj): xrcgen = common.code_writers['XRC'] class StatusbarXrcObject(xrcgen.DefaultXrcObject): def write(self, outfile, tabs): if 'statusbar' in self.properties: fields, widths = self.properties['statusbar'] self.properties['fields'] = str(len(fields)) self.properties['widths'] = ', '.join([str(w) for w in widths]) del self.properties['statusbar'] xrcgen.DefaultXrcObject.write(self, outfile, tabs) # end of class StatusbarXrcObject return StatusbarXrcObject(obj) class CppStatusBarCodeGenerator: def get_code(self, obj): """\ function that generates code for the statusbar of a wxFrame. """ cppgen = common.code_writers['C++'] labels, widths = obj.properties['statusbar'] style = obj.properties.get("style") if not style: style = '0' init = [ '%s = CreateStatusBar(%s, %s);\n' % (obj.name, len(labels), style) ] props = [] append = props.append append('int %s_widths[] = { %s };\n' % (obj.name, ', '.join(map(str, widths)))) append('%s->SetStatusWidths(%s, %s_widths);\n' % \ (obj.name, len(widths), obj.name)) labels = ',\n '.join([cppgen.quote_str(l) for l in labels]) append('const wxString %s_fields[] = {\n %s\n };\n' % (obj.name, labels)) append('for(int i = 0; i < %s->GetFieldsCount(); ++i) {\n' % obj.name) append(' %s->SetStatusText(%s_fields[i], i);\n }\n' % \ (obj.name, obj.name)) return init, [], props, [] # end of class CppStatusBarCodeGenerator class CppFrameCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxString&', 'title'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', 'wxDEFAULT_FRAME_STYLE')] def get_code(self, obj): return [], [], [], [] # the frame can't be a children def get_properties_code(self, frame): """\ generates the code for the various wxFrame specific properties. Returns a list of strings containing the generated code """ prop = frame.properties cppgen = common.code_writers['C++'] out = [] title = prop.get('title') if title: out.append('SetTitle(%s);\n' % cppgen.quote_str(title)) icon = prop.get('icon') if icon: out.append('wxIcon _icon;\n') if icon.startswith('var:'): out.append('_icon.CopyFromBitmap(wxBitmap(' + '%s, wxBITMAP_TYPE_ANY));\n' % \ icon[4:].strip()) elif icon.startswith('code:'): out.append('_icon.CopyFromBitmap(%s);\n' % \ icon[5:].strip()) else: out.append('_icon.CopyFromBitmap(wxBitmap(%s, ' 'wxBITMAP_TYPE_ANY));\n' % \ cppgen.quote_str(icon, False, False)) out.append('SetIcon(_icon);\n') out.extend(cppgen.generate_common_properties(frame)) return out def get_layout_code(self, frame): ret = ['Layout();\n'] try: if int(frame.properties['centered']): ret.append('Centre();\n') except (KeyError, ValueError): pass cppgen = common.code_writers['C++'] if frame.properties.get('size', '').strip() and \ cppgen.for_version < (2, 8): ret.append(cppgen.generate_code_size(frame)) return ret # end of class CppFrameCodeGenerator class CppMDIChildFrameCodeGenerator(CppFrameCodeGenerator): extra_headers = [''] constructor = [('wxMDIParentFrame*', 'parent'), ('int', 'id'), ('const wxString&', 'title'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', 'wxDEFAULT_FRAME_STYLE')] # end of class CppMDIChildFrameCodeGenerator def initialize(): cn = common.class_names cn['EditFrame'] = 'wxFrame' cn['EditMDIChildFrame'] = 'wxMDIChildFrame' cn['EditStatusBar'] = 'wxStatusBar' common.toplevels['EditFrame'] = 1 common.toplevels['EditMDIChildFrame'] = 1 pygen = common.code_writers.get('python') if pygen: awh = pygen.add_widget_handler awh('wxFrame', PythonFrameCodeGenerator()) awh('wxMDIChildFrame', PythonFrameCodeGenerator()) awh('wxStatusBar', PythonStatusbarCodeGenerator()) aph = pygen.add_property_handler aph('statusbar', pygen.DummyPropertyHandler) aph('fields', StatusFieldsHandler) aph('menubar', pygen.DummyPropertyHandler) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxFrame', xrc_frame_code_generator) xrcgen.add_widget_handler('wxMDIChildFrame', xrcgen.NotImplementedXrcObject) xrcgen.add_widget_handler('wxStatusBar', xrc_statusbar_code_generator) #xrcgen.NotImplementedXrcObject) xrcgen.add_property_handler('fields', StatusFieldsHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxFrame', CppFrameCodeGenerator()) cppgen.add_widget_handler('wxMDIChildFrame', CppMDIChildFrameCodeGenerator()) cppgen.add_widget_handler('wxStatusBar', CppStatusBarCodeGenerator()) cppgen.add_property_handler('fields', StatusFieldsHandler) cppgen.add_property_handler('menubar', cppgen.DummyPropertyHandler) cppgen.add_property_handler('statusbar', cppgen.DummyPropertyHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/perl_codegen.py0000644000175000017500000000770310743421035023326 0ustar stanistani# codegen.py: code generator functions for wxFrame objects # $Id: perl_codegen.py,v 1.10 2007/03/27 07:01:59 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * from codegen import StatusFieldsHandler class PerlStatusBarCodeGenerator: def get_code(self, obj): """\ function that generates code for the statusbar of a wxFrame. """ plgen = common.code_writers['perl'] labels, widths = obj.properties['statusbar'] style = obj.properties.get("style") if not style: style = '0' init = [ '$self->{%s} = $self->CreateStatusBar(%s, %s);\n' % (obj.name, len(labels), style) ] props = [] append = props.append append('$self->{%s}->SetStatusWidths(%s);\n' % (obj.name, ','.join(map(str, widths)))) labels = ',\n\t\t'.join([plgen.quote_str(l) for l in labels]) append('\n\tmy( @%s_fields ) = (\n\t\t%s\n\t);\n\n' % (obj.name, labels)) append('if( @%s_fields ) {\n' % obj.name) append('\t$self->{%s}->SetStatusText($%s_fields[$_], $_) ' % (obj.name, obj.name) ) append('\n\t\tfor 0 .. $#%s_fields ;\n\t}\n' % obj.name) return init, props, [] # end of class PerlStatusBarCodeGenerator class PerlFrameCodeGenerator: #wxFrame( parent, id, title, pos , size , style , name ) new_signature = [ '$parent', '$id', '$title', '$pos', '$size', '$style', '$name' ] def get_code(self, obj): return [], [], [], [] # the frame can't be a children def get_properties_code(self, frame): """\ generates the code for the various wxFrame specific properties. Returns a list of strings containing the generated code """ prop = frame.properties plgen = common.code_writers['perl'] out = [] title = prop.get('title') if title: out.append('$self->SetTitle(%s);\n' % plgen.quote_str(title)) icon = prop.get('icon') if icon: out.append('my $icon = Wx::Icon->new();\n') out.append('$icon->CopyFromBitmap(Wx::Bitmap->new(%s, ' 'wxBITMAP_TYPE_ANY));\n' % plgen.quote_str(icon)) out.append('$self->SetIcon($icon);\n') out.extend(plgen.generate_common_properties(frame)) return out def get_layout_code(self, frame): ret = ['$self->Layout();\n'] try: if int(frame.properties['centered']): ret.append('$self->Centre();\n') except (KeyError, ValueError): pass plgen = common.code_writers['perl'] if frame.properties.get('size', '').strip() and \ plgen.for_version < (2, 8): ret.append(plgen.generate_code_size(frame)) return ret # end of class PerlFrameCodeGenerator class PerlMDIChildFrameCodeGenerator(PerlFrameCodeGenerator): extra_headers = ['Wx::MDI'] #wxMDIChildFrame(parent, id, title, pos, size, style, name ) # end of class PerlMDIChildFrameCodeGenerator def initialize(): cn = common.class_names cn['EditFrame'] = 'wxFrame' cn['EditMDIChildFrame'] = 'wxMDIChildFrame' cn['EditStatusBar'] = 'wxStatusBar' common.toplevels['EditFrame'] = 1 common.toplevels['EditMDIChildFrame'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxFrame', PerlFrameCodeGenerator()) plgen.add_widget_handler('wxMDIChildFrame', PerlMDIChildFrameCodeGenerator()) plgen.add_widget_handler('wxStatusBar', PerlStatusBarCodeGenerator()) plgen.add_property_handler('fields', StatusFieldsHandler) plgen.add_property_handler('menubar', plgen.DummyPropertyHandler) plgen.add_property_handler('statusbar', plgen.DummyPropertyHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/lisp_codegen.py0000644000175000017500000000727310743421035023335 0ustar stanistani# codegen.py: code generator functions for wxFrame objects # $Id: lisp_codegen.py,v 1.3 2007/03/27 07:02:00 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from MenuTree import * from codegen import StatusFieldsHandler class LispStatusBarCodeGenerator: def get_code(self, obj): """\ function that generates code for the statusbar of a wxFrame. """ plgen = common.code_writers['lisp'] labels, widths = obj.properties['statusbar'] style = obj.properties.get("style") if not style: style = '0' init = [ '(setf (slot-%s obj) (wxFrame_CreateStatusBar (slot-top-window obj) %s %s))\n' % (obj.name, len(labels), style) ] props = [] append = props.append append('(wxStatusBar_SetStatusWidths (slot-%s obj) %s (vector %s))\n' % (obj.name, len(widths),' '.join(map(str, widths)))) i = 0 for l in labels: append('\t (wxStatusBar_SetStatusText (slot-%s obj) %s %s)\n' % (obj.name, plgen.quote_str(l),i) ) i=i+1 return init, props, [] # end of class LispStatusBarCodeGenerator class LispFrameCodeGenerator: #wxFrame( parent, id, title, pos , size , style , name ) new_signature = [ '$parent', '$id', '$title', '$pos', '$size', '$style', '$name' ] def get_code(self, obj): return [], [], [], [] # the frame can't be a children def get_properties_code(self, frame): """\ generates the code for the various wxFrame specific properties. Returns a list of strings containing the generated code """ prop = frame.properties plgen = common.code_writers['lisp'] out = [] title = prop.get('title') if title: out.append('(wxFrame_SetTitle (slot-top-window %s) %s)\n' % plgen.quote_str(title)) icon = prop.get('icon') if icon: out.append('my $icon = Wx::Icon->new();\n') out.append('$icon->CopyFromBitmap(Wx::Bitmap->new(%s, ' 'wxBITMAP_TYPE_ANY));\n' % plgen.quote_str(icon)) out.append('(wxFrame_SetIcon (slot-top-window obj) $icon)\n') out.extend(plgen.generate_common_properties(frame)) return out def get_layout_code(self, frame): ret = ['$self->Layout();\n'] try: if int(frame.properties['centered']): ret.append('(wxFrame_Centre (slot-top-window obj) 0)\n') except (KeyError, ValueError): pass return ret # end of class LispFrameCodeGenerator class LispMDIChildFrameCodeGenerator(LispFrameCodeGenerator): extra_headers = ['Wx::MDI'] #wxMDIChildFrame(parent, id, title, pos, size, style, name ) # end of class LispMDIChildFrameCodeGenerator def initialize(): cn = common.class_names cn['EditFrame'] = 'wxFrame' cn['EditMDIChildFrame'] = 'wxMDIChildFrame' cn['EditStatusBar'] = 'wxStatusBar' common.toplevels['EditFrame'] = 1 common.toplevels['EditMDIChildFrame'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxFrame', LispFrameCodeGenerator()) plgen.add_widget_handler('wxMDIChildFrame', LispMDIChildFrameCodeGenerator()) plgen.add_widget_handler('wxStatusBar', LispStatusBarCodeGenerator()) plgen.add_property_handler('fields', StatusFieldsHandler) plgen.add_property_handler('menubar', plgen.DummyPropertyHandler) plgen.add_property_handler('statusbar', plgen.DummyPropertyHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/frame.py0000644000175000017500000005356710743421035022003 0ustar stanistani# frame.py: wxFrame and wxStatusBar objects # $Id: frame.py,v 1.46 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, math, misc from tree import Tree #from MenuTree import * from widget_properties import * from edit_windows import EditBase, TopLevelBase class EditStatusBar(EditBase): _hidden_frame = None def __init__(self, parent, property_window): EditBase.__init__(self, parent.name + '_statusbar', 'wxStatusBar', parent, id, property_window, custom_class=False, show=False) # style property self.style_pos = (wx.ST_SIZEGRIP,) style_labels = ('#section#' + _('Style'), 'wxST_SIZEGRIP') self.access_functions['style'] = (self.get_style, self.set_style) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self.node = Tree.Node(self) common.app_tree.add(self.node, parent.node) self.fields = [ [self.name, "-1"] ] # list of 2-lists label, size # for the statusbar fields self.access_functions['fields'] = (self.get_fields, self.set_fields) prop = self.properties['fields'] = GridProperty( self, 'fields', None, [("Text", GridProperty.STRING), ("Size", GridProperty.INT)]) # replace the default 'write' method of 'prop' with a custom one def write_prop(outfile, tabs): from xml.sax.saxutils import escape, quoteattr fwrite = outfile.write fwrite(' ' * tabs + '\n') tabs += 1 import widget_properties for label, width in self.fields: fwrite(' ' * tabs + '%s\n' % (quoteattr(width), escape(widget_properties._encode(label)))) tabs -= 1 fwrite(' ' * tabs + '\n') prop.write = write_prop def create_widget(self): self.widget = wx.StatusBar(self.parent.widget, wx.NewId()) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) self.set_fields(self.fields) if self.parent.widget: self.parent.widget.SetStatusBar(self.widget) def create_properties(self): EditBase.create_properties(self) page = self._common_panel self.properties['style'].display(page) prop = self.properties['fields'] prop.display(page) sizer = page.GetSizer() if not sizer: sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name_prop.panel, 0, wx.EXPAND) sizer.Add(self.klass_prop.panel, 0, wx.EXPAND) page.SetAutoLayout(1) page.SetSizer(sizer) sizer.Add(self.properties['style'].panel, 0, wx.EXPAND) sizer.Add(prop.panel, 1, wx.ALL|wx.EXPAND, 3) sizer.Fit(page) page.SetSize(self.notebook.GetClientSize()) sizer.Layout() self.notebook.AddPage(page, _("Common")) self.property_window.Layout() prop.set_col_sizes([190, 0]) def set_fields(self, values): # values is a list of lists self.fields = [] if self.widget: self.widget.SetFieldsCount(len(values)) for i in range(len(values)): try: v = int(values[i][1]) except: v = 0 s = misc.wxstr(values[i][0]) self.fields.append([s, str(v)]) if self.widget: self.widget.SetStatusText(s, i) if self.widget: self.widget.SetStatusWidths([int(i[1]) for i in self.fields]) def get_fields(self): return self.fields def __getitem__(self, key): return self.access_functions[key] def remove(self, *args, **kwds): if not kwds.get('do_nothing', False): if self.parent.widget: self.parent.widget.SetStatusBar(None) try: self.parent.properties['statusbar'].set_value(0) except KeyError: pass if self.widget: self.widget.Hide() EditBase.remove(self) else: if misc.check_wx_version(2, 6): if EditStatusBar._hidden_frame is None: EditStatusBar._hidden_frame = wx.Frame(None, -1, "") if self.widget is not None: self.widget.Reparent(EditStatusBar._hidden_frame) self.widget = None def popup_menu(self, *args): pass # to avoid strange segfault :) def get_property_handler(self, name): class FieldsHandler: """\ custom Property handler for statusbar fields. """ def __init__(self, owner): self.owner = owner self.width = -1 self.value = [] def start_elem(self, name, attrs): if name == 'fields': self.fields = [] else: # name == 'field' self.value = [] self.width = attrs.get('width', '-1') def end_elem(self, name): if name == 'field': self.fields.append(["".join(self.value), self.width]) else: # name == 'fields' self.owner.fields = self.fields self.owner.set_fields(self.owner.fields) self.owner.properties['fields'].set_value( self.owner.fields) return True def char_data(self, data): self.value.append(data) return False # tell there's no need to go further # (i.e. to call add_property) if name == 'fields': return FieldsHandler(self) return None def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditStatusBar class EditFrame(TopLevelBase): def __init__(self, name, parent, id, title, property_window, style=wx.DEFAULT_FRAME_STYLE, show=True, klass='wxFrame'): TopLevelBase.__init__(self, name, klass, parent, id, property_window, show=show, title=title) self.base = 'wxFrame' self.style = style self.statusbar = None self.icon = '' self.access_functions['statusbar'] = (self.get_statusbar, self.set_statusbar) self.menubar = None self.access_functions['menubar'] = (self.get_menubar, self.set_menubar) self.toolbar = None self.access_functions['toolbar'] = (self.get_toolbar, self.set_toolbar) self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['icon'] = (self.get_icon, self.set_icon) prop = self.properties style_labels = ['#section#' + _('Style'), 'wxDEFAULT_FRAME_STYLE', 'wxICONIZE', 'wxCAPTION', 'wxMINIMIZE', 'wxMINIMIZE_BOX', 'wxMAXIMIZE', 'wxMAXIMIZE_BOX', 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxSIMPLE_BORDER', 'wxRESIZE_BORDER', 'wxFRAME_TOOL_WINDOW', 'wxFRAME_NO_TASKBAR', 'wxFRAME_FLOAT_ON_PARENT', 'wxNO_BORDER', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE', 'wxTAB_TRAVERSAL', 'wxCLIP_CHILDREN'] self.style_pos = [wx.DEFAULT_FRAME_STYLE, wx.ICONIZE, wx.CAPTION, wx.MINIMIZE, wx.MINIMIZE_BOX, wx.MAXIMIZE, wx.MAXIMIZE_BOX, wx.STAY_ON_TOP, wx.SYSTEM_MENU, wx.SIMPLE_BORDER, wx.RESIZE_BORDER, wx.FRAME_TOOL_WINDOW, wx.FRAME_NO_TASKBAR, wx.FRAME_FLOAT_ON_PARENT, wx.NO_BORDER, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE, wx.TAB_TRAVERSAL, wx.CLIP_CHILDREN] if misc.check_wx_version(2, 5): style_labels.insert(5, 'wxCLOSE_BOX') self.style_pos.insert(4, wx.CLOSE_BOX) prop['style'] = CheckListProperty(self, 'style', None, style_labels) # menubar property prop['menubar'] = CheckBoxProperty(self, 'menubar', None, _('Has MenuBar')) # statusbar property prop['statusbar'] = CheckBoxProperty(self, 'statusbar', None, _('Has StatusBar')) # toolbar property prop['toolbar'] = CheckBoxProperty(self, 'toolbar', None, _('Has ToolBar')) # icon property prop['icon'] = FileDialogProperty(self, 'icon', None, style=wx.OPEN|wx.FILE_MUST_EXIST, can_disable=True, label=_("icon")) # centered property self.centered = False self.access_functions['centered'] = (self.get_centered, self.set_centered) prop['centered'] = CheckBoxProperty(self, 'centered', None, label=_("centered")) # size hints property self.sizehints = False self.access_functions['sizehints'] = (self.get_sizehints, self.set_sizehints) prop['sizehints'] = CheckBoxProperty(self, 'sizehints', None, label=_('Set Size Hints')) def create_widget(self): if self.parent: w = self.parent.widget else: w = common.palette self.widget = wx.Frame(w, self.id, self.get_title()) self.set_icon(self.icon) def finish_widget_creation(self): TopLevelBase.finish_widget_creation(self) if not self.properties['size'].is_active(): #if self.sizer: self.sizer.fit_parent() #else: self.widget.SetSize((400, 300)) if wx.Platform == '__WXMSW__': self.widget.CenterOnScreen() if self.menubar and self.menubar.widget: self.widget.SetMenuBar(self.menubar.widget) if self.statusbar and self.statusbar.widget: self.widget.SetStatusBar(self.statusbar.widget) if self.toolbar and self.toolbar.widget: self.widget.SetToolBar(self.toolbar.widget) def create_properties(self): TopLevelBase.create_properties(self) prop = self.properties panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop['title'].display(panel) prop['icon'].display(panel) prop['centered'].display(panel) prop['sizehints'].display(panel) prop['menubar'].display(panel) prop['toolbar'].display(panel) try: sbprop = prop['statusbar'] sbprop.display(panel) except KeyError: sbprop = None prop['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop['title'].panel, 0, wx.EXPAND) szr.Add(prop['icon'].panel, 0, wx.EXPAND) szr.Add(prop['centered'].panel, 0, wx.EXPAND) szr.Add(prop['sizehints'].panel, 0, wx.EXPAND) szr.Add(prop['menubar'].panel, 0, wx.EXPAND) szr.Add(prop['toolbar'].panel, 0, wx.EXPAND) if sbprop: szr.Add(sbprop.panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') w, h = panel.GetClientSizeTuple() panel.SetScrollbars(5, 5, int(math.ceil(w/5.0)), int(math.ceil(h/5.0))) def get_menubar(self): return self.menubar is not None def set_menubar(self, value): if value: from menubar import EditMenuBar self.menubar = EditMenuBar(self.name + '_menubar', 'wxMenuBar', self, common.property_panel) self.menubar.node = Tree.Node(self.menubar) common.app_tree.add(self.menubar.node, self.node) if self.widget: self.menubar.show_widget(True) self.menubar.show_properties() else: self.menubar = self.menubar.remove() self.show_properties(None) def get_statusbar(self): return self.statusbar is not None def set_statusbar(self, value): if value: self.statusbar = EditStatusBar(self, common.property_panel) if self.widget: self.statusbar.show_widget(True) self.statusbar.show_properties() else: self.statusbar = self.statusbar.remove() self.show_properties(None) if self.widget: # this is needed at least on win32 wx.PostEvent(self.widget, wx.SizeEvent(self.widget.GetSize(), self.widget.GetId())) def get_toolbar(self): return self.toolbar is not None def set_toolbar(self, value): if value: from toolbar import EditToolBar self.toolbar = EditToolBar(self.name + '_toolbar', 'wxToolBar', self, common.property_panel) self.toolbar.node = Tree.Node(self.toolbar) common.app_tree.add(self.toolbar.node, self.node) if self.widget: self.toolbar.show_widget(True) self.toolbar.show_properties() else: self.toolbar = self.toolbar.remove() self.show_properties(None) def get_style(self): retval = [0] * len(self.style_pos) try: if self.style == wx.DEFAULT_FRAME_STYLE: retval[0] = 1 else: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 retval[0] = 0 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) style = 0 for v in range(len(value)): if value[v]: style |= self.style_pos[v] self.style = style if self.widget: self.widget.SetWindowStyleFlag(style) def remove(self, *args): if self.menubar: self.menubar = self.menubar.remove(gtk_do_nothing=True) if self.statusbar: self.statusbar = self.statusbar.remove(do_nothing=True) if self.toolbar: self.toolbar = self.toolbar.remove(do_nothing=True) TopLevelBase.remove(self, *args) def get_icon(self): # is a string that holds the filename (for example: icon.png) return self.icon def set_icon(self, value): self.icon = value.strip() if self.widget: if self.icon and not (self.icon.startswith('var:') or self.icon.startswith('code:')): # setting icon icon = misc.get_relative_path(self.icon) bmp = wx.Bitmap(icon, wx.BITMAP_TYPE_ANY) if not bmp.Ok(): self.set_icon("") else: icon = wx.EmptyIcon() icon.CopyFromBitmap(bmp) self.widget.SetIcon(icon) else: # removing icon icon = wx.EmptyIcon() import os xpm = os.path.join(common.wxglade_path, 'icons', 'frame.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) self.widget.SetIcon(icon) def get_centered(self): return self.centered def set_centered(self, value): try: self.centered = bool(int(value)) except ValueError: pass def get_sizehints(self): return self.sizehints def set_sizehints(self, value): try: self.sizehints = bool(int(value)) except ValueError: pass # end of class EditFrame class EditMDIChildFrame(EditFrame): _is_toplevel = False # used to avoid to appear in the "Top Window" property # of the app def __init__(self, *args, **kwds): EditFrame.__init__(self, *args, **kwds) del self.properties['statusbar'] self.base = 'wxFrame' # end of class EditMDIChildFrame def builder(parent, sizer, pos, number=[0]): """\ factory function for EditFrame objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select frame class')) if common.app_tree.app.get_language().lower() == 'xrc': self.klass = 'wxFrame' else: if not number[0]: self.klass = 'MyFrame' else: self.klass = 'MyFrame%s' % number[0] number[0] += 1 self.base = 0 base_prop = RadioProperty(self, 'base class', self, ['wxFrame', 'wxMDIChildFrame'], label=_("base class")) klass_prop = TextProperty(self, 'class', self, label=_("class")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(base_prop.panel, 0, wx.ALL|wx.EXPAND, 5) szr.Add(klass_prop.panel, 0, wx.EXPAND) btnbox = wx.BoxSizer(wx.HORIZONTAL) btnOK = wx.Button(self, wx.ID_OK, _('OK')) btnCANCEL = wx.Button(self, wx.ID_CANCEL, _('Cancel')) btnbox.Add(btnOK, 0, wx.ALL, 3) btnbox.Add(btnCANCEL, 0, wx.ALL, 3) btnOK.SetFocus() szr.Add(btnbox, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def undo(self): if number[0] > 0: number[0] -= 1 def __getitem__(self, value): if value == 'class': def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) else: def set_base(b): self.base = b return (lambda : self.base, set_base) # end of inner class dialog = Dialog() # Check if the user hit Cancel, if so then bail out if dialog.ShowModal() == wx.ID_CANCEL: # restore state dialog.undo() # clean up resources dialog.Destroy() return label = 'frame_%d' % (number[0] or 1) while common.app_tree.has_name(label): number[0] += 1 label = 'frame_%d' % number[0] if dialog.base == 0: base_class = EditFrame else: base_class = EditMDIChildFrame frame = base_class(label, parent, wx.NewId(), label, common.property_panel, klass=dialog.klass) node = Tree.Node(frame) frame.node = node common.app_tree.add(node) frame.show_widget(True) # add a default vertical sizer to the frame import edit_sizers edit_sizers._builder(frame, None, 0) # now select the frame's node in the tree common.app_tree.select_item(node) dialog.Destroy() if wx.Platform == '__WXMSW__': #frame.widget.CenterOnScreen() frame.widget.Raise() def _make_builder(base_class): def xml_builder(attrs, parent, sizer, sizeritem, pos=None): from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") frame = base_class(label, parent, wx.NewId(), "", common.property_panel, show=False) node = Tree.Node(frame) frame.node = node common.app_tree.add(node) return frame return xml_builder ## def xml_builder(attrs, parent, sizer, sizeritem, pos=None): ## """\ ## factory to build EditFrame objects from an xml file ## """ ## from xml_parse import XmlParsingError ## try: label = attrs['name'] ## except KeyError: raise XmlParsingError, _("'name' attribute missing") ## frame = EditFrame(label, parent, wx.NewId(), label, common.property_panel, ## show=False) ## node = Tree.Node(frame) ## frame.node = node ## common.app_tree.add(node) ## return frame def statusbar_xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditStatusBar objects from an xml file """ parent.statusbar.set_fields([]) name = attrs.get('name') if name: parent.statusbar.set_name(name) parent.statusbar.name_prop.set_value(name) return parent.statusbar def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ cwx = common.widgets_from_xml cwx['EditStatusBar'] = statusbar_xml_builder cwx['EditFrame'] = _make_builder(EditFrame) cwx['EditMDIChildFrame'] = _make_builder(EditMDIChildFrame) common.widgets['EditFrame'] = builder # add statusbar icon to WidgetTree from tree import WidgetTree import os.path WidgetTree.images['EditStatusBar'] = os.path.join(common.wxglade_path, 'icons/statusbar.xpm') WidgetTree.images['EditMDIChildFrame'] = os.path.join(common.wxglade_path, 'icons/frame.xpm') return common.make_object_button('EditFrame', 'icons/frame.xpm', 1) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/frame/__init__.py0000644000175000017500000000064110743421035022431 0ustar stanistani# __init__.py: frame widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:00 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import frame return frame.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/codegen.py0000644000175000017500000000717510743421035023561 0ustar stanistani# codegen.py: code generator functions for wxSpinButton objects # $Id: codegen.py,v 1.2 2004/12/13 18:45:13 agriggio Exp $ # # Copyright (c) 2004 D.H. aka crazyinsomniac at users.sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # based on wxGlade/widgets/spin_ctrl/ import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) # value = prop.get('value', '') # try: min_v, max_v = [ s.strip() for s in \ # prop.get('range', '0, 100').split(',') ] # except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s %s)\n' % (obj.name, klass, parent, id, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class SpinButtonXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'range': try: min, max = val.split(',') except ValueError: pass else: tab_s = ' '*tabs outfile.write(tab_s + '%s\n' % min) outfile.write(tab_s + '%s\n' % max) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class SpinButtonXrcObject return SpinButtonXrcObject(obj) class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxSpinButton objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] # value = prop.get('value', '') # try: min_v, max_v = [ s.strip() for s in \ # prop.get('range', '0, 100').split(',') ] # except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' style = prop.get('style') if not style: style = 'wxSP_ARROW_KEYS' init = ['%s = new %s(%s, %s, wxDefaultPosition, wxDefaultSize,' ' %s);\n' % (obj.name, obj.klass, parent, id, style)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxSpinEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditSpinButton'] = 'wxSpinButton' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxSpinButton', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxSpinButton', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxSpinButton', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/perl_codegen.py0000644000175000017500000000303010743421035024565 0ustar stanistani# perl_codegen.py : perl generator functions for wxSpinButton objects # $Id: perl_codegen.py,v 1.2 2005/08/15 07:42:55 crazyinsomniac Exp $ # # Copyright (c) 2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) # value = prop.get('value', '') # try: min_v, max_v = [ s.strip() for s in \ # prop.get('range', '0, 100').split(',') ] # except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = 'wxSP_ARROW_KEYS' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditSpinButton'] = 'wxSpinButton' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxSpinButton', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/lisp_codegen.py0000644000175000017500000000311210743421035024573 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxSpinButton objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:39 efuzzyone Exp $ # # Copyright (c) 2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) # value = prop.get('value', '') # try: min_v, max_v = [ s.strip() for s in \ # prop.get('range', '0, 100').split(',') ] # except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = 'wxSP_ARROW_KEYS' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxSpinButton_Create %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditSpinButton'] = 'wxSpinButton' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxSpinButton', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/__init__.py0000644000175000017500000000066110743421035023705 0ustar stanistani# __init__.py: spin ctrl widget module initialization # $Id: __init__.py,v 1.3 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import spin_button return spin_button.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_button/spin_button.py0000644000175000017500000001322110743421035024506 0ustar stanistani# spin_button.py: wxSpinButton objects # $Id: spin_button.py,v 1.5 2006/11/07 15:06:25 jkt Exp $ # # Copyright (c) 2004 D.H. aka crazyinsomniac at users.sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # based on wxGlade/widgets/spin_ctrl/ import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * class EditSpinButton(ManagedBase): """\ Class to handle wxSpinButton objects """ events = ['EVT_SPIN', 'EVT_SPIN_UP', 'EVT_SPIN_DOWN'] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): import config ManagedBase.__init__(self, name, 'wxSpinButton', parent, id, sizer, pos, property_window, show=show) self.style = 0 self.value = 0 self.range = (0, 100) # Default values in wxSpinButton constructor. prop = self.properties self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['value'] = (self.get_value, self.set_value) self.access_functions['range'] = (self.get_range, self.set_range) style_labels = ('#section#' + _('Style'), 'wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP') self.style_pos = (wx.SP_HORIZONTAL, wx.SP_VERTICAL, wx.SP_ARROW_KEYS, wx.SP_WRAP) prop['style'] = CheckListProperty(self, 'style', None, style_labels) prop['range'] = TextProperty(self, 'range', None, can_disable=True, label=_("range")) prop['value'] = SpinProperty(self, 'value', None, can_disable=True, label=_("value")) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): try: self.widget = wx.SpinButton(self.parent.widget, self.id , style=self.style) except AttributeError: self.widget = wx.SpinButton(self.parent.widget, self.id ) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) prop = self.properties prop['range'].display(panel) prop['value'].display(panel) prop['style'].display(panel) szr.Add(prop['range'].panel, 0, wx.EXPAND) szr.Add(prop['value'].panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_range(self): # we cannot return self.range since this would become a "(0, 100)" # string, and we don't want the parens return "%s, %s" % self.range def set_range(self, val): try: min_v, max_v = map(int, val.split(',')) except: self.properties['range'].set_value(self.get_range()) else: self.range = (min_v, max_v) self.properties['value'].set_range(min_v, max_v) if self.widget: self.widget.SetRange(min_v, max_v) def get_value(self): return self.value def set_value(self, value): value = int(value) if self.value != value: self.value = value if self.widget: self.widget.SetValue(self.value) # end of class EditSpinButton def builder(parent, sizer, pos, number=[1]): """\ factory function for EditSpinButton objects. """ name = 'spin_button_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'spin_button_%d' % number[0] text = EditSpinButton(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(text) text.node = node text.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditSpinButton objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") text = EditSpinButton(name, parent, wx.NewId(), sizer, pos, common.property_panel) sizer.set_item(text.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(text) text.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return text def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditSpinButton'] = builder common.widgets_from_xml['EditSpinButton'] = xml_builder return common.make_object_button('EditSpinButton', 'icons/spinbtn.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/codegen.py0000644000175000017500000000626610743421035023513 0ustar stanistani# codegen.py: code generator functions for wxStaticLine objects # $Id: codegen.py,v 1.14 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties attribute = pygen.test_attribute(obj) id_name, id = pygen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style and style != 'wxLI_HORIZONTAL': style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) if attribute: prefix = 'self.' else: prefix = '' klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('%s%s = %s(%s, %s%s)\n' % (prefix, obj.name, klass, parent, id, style)) props_buf = pygen.generate_common_properties(obj) if not attribute: return [], [], init + props_buf return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates the C++ code for wxStaticLine objects """ cppgen = common.code_writers['C++'] prop = obj.properties attribute = cppgen.test_attribute(obj) id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style and style != 'wxLI_HORIZONTAL': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style if attribute: prefix = '' else: prefix = '%s* ' % obj.klass init = ['%s%s = new %s(%s, %s%s);\n' % (prefix, obj.name, obj.klass, parent, id, extra) ] if id_name: init.append(id_name) props_buf = cppgen.generate_common_properties(obj) if not attribute: return [], ids, [], init + props_buf return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): def write(self, *args, **kwds): try: del self.properties['attribute'] except KeyError: pass xrcgen.DefaultXrcObject.write(self, *args, **kwds) return XrcCodeGenerator(obj) def initialize(): common.class_names['EditStaticLine'] = 'wxStaticLine' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxStaticLine', PythonCodeGenerator()) cppgen = common.code_writers.get("C++") if cppgen: cppgen.add_widget_handler('wxStaticLine', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxStaticLine', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/perl_codegen.py0000644000175000017500000000326510743421035024531 0ustar stanistani# perl_codegen.py : perl generator functions for wxStaticLine objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:45:36 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not( style and style != 'wxLI_HORIZONTAL' ): # default style style = '' init = [] if id_name: init.append(id_name) if attribute: prefix = '$self->{%s}' % obj.name else: prefix = 'my $%s' % obj.name obj.name = '$' + obj.name # the yuck (needed for pl_codegen.py) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('%s = %s->new(%s, %s, wxDefaultPosition, wxDefaultSize, \ %s);\n' % (prefix, klass , parent, id, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: return [], [], init + props_buf return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditStaticLine'] = 'wxStaticLine' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxStaticLine', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/lisp_codegen.py0000644000175000017500000000334610743421035024536 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxStaticLine objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:50:08 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not( style and style != 'wxLI_HORIZONTAL' ): # default style style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) if attribute: prefix = '(slot-%s obj)' % obj.name else: prefix = 'my $%s' % obj.name obj.name = '$' + obj.name # the yuck (needed for pl_codegen.py) init.append('(setf %s (wxStaticLine_Create %s %s -1 -1 -1 -1 %s))\n' % (prefix, parent, id, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: return [], [], init + props_buf return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditStaticLine'] = 'wxStaticLine' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxStaticLine', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/static_line.py0000644000175000017500000001314410743421035024376 0ustar stanistani# static_line.py: wxStaticLine objects # $Id: static_line.py,v 1.13 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditStaticLine(ManagedBase): def __init__(self, name, parent, id, orientation, sizer, pos, property_window, show=True): """\ Class to handle wxStaticLine objects """ self.orientation = orientation self.attribute = True ManagedBase.__init__(self, name, 'wxStaticLine', parent, id, sizer, pos, property_window, show=show) self.access_functions['style'] = (self.get_orientation, self.set_orientation) def set_attribute(v): self.attribute = int(v) self.access_functions['attribute'] = (lambda : self.attribute, set_attribute) self.properties['style'] = HiddenProperty(self, 'style', label=_("style")) self.properties['attribute'] = CheckBoxProperty( self, 'attribute', None, _('Store as attribute'), write_always=True) self.removed_p = self.properties['font'] def create_widget(self): #self.orientation = int(self.property['style'].get_value()) self.widget = wx.StaticLine(self.parent.widget, self.id, style=self.orientation) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self) self.sel_marker.Reparent(self.parent.widget) del self.properties['font'] def create_properties(self): ManagedBase.create_properties(self) if self.removed_p.panel: self.removed_p.panel.Hide() panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['attribute'].display(panel) szr.Add(self.properties['attribute'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def __getitem__(self, key): if key != 'font': return ManagedBase.__getitem__(self, key) return (lambda : "", lambda v: None) def get_orientation(self): od = { wx.LI_HORIZONTAL: 'wxLI_HORIZONTAL', wx.LI_VERTICAL: 'wxLI_VERTICAL' } return od.get(self.orientation, 'wxLI_HORIZONTAL') def set_orientation(self, value): od = { 'wxLI_HORIZONTAL': wx.LI_HORIZONTAL, 'wxLI_VERTICAL': wx.LI_VERTICAL } self.orientation = od.get(value, wx.LI_HORIZONTAL) # end of class EditStaticLine def builder(parent, sizer, pos, number=[1]): """\ factory function for EditStaticLine objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, 'Select orientation') self.orientations = [ wx.LI_HORIZONTAL, wx.LI_VERTICAL ] self.orientation = wx.LI_HORIZONTAL prop = RadioProperty(self, 'orientation', self, ['wxLI_HORIZONTAL', 'wxLI_VERTICAL'], label=_("orientation")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop.panel, 0, wx.ALL|wx.EXPAND, 10) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.BOTTOM|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, value): def set_orientation(o): self.orientation = self.orientations[o] return (lambda: self.orientation, set_orientation) # end of inner class dialog = Dialog() dialog.ShowModal() label = 'static_line_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'static_line_%d' % number[0] static_line = EditStaticLine(label, parent, wx.NewId(), dialog.orientation, sizer, pos, common.property_panel) node = Tree.Node(static_line) static_line.node = node static_line.set_flag("wxEXPAND") static_line.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditStaticLine objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") static_line = EditStaticLine(name, parent, wx.NewId(), 0, sizer, pos, common.property_panel) sizer.set_item(static_line.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(static_line) static_line.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return static_line def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditStaticLine'] = builder common.widgets_from_xml['EditStaticLine'] = xml_builder return common.make_object_button('EditStaticLine', 'icons/static_line.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_line/__init__.py0000644000175000017500000000066310743421035023641 0ustar stanistani# __init__.py: static line widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import static_line return static_line.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/codegen.py0000644000175000017500000000463610743421035023213 0ustar stanistani# codegen.py: code generator functions for wxListCtrl objects # $Id: codegen.py,v 1.8 2007/03/27 07:01:57 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style and style != 'wxLC_ICON': # default style style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s%s)\n' % (obj.name, klass, parent, id, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxListCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get('style') if style and style != 'wxLC_ICON': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s%s);\n' % (obj.name, obj.klass, parent, id, extra)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxListEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditListCtrl'] = 'wxListCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxListCtrl', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxListCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/perl_codegen.py0000644000175000017500000000255410743421035024232 0ustar stanistani# perl_codegen.py : perl generator functions for wxListCtrl objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:41:03 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not(style and style != 'wxLC_ICON'): # default style style = '' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditListCtrl'] = 'wxListCtrl' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxListCtrl', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/list_ctrl.py0000644000175000017500000002271610743421035023605 0ustar stanistani# text_ctrl.py: wxListCtrl objects # $Id: list_ctrl.py,v 1.15 2007/03/27 07:01:57 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * class EditListCtrl(ManagedBase): """\ Class to handle wxListCtrl objects """ events = [ 'EVT_LIST_BEGIN_DRAG', 'EVT_LIST_BEGIN_RDRAG', 'EVT_LIST_BEGIN_LABEL_EDIT', 'EVT_LIST_END_LABEL_EDIT', 'EVT_LIST_DELETE_ITEM', 'EVT_LIST_DELETE_ALL_ITEMS', 'EVT_LIST_ITEM_SELECTED', 'EVT_LIST_ITEM_DESELECTED', 'EVT_LIST_ITEM_ACTIVATED', 'EVT_LIST_ITEM_FOCUSED', 'EVT_LIST_ITEM_MIDDLE_CLICK', 'EVT_LIST_ITEM_RIGHT_CLICK', 'EVT_LIST_KEY_DOWN', 'EVT_LIST_INSERT_ITEM', 'EVT_LIST_COL_CLICK', 'EVT_LIST_COL_RIGHT_CLICK', 'EVT_LIST_COL_BEGIN_DRAG', 'EVT_LIST_COL_DRAGGING', 'EVT_LIST_COL_END_DRAG', 'EVT_LIST_CACHE_HINT', ] def __init__(self, name, parent, id, sizer, pos, property_window, show=True, style=wx.LC_REPORT|wx.SUNKEN_BORDER): ManagedBase.__init__(self, name, 'wxListCtrl', parent, id, sizer, pos, property_window, show=show) self.style = style self.access_functions['style'] = (self.get_style, self.set_style) # style property self.style_pos = (wx.LC_LIST, wx.LC_REPORT, wx.LC_ICON, wx.LC_VIRTUAL, wx.LC_SMALL_ICON, wx.LC_ALIGN_TOP, wx.LC_ALIGN_LEFT, wx.LC_AUTOARRANGE, wx.LC_EDIT_LABELS, wx.LC_NO_HEADER, wx.LC_SINGLE_SEL, wx.LC_SORT_ASCENDING, wx.LC_SORT_DESCENDING, wx.LC_HRULES, wx.LC_VRULES, wx.SIMPLE_BORDER, wx.DOUBLE_BORDER, wx.SUNKEN_BORDER, wx.RAISED_BORDER, wx.STATIC_BORDER, wx.NO_BORDER, wx.WANTS_CHARS, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE) style_labels = ('#section#' + _('Style'), 'wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_VIRTUAL', 'wxLC_SMALL_ICON', 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER', 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING', 'wxLC_HRULES', 'wxLC_VRULES', 'wxSIMPLE_BORDER', 'wxDOUBLE_BORDER', 'wxSUNKEN_BORDER', 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_BORDER', 'wxWANTS_CHARS', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE') self.style_tooltips = (_("Multicolumn list view, with optional small icons. Columns are computed automatically, i.e. you don't set columns as in wxLC_REPORT. In other words, the list wraps, unlike a wxListBox."), _("Single or multicolumn report view, with optional header."), _("Large icon view, with optional labels."), _("The application provides items text on demand. May only be used with wxLC_REPORT."), _("Small icon view, with optional labels."), _("Icons align to the top. Win32 default, Win32 only."), _("Icons align to the left."), _("Icons arrange themselves. Win32 only."), _("Labels are editable: the application will be notified when editing starts."), _("No header in report mode."), _("Single selection (default is multiple)."), _("Sort in ascending order (must still supply a comparison callback in SortItems."), _("Sort in descending order (must still supply a comparison callback in SortItems."), _("Draws light horizontal rules between rows in report mode."), _("Draws light vertical rules between columns in report mode"), _("Displays a thin border around the window. wxBORDER is the old name for this style."), _("Displays a double border. Windows and Mac only."), _("Displays a sunken border."), _("Displays a raised border."), _("Displays a border suitable for a static control. Windows only."), _("Displays no border, overriding the default border style for the window."), _("Use this to indicate that the window wants to get all char/key events for all keys - even for keys like TAB or ENTER which are usually used for dialog navigation and which wouldn't be generated without this style. If you need to use this style in order to get the arrows or etc., but would still like to have normal keyboard navigation take place, you should create and send a wxNavigationKeyEvent in response to the key events for Tab and Shift-Tab."), _("On Windows, this style used to disable repainting the window completely when its size is changed. Since this behaviour is now the default, the style is now obsolete and no longer has an effect."), _("Use this style to force a complete redraw of the window whenever it is resized instead of redrawing just the part of the window affected by resizing. Note that this was the behaviour by default before 2.5.1 release and that if you experience redraw problems with code which previously used to work you may want to try this. Currently this style applies on GTK+ 2 and Windows only, and full repainting is always done on other platforms.")) self.properties['style'] = CheckListProperty( self, 'style', None, style_labels, tooltips=self.style_tooltips) def create_widget(self): self.widget = wx.ListCtrl(self.parent.widget, self.id, style=wx.LC_REPORT|wx.SUNKEN_BORDER) # add a couple of columns just for a better appearence (for now) self.widget.InsertColumn(0, _('List Control:')) self.widget.InsertColumn(1, self.name) wx.EVT_LIST_COL_CLICK(self.widget, self.widget.GetId(), self.on_set_focus) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self, sel_marker_parent=self.widget) def set_name(self, name): ManagedBase.set_name(self, name) if self.widget: col = self.widget.GetColumn(1) col.SetText(self.name) self.widget.SetColumn(1, col) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop = self.properties prop['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, 'Widget') self.property_window.Layout() import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditListCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditListCtrl objects. """ name = 'list_ctrl_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'list_ctrl_%d' % number[0] list_ctrl = EditListCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(list_ctrl) list_ctrl.node = node list_ctrl.set_option(1) list_ctrl.set_flag("wxEXPAND") list_ctrl.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) sizer.set_item(list_ctrl.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditListCtrl objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") list_ctrl = EditListCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel, style=0) sizer.set_item(list_ctrl.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(list_ctrl) list_ctrl.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return list_ctrl def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditListCtrl'] = builder common.widgets_from_xml['EditListCtrl'] = xml_builder return common.make_object_button('EditListCtrl', 'icons/list_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/lisp_codegen.py0000644000175000017500000000262110743421035024232 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxListCtrl objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:48 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not(style and style != 'wxLC_ICON'): # default style style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxListCtrl_Create %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditListCtrl'] = 'wxListCtrl' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxListCtrl', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_ctrl/__init__.py0000644000175000017500000000065510743421035023343 0ustar stanistani# __init__.py: list ctrl widget module initialization # $Id: __init__.py,v 1.5 2007/03/27 07:01:57 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import list_ctrl return list_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/codegen.py0000644000175000017500000000757610743421035023045 0ustar stanistani# codegen.py: code generator functions for wxListBox objects # $Id: codegen.py,v 1.14 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) choices = ', '.join([pygen.quote_str(c) for c in choices]) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, choices=[%s]%s)\n' % (obj.name, klass, parent, id, choices, style)) props_buf = pygen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and choices: props_buf.append('self.%s.SetSelection(%s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class ListBoxXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'choices': xrc_write_choices_property(self, outfile, tabs) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class ListBoxXrcObject return ListBoxXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxListBox objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' number = len(choices) ch_arr = '{\n %s\n };\n' % \ ',\n '.join([cppgen.quote_str(c) for c in choices]) style = prop.get("style", "0") init = [] if number: init.append('const wxString %s_choices[] = %s' % (obj.name, ch_arr)) else: init.append('const wxString *%s_choices = NULL;\n' % obj.name) init.append('%s = new %s(%s, %s, wxDefaultPosition, wxDefaultSize, ' '%s, %s_choices, %s);\n' % \ (obj.name, obj.klass, parent, id, number, obj.name, style)) props_buf = cppgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and choices: props_buf.append('%s->SetSelection(%s);\n' % (obj.name, selection)) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditListBox'] = 'wxListBox' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxListBox', PythonCodeGenerator()) pygen.add_property_handler('choices', ChoicesCodeHandler) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxListBox', xrc_code_generator) xrcgen.add_property_handler('choices', ChoicesCodeHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxListBox', CppCodeGenerator()) cppgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/perl_codegen.py0000644000175000017500000000332110743421035024047 0ustar stanistani# perl_codegen.py : perl generator functions for wxListBox objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:40:10 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = '' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); choices = ', '.join([plgen.quote_str(c) for c in choices]) init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, \ wxDefaultSize, [%s], %s);\n' % (obj.name, klass, parent, id, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('$self->{%s}->SetSelection(%s);\n' % (obj.name, selection)) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditListBox'] = 'wxListBox' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxListBox', PerlCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/lisp_codegen.py0000644000175000017500000000347410743421035024065 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxListBox objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:46 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) length = len(choices) choices = ' '.join([plgen.quote_str(c) for c in choices]) init.append('(setf (slot-%s obj) (wxListBox_Create %s %s -1 -1 -1 -1 %s (vector %s) %s))\n' % (obj.name, parent, id, length, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('(wxListBox_SetSelection (slot-%s obj) %s 1)\n' % (obj.name, selection)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditListBox'] = 'wxListBox' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxListBox', LispCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/list_box.py0000644000175000017500000001656710743421035023264 0ustar stanistani# list_box.py: wxListBox objects # $Id: list_box.py,v 1.22 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from ChoicesProperty import * class EditListBox(ManagedBase): events = ['EVT_LISTBOX', 'EVT_LISTBOX_DCLICK'] def __init__(self, name, parent, id, choices, sizer, pos, property_window, show=True): """\ Class to handle wxListBox objects """ ManagedBase.__init__(self, name, 'wxListBox', parent, id, sizer, pos, property_window, show=show) self.selection = 0 self.choices = choices # properties self.access_functions['choices'] = (self.get_choices, self.set_choices) self.properties['choices'] = ChoicesProperty(self, 'choices', None, [(_('Label'), GridProperty.STRING)], len(choices), label=_('choices')) self.access_functions['selection'] = (self.get_selection, self.set_selection) self.style = 0 self.access_functions['style'] = (self.get_style, self.set_style) self.properties['selection'] = SpinProperty(self, 'selection', None, r=(0, len(choices)-1), label=_('selection')) self.style_pos = (wx.LB_SINGLE, wx.LB_MULTIPLE, wx.LB_EXTENDED, wx.LB_HSCROLL, wx.LB_ALWAYS_SB, wx.LB_NEEDED_SB, wx.LB_SORT) style_labels = ('#section#' + _('Style'), 'wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL', 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT') self.style_tooltips = (_('Single-selection list.'), _('Multiple-selection list: the user can toggle multiple items on ' 'and off.'), _('Extended-selection list: the user can select multiple items ' 'using the SHIFT key and the mouse or special key combinations.'), _('Create horizontal scrollbar if contents are too wide ' '(Windows only).'), _('Always show a vertical scrollbar.'), _('Only create a vertical scrollbar if needed.'), _('The listbox contents are sorted in alphabetical order.')) self.properties['style'] = CheckListProperty( self, 'style', None, style_labels, tooltips=self.style_tooltips) def create_widget(self): self.widget = wx.ListBox(self.parent.widget, self.id, choices=self.choices) self.set_selection(self.selection) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) self.properties['choices'].display(panel) self.properties['style'].display(panel) self.properties['selection'].display(panel) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) szr.Add(self.properties['selection'].panel, 0, wx.EXPAND) ch = self.properties['choices'].panel ch.SetSize((ch.GetSize()[0]-20, 200)) szr.Add(self.properties['choices'].panel, 1, wx.ALL|wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetSize() from math import ceil panel.SetScrollbars(5, 5, int(ceil(w/5.0)), int(ceil(h/5.0))) self.notebook.AddPage(panel, 'Widget') self.properties['choices'].set_col_sizes([-1]) def get_property_handler(self, prop_name): if prop_name == 'choices': return ChoicesHandler(self) return ManagedBase.get_property_handler(self, prop_name) def get_choices(self): return zip(self.choices) def set_choices(self, values): self.choices = [ misc.wxstr(v[0]) for v in values ] self.properties['selection'].set_range(0, len(self.choices)-1) if self.widget: self.widget.Clear() for c in self.choices: self.widget.Append(c) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) self.widget.SetSelection( int(self.properties['selection'].get_value())) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_selection(self): return self.selection def set_selection(self, value): value = int(value) if value != self.selection: self.selection = value if self.widget: self.widget.SetSelection(value) # end of class EditListBox def builder(parent, sizer, pos, number=[1]): """\ factory function for EditListBox objects. """ name = 'list_box_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'list_box_%d' % number[0] list_box = EditListBox(name, parent, wx.NewId(), #[misc._encode('choice 1')], sizer, pos, [], sizer, pos, common.property_panel) node = Tree.Node(list_box) ## sizer.set_item(pos, size=list_box.GetBestSize()) list_box.node = node list_box.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditListBox objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") list_box = EditListBox(name, parent, wx.NewId(), [], sizer, pos, common.property_panel) sizer.set_item(list_box.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=list_box.GetBestSize()) node = Tree.Node(list_box) list_box.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return list_box def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditListBox'] = builder common.widgets_from_xml['EditListBox'] = xml_builder return common.make_object_button('EditListBox', 'icons/list_box.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/list_box/__init__.py0000644000175000017500000000065210743421035023164 0ustar stanistani# __init__.py: list box widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import list_box return list_box.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/codegen.py0000644000175000017500000000441610743421035023220 0ustar stanistani# codegen.py: code generator functions for wxTextCtrl objects # $Id: codegen.py,v 1.13 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) value = pygen.quote_str(prop.get('value', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, value, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ generates C++ code for wxTextCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] value = cppgen.quote_str(prop.get('value', '')) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get('style') if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, value, extra)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditTextCtrl'] = 'wxTextCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxTextCtrl', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxTextCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/perl_codegen.py0000644000175000017500000000257310743421035024244 0ustar stanistani# perl_codegen.py : perl generator functions for wxTextCtrl objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:48:47 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = plgen.quote_str(prop.get('value', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style : style = '' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, value, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditTextCtrl'] = 'wxTextCtrl' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxTextCtrl', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/lisp_codegen.py0000644000175000017500000000265110743421035024246 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxTextCtrl objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:42:16 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = plgen.quote_str(prop.get('value', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxTextCtrl_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, value, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditTextCtrl'] = 'wxTextCtrl' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxTextCtrl', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/__init__.py0000644000175000017500000000065510743421035023354 0ustar stanistani# __init__.py: text ctrl widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import text_ctrl return text_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/text_ctrl/text_ctrl.py0000644000175000017500000001442610743421035023626 0ustar stanistani# text_ctrl.py: wxTextCtrl objects # $Id: text_ctrl.py,v 1.18 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase, WindowBase from tree import Tree import common, misc from widget_properties import * class EditTextCtrl(ManagedBase): """\ Class to handle wxTextCtrl objects """ events = [ 'EVT_TEXT', 'EVT_TEXT_ENTER', 'EVT_TEXT_URL', 'EVT_TEXT_MAXLEN', ] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): import config ManagedBase.__init__(self, name, 'wxTextCtrl', parent, id, sizer, pos, property_window, show=show) self.value = "" self.style = 0 self.access_functions['value'] = (self.get_value, self.set_value) self.access_functions['style'] = (self.get_style, self.set_style) prop = self.properties # value property prop['value'] = TextProperty(self, 'value', None, multiline=True, label=_("value")) # style property self.style_pos = (wx.TE_PROCESS_ENTER, wx.TE_PROCESS_TAB, wx.TE_MULTILINE,wx.TE_PASSWORD, wx.TE_READONLY, wx.HSCROLL, wx.TE_RICH, wx.TE_RICH2, wx.TE_AUTO_URL, wx.TE_NOHIDESEL, wx.TE_CENTRE, wx.TE_RIGHT, wx.TE_LINEWRAP, wx.TE_WORDWRAP, wx.NO_BORDER) style_labels = ('#section#' + _('Style'), 'wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE', 'wxTE_PASSWORD', 'wxTE_READONLY', 'wxHSCROLL', 'wxTE_RICH', 'wxTE_RICH2', 'wxTE_AUTO_URL', 'wxTE_NOHIDESEL', 'wxTE_CENTRE', 'wxTE_RIGHT', 'wxTE_LINEWRAP', 'wxTE_WORDWRAP', 'wxNO_BORDER') prop['style'] = CheckListProperty(self, 'style', None, style_labels) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): value = self.value if self.style & wx.TE_MULTILINE: value = value.replace('\\n', '\n') self.widget = wx.TextCtrl(self.parent.widget, self.id, value=value, style=self.style & wx.TE_MULTILINE) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop = self.properties prop['value'].display(panel) prop['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop['value'].panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, _('Widget')) import math panel.SetScrollbars( 1, 5, 1, int(math.ceil(panel.GetClientSize()[1]/5.0))) def get_value(self): return self.value def set_value(self, value): value = misc.wxstr(value) if not misc.streq(value, self.value): self.value = value if self.style & wx.TE_MULTILINE: value = value.replace('\\n', '\n') if self.widget: self.widget.SetValue(value) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): old = self.style & wx.TE_MULTILINE value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: new = self.style & wx.TE_MULTILINE if old != new: focused = misc.focused_widget is self self.sel_marker.Destroy() w = self.widget self.create_widget() if not self.properties['size'].is_active(): self.widget.SetSize(self.widget.GetBestSize()) self.finish_widget_creation() self.sizer.layout() if focused: misc.focused_widget = self self.sel_marker.Show(True) # end of class EditTextCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditTextCtrl objects. """ name = 'text_ctrl_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'text_ctrl_%d' % number[0] text = EditTextCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(text) text.node = node text.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditTextCtrl objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") text = EditTextCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) sizer.set_item(text.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(text) text.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return text def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditTextCtrl'] = builder common.widgets_from_xml['EditTextCtrl'] = xml_builder return common.make_object_button('EditTextCtrl', 'icons/text_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/datepicker_ctrl/codegen.py0000644000175000017500000001137110743421035024345 0ustar stanistani# codegen.py: code generator functions for wxDatePickerCtrl objects # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/widgets/datepicker_ctrl/codegen.py,v 1.2 2007/03/27 07:02:01 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: #def __init__(self): #self.pygen = common.code_writers['python'] #def __get_import_modules(self): #if self.pygen.use_new_namespace: #return ['import wx.calendar\n'] #else: #return ['from wxPython.calendar import *\n'] #import_modules = property(__get_import_modules) #def cn(self, c): #""" Create names according to if the new namescace (wx) was selected #@type c: string #@param c: the name which should be altered #@rtype: string #@return: the orignial name with a prefix according to which namespace the user selected #""" #if self.pygen.use_new_namespace: #if c[:2] == 'wx': #c = c[2:] #return 'wx.calendar.' + c #else: #return c #def cn_f(self, flags): #""" Same as cn(c) but for flags #@rtype: string #""" #if self.pygen.use_new_namespace: #return "|".join([self.cn(f) for f in str(flags).split('|')]) #else: #return str(flags) def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) #label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s%s)\n' % # (obj.name, klass, parent, id, label, style)) (obj.name, klass,parent, id, style)) props_buf = pygen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('self.%s.SetDefault()\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class DatePickerCtrlXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'label': # translate & into _ as accelerator marker val2 = val.replace('&', '_') if val.count('&&') > 0: while True: index = val.find('&&') if index < 0: break val = val2[:index] + '&&' + val2[index+2:] else: val = val2 xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class DatePickerCtrlXrcObject return DatePickerCtrlXrcObject(obj) class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ fuction that generates python code for wxDatePickerCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, %s' % style #label = cppgen.quote_str(prop.get('label', '')) init = [ '%s = new %s(%s, %s%s);\n' % # (obj.name, obj.klass, parent, id, label, extra) ] (obj.name, obj.klass, parent, id, extra) ] props_buf = cppgen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('%s->SetDefault();\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditDatePickerCtrl'] = 'wxDatePickerCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxDatePickerCtrl', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxDatePickerCtrl', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxDatePickerCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/datepicker_ctrl/__init__.py0000644000175000017500000000100310743421035024467 0ustar stanistani# __init__.py: datepicker_ctrl widget module initialization # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/widgets/datepicker_ctrl/__init__.py,v 1.2 2007/03/27 07:02:01 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import datepicker_ctrl return datepicker_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/datepicker_ctrl/datepicker_ctrl.py0000644000175000017500000001400110743421035026071 0ustar stanistani# datepicker_ctrl.py: wxDatePickerCtrl objects # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/widgets/datepicker_ctrl/datepicker_ctrl.py,v 1.5 2007/03/27 07:02:01 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * class EditDatePickerCtrl(ManagedBase): events = ['EVT_DATE_CHANGED'] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): """\ Class to handle wxDatePickerCtrl objects """ import config self.default = False ManagedBase.__init__(self, name, 'wxDatePickerCtrl', parent, id, sizer, pos, property_window, show=show) #self.access_functions['label'] = (self.get_label, self.set_label) #self.properties['label'] = TextProperty(self, 'label', None, # multiline=True, label=_("label")) self.access_functions['default'] = (self.get_default, self.set_default) self.access_functions['style'] = (self.get_style, self.set_style) self.properties['default'] = CheckBoxProperty(self, 'default', None, label=_("default")) style_labels = ('#section#' + _('Style'), 'wxDP_SPIN', 'wxDP_DROPDOWN', 'wxDP_DEFAULT', 'wxDP_ALLOWNONE', 'wxDP_SHOWCENTURY') self.style_pos = (wx.DP_SPIN, wx.DP_DROPDOWN, wx.DP_DEFAULT, wx.DP_ALLOWNONE, wx.DP_SHOWCENTURY) self.tooltips = (_("Creates a control without a month calendar drop down but with spin-control-like arrows to change individual date components. This style is not supported by the generic version."), _("Creates a control with a month calendar drop-down part from which the user can select a date."), _("Creates a control with the style that is best supported for the current platform (currently wxDP_SPIN under Windows and wxDP_DROPDOWN elsewhere)."), _("With this style, the control allows the user to not enter any valid date at all. Without it - the default - the control always has some valid date."), _("Forces display of the century in the default date format. Without this style the century could be displayed, or not, depending on the default date representation in the system.")) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels,tooltips=self.tooltips) if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) #self.properties['label'].display(panel) self.properties['default'].display(panel) self.properties['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) #szr.Add(self.properties['label'].panel, 0, wxEXPAND) szr.Add(self.properties['default'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(1) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def create_widget(self): try: #TODO add all the other parameters for the DatePickerCtrl intial date self.widget = wx.DatePickerCtrl(self.parent.widget, self.id ,style=self.style) except AttributeError: self.widget = wx.DatePickerCtrl(self.parent.widget, self.id) def get_default(self): return self.default def set_default(self, value): self.default = bool(int(value)) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) # end of class EditDatePickerCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditDatePickerCtrl objects. """ label = 'datepicker_ctrl_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'datepicker_ctrl_%d' % number[0] datepicker_ctrl = EditDatePickerCtrl(label, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(datepicker_ctrl) datepicker_ctrl.node = node datepicker_ctrl.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditDatePickerCtrl objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") datepicker_ctrl = EditDatePickerCtrl(label, parent, wx.NewId(), sizer, pos, common.property_panel, show=False) node = Tree.Node(datepicker_ctrl) datepicker_ctrl.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return datepicker_ctrl def initialize(): """\ initialization function for the module. @rtype: wxBitmapButton @return: an icon to be added to the main palette. """ common.widgets['EditDatePickerCtrl'] = builder common.widgets_from_xml['EditDatePickerCtrl'] = xml_builder return common.make_object_button('EditDatePickerCtrl', 'icons/datepicker_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/calendar_ctrl/codegen.py0000644000175000017500000001137710743421035024011 0ustar stanistani# codegen.py: code generator functions for wxCalendarCtrl objects # $Id: codegen.py,v 1.7 2007/08/07 12:18:34 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator(object): def __init__(self): self.pygen = common.code_writers['python'] self.real_class_name = 'CalendarCtrl' def __get_import_modules(self): if self.pygen.use_new_namespace: return ['import wx.calendar\n'] else: return ['from wxPython.calendar import *\n'] import_modules = property(__get_import_modules) def cn(self, c): """ Create names according to if the new namescace (wx) was selected @type c: string @param c: the name which should be altered @rtype: string @return: the orignial name with a prefix according to which namespace the user selected """ if self.pygen.use_new_namespace: if c[:2] == 'wx': c = c[2:] return 'wx.calendar.' + c else: return c def cn_f(self, flags): """ Same as cn(c) but for flags @rtype: string """ if self.pygen.use_new_namespace: return "|".join([self.cn(f) for f in str(flags).split('|')]) else: return str(flags) def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) #label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % self.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base or klass == self.real_class_name: klass = self.cn(klass) init.append('self.%s = %s(%s, %s%s)\n' % # (obj.name, klass, parent, id, label, style)) (obj.name, klass,parent, id, style)) props_buf = pygen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('self.%s.SetDefault()\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class CalendarCtrlXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'label': # translate & into _ as accelerator marker val2 = val.replace('&', '_') if val.count('&&') > 0: while True: index = val.find('&&') if index < 0: break val = val2[:index] + '&&' + val2[index+2:] else: val = val2 xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class CalendarCtrlXrcObject return CalendarCtrlXrcObject(obj) class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ fuction that generates python code for wxCalendarCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, %s'\ % style #label = cppgen.quote_str(prop.get('label', '')) init = [ '%s = new %s(%s, %s%s);\n' % # (obj.name, obj.klass, parent, id, label, extra) ] (obj.name, obj.klass, parent, id, extra) ] props_buf = cppgen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('%s->SetDefault();\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditCalendarCtrl'] = 'wxCalendarCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxCalendarCtrl', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxCalendarCtrl', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxCalendarCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/calendar_ctrl/__init__.py0000644000175000017500000000077310743421035024142 0ustar stanistani# __init__.py: calendar_ctrl widget module initialization # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/widgets/calendar_ctrl/__init__.py,v 1.2 2007/03/27 07:02:04 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import calendar_ctrl return calendar_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/calendar_ctrl/calendar_ctrl.py0000644000175000017500000001376110743421035025201 0ustar stanistani# calendar_ctrl.py: wxCalendarCtrl objects # $Header: /home/alb/tmp/wxglade_cvs_backup/wxGlade/widgets/calendar_ctrl/calendar_ctrl.py,v 1.11 2007/03/27 07:02:04 agriggio Exp $ # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * #import needed modules for the wxCalendarCtrl from wx.calendar import * class EditCalendarCtrl(ManagedBase): events = [ 'EVT_CALENDAR', 'EVT_CALENDAR_SEL_CHANGE', 'EVT_CALENDAR_DAY', 'EVT_CALENDAR_MONTH', 'EVT_CALENDAR_YEAR', 'EVT_CALENDAR_WEEKDAY_CLICKED'] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): """\ Class to handle wxCalendarCtrl objects """ import config self.default = False ManagedBase.__init__(self, name, 'CalendarCtrl', parent, id, sizer, pos, property_window, show=show) #self.access_functions['label'] = (self.get_label, self.set_label) #self.properties['label'] = TextProperty(self, 'label', None, # multiline=True) self.access_functions['default'] = (self.get_default, self.set_default) self.access_functions['style'] = (self.get_style, self.set_style) self.properties['default'] = CheckBoxProperty(self, 'default', None, label=_("default")) style_labels = ('#section#' + _('Style'), 'wxCAL_SUNDAY_FIRST', 'wxCAL_MONDAY_FIRST', 'wxCAL_SHOW_HOLIDAYS', 'wxCAL_NO_YEAR_CHANGE', 'wxCAL_NO_MONTH_CHANGE', 'wxCAL_SHOW_SURROUNDING_WEEKS','wxCAL_SEQUENTIAL_MONTH_SELECTION') self.style_pos = (CAL_SUNDAY_FIRST, CAL_MONDAY_FIRST, CAL_SHOW_HOLIDAYS, CAL_NO_YEAR_CHANGE, CAL_NO_MONTH_CHANGE, CAL_SHOW_SURROUNDING_WEEKS, CAL_SEQUENTIAL_MONTH_SELECTION) self.tooltips=(_("Show Sunday as the first day in the week"), _("Show Monday as the first day in the week"), _("Highlight holidays in the calendar"), _("Disable the year changing"), _("Disable the month (and, implicitly, the year) changing"), _("Show the neighbouring weeks in the previous and next months"), _("Use alternative, more compact, style for the month and year selection controls.")) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels,tooltips=self.tooltips) if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) #self.properties['label'].display(panel) self.properties['default'].display(panel) self.properties['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) #szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['default'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(1) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def create_widget(self): try: #TODO add all the other parameters for the CalendarCtrl especialy style=self.style and the initial date self.widget = CalendarCtrl(self.parent.widget, self.id ,style=self.style) except AttributeError: self.widget = CalendarCtrl(self.parent.widget, self.id) def get_default(self): return self.default def set_default(self, value): self.default = bool(int(value)) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) # end of class EditCalendarCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditCalendarCtrl objects. """ label = 'calendar_ctrl_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'calendar_ctrl_%d' % number[0] calendar_ctrl = EditCalendarCtrl(label, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(calendar_ctrl) calendar_ctrl.node = node calendar_ctrl.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditCalendarCtrl objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") calendar_ctrl = EditCalendarCtrl(label, parent, wx.NewId(), sizer, pos, common.property_panel, show=False) node = Tree.Node(calendar_ctrl) calendar_ctrl.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return calendar_ctrl def initialize(): """\ initialization function for the module. @rtype: wxBitmapButton @return: an icon to be added to the main palette. """ common.widgets['EditCalendarCtrl'] = builder common.widgets_from_xml['EditCalendarCtrl'] = xml_builder return common.make_object_button('EditCalendarCtrl', 'icons/calendar_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/codegen.py0000644000175000017500000001564310743421035023034 0ustar stanistani# codegen.py: code generator functions for wxNotebook objects # $Id: codegen.py,v 1.21 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class TabsCodeHandler: def __init__(self): self.tabs = [] self.curr_tab_name = [] self.tab_window = None def start_elem(self, name, attrs): if name == 'tab': window = attrs.get('window') if not window: return self.tab_window = window self.curr_tab_name = [] def end_elem(self, name, code_obj): if name == 'tabs': code_obj.properties['tabs'] = self.tabs return True elif name == 'tab': tab_name = "".join(self.curr_tab_name) if self.tab_window: self.tabs.append((tab_name, self.tab_window)) return False def char_data(self, data): self.curr_tab_name.append(data) # end of class TabsCodeHandler class PythonCodeGenerator: def get_code(self, window): pygen = common.code_writers['python'] prop = window.properties id_name, id = pygen.generate_code_id(window) layout_props = [] tabs = prop.get('tabs', []) for label, tab_win in tabs: layout_props.append('self.%s.AddPage(self.%s, %s)\n' % \ (window.name, tab_win, pygen.quote_str(label))) if not window.parent.is_toplevel: parent = 'self.%s' % window.parent.name else: parent = 'self' if window.is_toplevel: l = [] if id_name: l.append(id_name) l.append('self.%s = %s(%s, %s)\n' % (window.name, pygen.without_package(window.klass), parent,id)) return l, [], [] style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' klass = window.klass if window.preview: klass = 'wxNotebook' init = [] if id_name: init.append(id_name) init.append(('self.%s = ' + pygen.cn(klass) + '(%s, %s%s)\n') % (window.name, parent, id, style)) props_buf = pygen.generate_common_properties(window) return init, props_buf, layout_props def get_properties_code(self, obj): prop = obj.properties pygen = common.code_writers['python'] props_buf = [] tabs = prop.get('tabs', []) for label, window in tabs: props_buf.append('self.AddPage(self.%s, %s)\n' % \ (window, pygen.quote_str(label))) props_buf.extend(pygen.generate_common_properties(obj)) return props_buf # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] from xml.sax.saxutils import escape class NotebookXrcObject(xrcgen.DefaultXrcObject): def write(self, outfile, ntabs): if self.properties.has_key('tabs'): self.tabs = self.properties['tabs'] del self.properties['tabs'] else: self.tabs = [] self.index = 0 # always use a wxNotebookSizer self.properties['usenotebooksizer'] = '1' if 'no_custom_class' in self.properties: del self.properties['no_custom_class'] xrcgen.DefaultXrcObject.write(self, outfile, ntabs) def write_child_prologue(self, child, outfile, ntabs): if self.tabs: tab_s = ' ' * ntabs outfile.write(tab_s + '\n') outfile.write(tab_s + '\n' % \ escape(self.tabs[self.index][0])) self.index += 1 def write_child_epilogue(self, child, outfile, ntabs): if self.tabs: outfile.write(' '*ntabs + '\n') return NotebookXrcObject(obj) class CppCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', '0')] extra_headers = [''] def get_code(self, window): """\ generates the C++ code for wxNotebook """ cppgen = common.code_writers['C++'] prop = window.properties id_name, id = cppgen.generate_code_id(window) if id_name: ids = [ id_name ] else: ids = [] layout_props = [] tabs = prop.get('tabs', []) for label, tab_win in tabs: layout_props.append('%s->AddPage(%s, %s);\n' % \ (window.name, tab_win, cppgen.quote_str(label))) if not window.parent.is_toplevel: parent = '%s' % window.parent.name else: parent = 'this' if window.is_toplevel: l = ['%s = new %s(%s, %s);\n' % (window.name, window.klass, parent, id)] return l, ids, [], [] extra = '' style = prop.get('style') if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s%s);\n' % (window.name, window.klass, parent, id, extra) ] props_buf = cppgen.generate_common_properties(window) return init, ids, props_buf, layout_props def get_properties_code(self, obj): prop = obj.properties cppgen = common.code_writers['C++'] props_buf = [] tabs = prop.get('tabs', []) for label, window in tabs: props_buf.append('AddPage(%s, %s);\n' % \ (window, cppgen.quote_str(label))) props_buf.extend(cppgen.generate_common_properties(obj)) return props_buf def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxNotebookEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditNotebook'] = 'wxNotebook' common.class_names['NotebookPane'] = 'wxPanel' common.toplevels['EditNotebook'] = 1 common.toplevels['NotebookPane'] = 1 # python code generation functions pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxNotebook', PythonCodeGenerator()) pygen.add_property_handler('tabs', TabsCodeHandler, 'wxNotebook') xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxNotebook', xrc_code_generator) xrcgen.add_property_handler('tabs', TabsCodeHandler, 'wxNotebook') cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxNotebook', CppCodeGenerator()) cppgen.add_property_handler('tabs', TabsCodeHandler, 'wxNotebook') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/notebook.py0000644000175000017500000003654610743421035023255 0ustar stanistani# notebook.py: wxNotebook objects # $Id: notebook.py,v 1.32 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase, WindowBase from edit_sizers.edit_sizers import Sizer, SizerSlot try: from panel import EditPanel _has_panel = True except ImportError: _has_panel = False def _ugly_hack_for_win32_notebook_bug(notebook_widget): """\ The name should say all. The problem is hard to explain, so let me just illustrate a way to reproduce the bug: 1. create a frame in wxGlade, add a notebook with two pages 2. put a button on the first page, and a text ctrl on the second one 3. save the app 4. exit wxGlade, and comment out the body of this function 5. restart wxGlade and load the previous app 6. Try to click on the button on the first page of the notebook, and see what happens... If you don't see what I mean, please drop me an email with your version of Windows, Python and wxPython, because I really want to understand what's going on... So far I've not been able to reproduce the problem on a standalone minimal app, but as time permits I'll try again... if you succeed, please let me know. """ #print '_ugly_hack_for_win32_notebook_bug' index_ok = notebook_widget.GetSelection() for i in range(notebook_widget.GetPageCount()): notebook_widget.GetPage(i).Hide() notebook_widget.GetPage(index_ok).Show() class NotebookVirtualSizer(Sizer): '''\ "Virtual sizer" responsible for the management of the pages of a Notebook. ''' def __init__(self, *args, **kwds): Sizer.__init__(self, *args, **kwds) self._itempos = 0 def set_item(self, pos, option=None, flag=None, border=None, size=None, force_layout=True): """\ Updates the layout of the item at the given pos. """ if not self.window.widget: return pos -= 1 label, item = self.window.tabs[pos] if not item or not item.widget: return if not (pos < self.window.widget.GetPageCount()): self.window.widget.AddPage(item.widget, label) elif self.window.widget.GetPage(pos) is not item.widget: #self.window.widget.RemovePage(pos) self.window.widget.DeletePage(pos) self.window.widget.InsertPage(pos, item.widget, label) self.window.widget.SetSelection(pos) try: misc.wxCallAfter(item.sel_marker.update) except AttributeError, e: #print e pass if self.window.sizer is not None: self.window.sizer.set_item( self.window.pos, size=self.window.widget.GetBestSize()) def add_item(self, item, pos=None, option=0, flag=0, border=0, size=None, force_layout=True): """\ Adds an item to self.window. """ #print 'pos:', pos, 'item.name:', item.name self.window.tabs[pos-1][1] = item item._dont_destroy = True def free_slot(self, pos, force_layout=True): """\ Replaces the element at pos with an empty slot """ if self.window._is_removing_pages or not self.window.widget: return slot = SizerSlot(self.window, self, pos) #print 'free:', slot, slot.pos, pos slot.show_widget(True) pos = pos-1 label, item = self.window.tabs[pos] self.window.widget.RemovePage(pos) self.window.widget.InsertPage(pos, slot.widget, label) self.window.widget.SetSelection(pos) def get_itempos(self, attrs): """\ Get position of sizer item (used in xml_parse) """ self._itempos += 1 return self._itempos def is_virtual(self): return True # end of class NotebookVirtualSizer class NotebookPagesProperty(GridProperty): def write(self, outfile, tabs): from xml.sax.saxutils import escape, quoteattr write = outfile.write write(' ' * tabs + '\n') tab_s = ' ' * (tabs+1) import widget_properties value = self.get_value() for i in range(len(value)): val = value[i] v = escape(widget_properties._encode(val[0])) window = None try: t = self.owner.tabs[i] if t[0] == val[0]: window = t[1] except: pass if window: write('%s' % (tab_s, quoteattr(window.name))) write(v) write('\n') write(' ' * tabs + '\n') # end of class NotebookPagesProperty class TabsHandler: def __init__(self, parent): self.parent = parent self.tab_names = [] self.curr_tab = [] def start_elem(self, name, attrs): pass def end_elem(self, name): if name == 'tabs': self.parent.tabs = [[misc.wxstr(name), None] for name in \ self.tab_names] self.parent.properties['tabs'].set_value([[name] for name in \ self.tab_names]) return True elif name == 'tab': self.tab_names.append("".join(self.curr_tab)) self.curr_tab = [] return False def char_data(self, data): self.curr_tab.append(data) # end of class TabsHandler class EditNotebook(ManagedBase): _custom_base_classes = True events = ['EVT_NOTEBOOK_PAGE_CHANGED', 'EVT_NOTEBOOK_PAGE_CHANGING'] def __init__(self, name, parent, id, style, sizer, pos, property_window, show=True): """\ Class to handle wxNotebook objects """ ManagedBase.__init__(self, name, 'wxNotebook', parent, id, sizer, pos, property_window, show=show) self.virtual_sizer = NotebookVirtualSizer(self) self._is_removing_pages = False self.style = style self.tabs = [ ['tab1', None] ] # list of pages of this notebook # (actually a list of # 2-list label, window) self.access_functions['style'] = (self.get_tab_pos, self.set_tab_pos) self.properties['style'] = HiddenProperty(self, 'style', label=_("style")) self.access_functions['tabs'] = (self.get_tabs, self.set_tabs) tab_cols = [('Tab label', GridProperty.STRING)] self.properties['tabs'] = NotebookPagesProperty(self, 'tabs', None, tab_cols, label=_("tabs")) del tab_cols self.nb_sizer = None self._create_slots = False self.no_custom_class = False self.access_functions['no_custom_class'] = (self.get_no_custom_class, self.set_no_custom_class) self.properties['no_custom_class'] = CheckBoxProperty( self, 'no_custom_class', label=_("Don't generate code for this custom class")) def create_widget(self): self.widget = wx.Notebook(self.parent.widget, self.id, style=self.style) if not misc.check_wx_version(2, 5, 2): self.nb_sizer = wx.NotebookSizer(self.widget) def show_widget(self, yes): ManagedBase.show_widget(self, yes) if yes and wx.Platform in ('__WXMSW__', '__WXMAC__'): misc.wxCallAfter(_ugly_hack_for_win32_notebook_bug, self.widget) if self._create_slots: self._create_slots = False for i in range(len(self.tabs)): if self.tabs[i][1] is None: self.tabs = self.tabs[:i] self.properties['tabs'].set_value(self.get_tabs()) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self) # replace 'self' with 'self.nb_sizer' in 'self.sizer' if not misc.check_wx_version(2, 5, 2): self.sizer._fix_notebook(self.pos, self.nb_sizer) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) self.properties['no_custom_class'].display(panel) self.properties['tabs'].display(panel) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.properties['no_custom_class'].panel, 0, wx.ALL|wx.EXPAND, 3) sizer.Add(self.properties['tabs'].panel, 1, wx.ALL|wx.EXPAND, 3) panel.SetAutoLayout(True) panel.SetSizer(sizer) sizer.Fit(panel) self.notebook.AddPage(panel, _('Widget')) self.properties['tabs'].set_col_sizes([-1]) def on_set_focus(self, event): self.show_properties() event.Skip() def _add_tab(self, window, pos): if window is None: window = SizerSlot(self, self.virtual_sizer, pos) self.tabs[pos-1][1] = window else: window._dont_destroy = True node = Tree.Node(window) window.node = node common.app_tree.add(node, self.node) if self.widget: window.show_widget(True) self.virtual_sizer.set_item(pos) try: misc.wxCallAfter(window.sel_marker.update) except AttributeError, e: #print e pass def get_tabs(self): return [ [n] for n, w in self.tabs ] def set_tabs(self, tabs): delta = len(self.tabs) - len(tabs) if delta > 0: self._is_removing_pages = True # we have to remove some pages i = len(tabs) if self.widget: for n, window in self.tabs[i:]: self.widget.RemovePage(i) window.remove(False) del self.tabs[i:] if self.widget: self.widget.SetSelection(0) self._is_removing_pages = False elif delta < 0: # we have to add some pages number = len(self.tabs)+1 while common.app_tree.has_name(self.name + '_pane_%s' % number): number += 1 pos = len(self.tabs) for i in range(-delta): self.tabs.append(['', None]) pos += 1 if _has_panel: window = EditPanel(self.name + '_pane_%s' % number, self, -1, self.virtual_sizer, pos, self.property_window) self._add_tab(window, pos) else: self._add_tab(None, pos) number += 1 if self.widget: self.widget.SetSelection(self.widget.GetPageCount()-1) # finally, we must update the labels of the tabs for i in range(len(tabs)): tt = misc.wxstr(tabs[i][0]) if self.widget: self.widget.SetPageText(i, tt) self.tabs[i][0] = tt def delete(self): if self.widget: self.widget.DeleteAllPages() ManagedBase.delete(self) def get_property_handler(self, name): if name == 'tabs': return TabsHandler(self) return ManagedBase.get_property_handler(self, name) def find_page(self, page): """\ returns the index of the given page in the notebook, or -1 if the page cannot be found """ if not self.widget: return -1 for i in range(len(self.tabs)): if self.tabs[i][1] is page: if i < self.widget.GetPageCount(): return i else: return -1 return -1 def get_tab_pos(self): styles = { wx.NB_LEFT: 'wxNB_LEFT', wx.NB_RIGHT: 'wxNB_RIGHT', wx.NB_BOTTOM: 'wxNB_BOTTOM' } return styles.get(self.style, '0') def set_tab_pos(self, value): styles = { 'wxNB_LEFT': wx.NB_LEFT, 'wxNB_RIGHT': wx.NB_RIGHT, 'wxNB_BOTTOM': wx.NB_BOTTOM } self.style = styles.get(value, 0) def get_no_custom_class(self): return self.no_custom_class def set_no_custom_class(self, value): self.no_custom_class = bool(int(value)) # end of class EditNotebook def builder(parent, sizer, pos, number=[1]): """\ factory function for EditNotebook objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select tab placement')) self.styles = [ 0, wx.NB_BOTTOM, wx.NB_LEFT, wx.NB_RIGHT ] self.style = 0 prop = RadioProperty(self, 'tab_placement', self, [_('Top'), _('Bottom'), _('Left'), _('Right')], columns=2, label=_('tab_placement')) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop.panel, 0, wx.ALL|wx.EXPAND, 10) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.BOTTOM|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, value): def set_style(s): self.style = self.styles[s] return (lambda: self.style, set_style) # end of inner class dialog = Dialog() dialog.ShowModal() name = 'notebook_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'notebook_%d' % number[0] window = EditNotebook(name, parent, wx.NewId(), dialog.style, sizer, pos, common.property_panel, show=False) if _has_panel: pane1 = EditPanel(name + '_pane_1', window, wx.NewId(), window.virtual_sizer, 1, common.property_panel) node = Tree.Node(window) window.node = node window.virtual_sizer.node = node window.set_option(1) window.set_flag("wxEXPAND") window.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) if _has_panel: window._add_tab(pane1, 1) sizer.set_item(window.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditNotebook objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if not sizer or not sizeritem: raise XmlParsingError, _("sizer or sizeritem object cannot be None") window = EditNotebook(name, parent, wx.NewId(), 0, sizer, pos, common.property_panel, True) window._create_slots = True sizer.set_item(window.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(window) window.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return window def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditNotebook'] = builder common.widgets_from_xml['EditNotebook'] = xml_builder return common.make_object_button('EditNotebook', 'icons/notebook.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/perl_codegen.py0000644000175000017500000000534210743421035024051 0ustar stanistani# perl_codegen.py : perl generator functions for wxNotebook objects # $Id: perl_codegen.py,v 1.6 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import TabsCodeHandler class PerlCodeGenerator: #wxNotebook(parent, id, pos, size, style, name) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, window): plgen = common.code_writers['perl'] prop = window.properties id_name, id = plgen.generate_code_id(window) layout_props = [] tabs = prop.get('tabs', []) for label, tab_win in tabs: layout_props.append('$self->{%s}->AddPage($self->{%s}, %s);\n' % \ (window.name, tab_win, plgen.quote_str(label))) if not window.parent.is_toplevel: parent = '$self->{%s}' % window.parent.name else: parent = '$self' if window.is_toplevel: klass = window.base if klass != window.klass: klass = window.klass; else: klass = plgen.cn(klass) #klass.replace('wx','Wx::',1) l = [] if id_name: l.append(id_name) l.append('$self->{%s} = %s->new(%s, %s);\n' % (window.name, klass, parent,id)) return l, [], [] style = prop.get("style") if style: style = "%s" % style else: style = '' init = [] if id_name: init.append(id_name) init.append('$self->{%s} = %s->new(%s, %s, ' 'wxDefaultPosition, wxDefaultSize, %s);\n' % (window.name, plgen.cn(window.klass), parent, id, style)) props_buf = plgen.generate_common_properties(window) return init, props_buf, layout_props def get_properties_code(self, obj): prop = obj.properties plgen = common.code_writers['perl'] props_buf = [] tabs = prop.get('tabs', []) for label, window in tabs: props_buf.append('$self->AddPage($self->{%s}, %s);\n' % \ (window, plgen.quote_str(label))) props_buf.extend(plgen.generate_common_properties(obj)) return props_buf # end of class PerlCodeGenerator def initialize(): common.class_names['EditNotebook'] = 'wxNotebook' common.class_names['NotebookPane'] = 'wxPanel' common.toplevels['EditNotebook'] = 1 common.toplevels['NotebookPane'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxNotebook', PerlCodeGenerator()) plgen.add_property_handler('tabs', TabsCodeHandler, 'wxNotebook') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/lisp_codegen.py0000644000175000017500000000543410743421035024060 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxNotebook objects # $Id: lisp_codegen.py,v 1.2 2005/09/27 02:20:44 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import TabsCodeHandler class LispCodeGenerator: #wxNotebook(parent, id, pos, size, style, name) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, window): plgen = common.code_writers['lisp'] prop = window.properties id_name, id = plgen.generate_code_id(window) layout_props = [] tabs = prop.get('tabs', []) for label, tab_win in tabs: tab_win = tab_win.replace('_','-') layout_props.append('(wxNotebook_AddPage (slot-%s obj) (slot-%s obj) %s 1 -1)\n' % \ (window.name, tab_win, plgen.quote_str(label))) if not window.parent.is_toplevel: parent = '(slot-%s obj)' % window.parent.name else: parent = '(slot-top-window obj)' if window.is_toplevel: l = [] if id_name: l.append(id_name) l.append('(setf (slot-%s obj) (wxNotebook_Create %s %s -1 -1 -1 -1 wxNB_TOP))\n' % (window.name, parent,id)) return l, [], [] style = prop.get("style") if style: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style else: style = 'wxNB_TOP' init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxNotebook_Create %s %s -1 -1 -1 -1 %s))\n' % (window.name, parent, id, style)) props_buf = plgen.generate_common_properties(window) return init, props_buf, layout_props def get_properties_code(self, obj): prop = obj.properties plgen = common.code_writers['lisp'] props_buf = [] tabs = prop.get('tabs', []) for label, window in tabs: props_buf.append('(wxNotebook_AddPage (slot-%s obj) page %s 1 -1);\n' % \ (window, plgen.quote_str(label))) props_buf.extend(plgen.generate_common_properties(obj)) return props_buf # end of class LispCodeGenerator def initialize(): common.class_names['EditNotebook'] = 'wxNotebook' common.class_names['NotebookPane'] = 'wxPanel' common.toplevels['EditNotebook'] = 1 common.toplevels['NotebookPane'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxNotebook', LispCodeGenerator()) plgen.add_property_handler('tabs', TabsCodeHandler, 'wxNotebook') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/notebook/__init__.py0000644000175000017500000000065210743421035023161 0ustar stanistani# __init__.py: notebook widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import notebook return notebook.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/codegen.py0000644000175000017500000000643010743421035023541 0ustar stanistani# codegen.py: code generator functions for wxStaticText objects # $Id: codegen.py,v 1.14 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties attribute = pygen.test_attribute(obj) id_name, id = pygen.generate_code_id(obj) label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) if attribute: prefix = 'self.' else: prefix = '' klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('%s%s = %s(%s, %s, %s%s)\n' % (prefix, obj.name, klass, parent, id, label, style)) props_buf = pygen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxStaticText objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] attribute = cppgen.test_attribute(obj) label = cppgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style if attribute: prefix = '' else: prefix = '%s* ' % obj.klass init = ['%s%s = new %s(%s, %s, %s%s);\n' % (prefix, obj.name, obj.klass, parent, id, label, extra) ] props_buf = cppgen.generate_common_properties(obj) if not attribute: return [], ids, [], init + props_buf return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): def write(self, *args, **kwds): try: del self.properties['attribute'] except KeyError: pass xrcgen.DefaultXrcObject.write(self, *args, **kwds) return XrcCodeGenerator(obj) def initialize(): common.class_names['EditStaticText'] = 'wxStaticText' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxStaticText', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxStaticText', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxStaticText', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/perl_codegen.py0000644000175000017500000000343410743421035024564 0ustar stanistani# perl_codegen.py : perl generator functions for wxStaticText objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:47:30 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D. H. aka crazyinsomniac on sourceforge # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = '' if id_name: init.append(id_name) if attribute: prefix = '$self->{%s}' % obj.name else: prefix = 'my $%s' % obj.name obj.name = '$' + obj.name klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('%s = %s->new(%s, %s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (prefix, klass, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditStaticText'] = 'wxStaticText' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxStaticText', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/static_text.py0000644000175000017500000001343510743421035024473 0ustar stanistani# static_text.py: wxStaticText objects # $Id: static_text.py,v 1.16 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * try: import wx.lib.stattext StaticText = wx.lib.stattext.GenStaticText except ImportError: StaticText = wx.StaticText class EditStaticText(ManagedBase): def __init__(self, name, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxStaticText objects """ import config ManagedBase.__init__(self, name, 'wxStaticText', parent, id, sizer, pos, property_window, show=show) self.label = label self.style = 0 self.attribute = True self.access_functions['label'] = (self.get_label, self.set_label) self.access_functions['style'] = (self.get_style, self.set_style) def set_attribute(v): self.attribute = int(v) self.access_functions['attribute'] = (lambda : self.attribute, set_attribute) self.properties['label'] = TextProperty(self, 'label', None, multiline=True, label=_('label')) self.style_pos = (wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_CENTRE, wx.ST_NO_AUTORESIZE) style_labels = ('#section#' + _('Style'), 'wxALIGN_LEFT', 'wxALIGN_RIGHT', 'wxALIGN_CENTRE', 'wxST_NO_AUTORESIZE') self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self.properties['attribute'] = CheckBoxProperty( self, 'attribute', None, _('Store as attribute'), write_always=True) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = StaticText(self.parent.widget, self.id, self.label.replace('\\n', '\n')) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['label'].display(panel) self.properties['style'].display(panel) self.properties['attribute'].display(panel) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) szr.Add(self.properties['attribute'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, _('Widget')) def get_label(self): return self.label def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): self.label = value if self.widget: self.widget.SetLabel(value.replace('\\n', '\n')) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) # end of class EditStaticText def builder(parent, sizer, pos, number=[1]): """\ factory function for EditStaticText objects. """ label = 'label_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'label_%d' % number[0] static_text = EditStaticText(label, parent, wx.NewId(), misc._encode(label), sizer, pos, common.property_panel) node = Tree.Node(static_text) static_text.node = node static_text.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditStaticText objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") static_text = EditStaticText(label, parent, wx.NewId(), "", sizer, pos, common.property_panel) sizer.set_item(static_text.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=static_text.GetBestSize()) node = Tree.Node(static_text) static_text.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return static_text def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditStaticText'] = builder common.widgets_from_xml['EditStaticText'] = xml_builder return common.make_object_button('EditStaticText', 'icons/static_text.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/lisp_codegen.py0000644000175000017500000000326710743421035024575 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxStaticText objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:43:12 efuzzyone Exp $ # # Copyright (c) 2002-2004 D. H. aka crazyinsomniac on sourceforge # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxStaticText_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditStaticText'] = 'wxStaticText' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxStaticText', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_text/__init__.py0000644000175000017500000000066310743421035023676 0ustar stanistani# __init__.py: static text widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:52 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import static_text return static_text.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/codegen.py0000644000175000017500000001020310743421035022512 0ustar stanistani# codegen.py: code generator functions for wxButton objects # $Id: codegen.py,v 1.18 2007/04/01 12:42:16 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn prop = obj.properties id_name, id = pygen.generate_code_id(obj) stockitem = prop.get('stockitem', 'None') if stockitem != 'None': id = pygen.cn("wxID_" + stockitem) label = pygen.quote_str('') else: label = pygen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, label, style)) props_buf = pygen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('self.%s.SetDefault()\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class ButtonXrcObject(xrcgen.DefaultXrcObject): def write(self, out_file, ntabs): stockitem = self.properties.get('stockitem', 'None') if stockitem != 'None': self.name = 'wxID_' + stockitem del self.properties['stockitem'] try: del self.properties['label'] except KeyError: pass xrcgen.DefaultXrcObject.write(self, out_file, ntabs) def write_property(self, name, val, outfile, tabs): if name == 'label': # translate & into _ as accelerator marker val2 = val.replace('&', '_') if val.count('&&') > 0: while True: index = val.find('&&') if index < 0: break val = val2[:index] + '&&' + val2[index+2:] else: val = val2 xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class ButtonXrcObject return ButtonXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ fuction that generates python code for wxButton objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style stockitem = prop.get('stockitem', 'None') if stockitem != 'None': label = cppgen.quote_str('') id = "wxID_" + stockitem else: label = cppgen.quote_str(prop.get('label', '')) init = [ '%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, label, extra) ] props_buf = cppgen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('%s->SetDefault();\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditButton'] = 'wxButton' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxButton', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxButton', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxButton', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/perl_codegen.py0000644000175000017500000000347010743421035023544 0ustar stanistani# perl_codegen.py : perl generator functions for wxButton objects # $Id: perl_codegen.py,v 1.8 2007/04/01 12:29:50 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): """\ fuction that generates perl code for wxButton objects. """ init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) stockitem = prop.get('stockitem', 'None') if stockitem != 'None': label = plgen.quote_str('') id = "wxID_" + stockitem else: label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: extra = '' else: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s%s);\n' % (obj.name, klass, parent, id, label, extra)) props_buf = plgen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('$self->{%s}->SetDefault();\n' % obj.name) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditButton'] = 'wxButton' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxButton', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/lisp_codegen.py0000644000175000017500000000344710743421035023555 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxButton objects # $Id: lisp_codegen.py,v 1.3 2007/04/01 12:29:50 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): """\ fuction that generates lisp code for wxButton objects. """ init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) stockitem = prop.get('stockitem', 'None') if stockitem != 'None': label = plgen.quote_str('') id = "wxID_" + stockitem else: label = plgen.quote_str(prop.get('label', '')) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxButton_Create %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, label, style)) props_buf = plgen.generate_common_properties(obj) if prop.get('default', False): props_buf.append('(wxButton_SetDefault (slot-%s obj))\n' % obj.name) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditButton'] = 'wxButton' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxButton', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/__init__.py0000644000175000017500000000064410743421035022655 0ustar stanistani# __init__.py: button widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import button return button.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/button.py0000644000175000017500000001742510743421035022436 0ustar stanistani# button.py: wxButton objects # $Id: button.py,v 1.24 2007/03/31 09:55:43 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from button_stockitems import * class EditButton(ManagedBase): events = ['EVT_BUTTON'] def __init__(self, name, parent, id, label, sizer, pos, property_window, show=True): """\ Class to handle wxButton objects """ import config self.label = label self.default = False self.stockitem = "None" ManagedBase.__init__(self, name, 'wxButton', parent, id, sizer, pos, property_window, show=show) self.access_functions['label'] = (self.get_label, self.set_label) self.properties['label'] = TextProperty(self, 'label', None, multiline=True) self.access_functions['stockitem'] = (self.get_stockitem, self.set_stockitem) self.access_functions['default'] = (self.get_default, self.set_default) self.access_functions['style'] = (self.get_style, self.set_style) self.properties['default'] = CheckBoxProperty(self, 'default', None, label=_("default")) #Get the list of items, and add a 'None' choices = ButtonStockItems.stock_ids.keys() choices.sort() choices[:0] = ['None'] self.properties['stockitem'] = ComboBoxProperty( self, 'stockitem', choices, can_disable=True, label=_("stockitem")) self.style_pos = (wx.BU_LEFT, wx.BU_RIGHT, wx.BU_TOP, wx.BU_BOTTOM, wx.BU_EXACTFIT,wx.NO_BORDER) style_labels = ('#section#' + _('Style'), 'wxBU_LEFT', 'wxBU_RIGHT', 'wxBU_TOP', 'wxBU_BOTTOM', 'wxBU_EXACTFIT','wxNO_BORDER') #The tooltips tuple style_tooltips=(_("Left-justifies the label. Windows and GTK+ only."), _("Right-justifies the bitmap label. Windows and GTK+ " "only."), _("Aligns the label to the top of the button. Windows " "and GTK+ only."), _("Aligns the label to the bottom of the button. " "Windows and GTK+ only."), _("Creates the button as small as possible instead of " "making it of the standard size (which is the default " "behaviour )."), _("Creates a flat button. Windows and GTK+ only.")) self.properties['style'] = CheckListProperty( self, 'style', None, style_labels, tooltips=style_tooltips) # the tooltips tuple is # passed as the last # argument # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) self.properties['label'].display(panel) self.properties['stockitem'].display(panel) self.properties['default'].display(panel) self.properties['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['stockitem'].panel, 0, wx.EXPAND) szr.Add(self.properties['default'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(1) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') if self.stockitem != "None": s = common.app_tree.app.saved self.set_stockitem(self.stockitem) common.app_tree.app.saved = s def get_label(self): return self.label def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): if self.widget: self.widget.SetLabel(value.replace('\\n', '\n')) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) self.label = value def create_widget(self): try: self.widget = wx.Button(self.parent.widget, self.id, self.label, style=self.style) except AttributeError: self.widget = wx.Button(self.parent.widget, self.id, self.label) def get_default(self): return self.default def set_default(self, value): self.default = bool(int(value)) def get_stockitem(self): return self.stockitem def set_stockitem(self, value): self.stockitem = misc.wxstr(value) if self.stockitem != "None": l = ButtonStockItems.stock_ids[self.stockitem]; self.set_label(l) self.properties['label'].set_value(l) if self.properties['label'].panel is not None: self.properties['label'].text.Enable(False) self.window_id = "wxID_" + self.stockitem self.properties['id'].set_value(self.window_id) self.properties['id'].toggle_active(False) else: if self.properties['label'].panel is not None: self.properties['label'].text.Enable(True) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) # end of class EditButton def builder(parent, sizer, pos, number=[1]): """\ factory function for EditButton objects. """ label = 'button_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'button_%d' % number[0] button = EditButton(label, parent, wx.NewId(), misc._encode(label), sizer, pos, common.property_panel) node = Tree.Node(button) button.node = node button.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditButton objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") button = EditButton(label, parent, wx.NewId(), '', sizer, pos, common.property_panel, show=False) node = Tree.Node(button) button.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return button def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditButton'] = builder common.widgets_from_xml['EditButton'] = xml_builder return common.make_object_button('EditButton', 'icons/button.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/button/button_stockitems.py0000644000175000017500000000424510743421035024677 0ustar stanistaniclass ButtonStockItems: stock_ids = { "ADD" : "Add", "APPLY" : "&Apply", "BOLD" : "&Bold", "CANCEL" : "&Cancel", "CLEAR" : "&Clear", "CLOSE" : "&Close", "COPY" : "&Copy", "CUT" : "Cu&t", "DELETE" : "&Delete", "FIND" : "&Find", "REPLACE" : "Find and rep&lace", "BACKWARD" : "&Back", "DOWN" : "&Down", "FORWARD" : "&Forward", "UP" : "&Up", "HELP" : "&Help", "HOME" : "&Home", "INDENT" : "Indent", "INDEX" : "&Index", "ITALIC" : "&Italic", "JUSTIFY_CENTER" : "Centered", "JUSTIFY_FILL" : "Justified", "JUSTIFY_LEFT" : "Align Left", "JUSTIFY_RIGHT" : "Align Right", "NEW" : "&New", "NO" : "&No", "OK" : "&OK", "OPEN" : "&Open", "PASTE" : "&Paste", "PREFERENCES" : "&Preferences", "PRINT" : "&Print", "PREVIEW" : "Print previe&w", "PROPERTIES" : "&Properties", "EXIT" : "&Quit", "REDO" : "&Redo", "REFRESH" : "Refresh", "REMOVE" : "Remove", "REVERT_TO_SAVED" : "Revert to Saved", "SAVE" : "&Save", "SAVEAS" : "Save &As...", "STOP" : "&Stop", "UNDELETE" : "Undelete", "UNDERLINE" : "&Underline", "UNDO" : "&Undo", "UNINDENT" : "&Unindent", "YES" : "&Yes", "ZOOM_100" : "&Actual Size", "ZOOM_FIT" : "Zoom to &Fit", "ZOOM_IN" : "Zoom &In", "ZOOM_OUT" : "Zoom &Out", } spe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/codegen.py0000644000175000017500000001424310743421035022306 0ustar stanistani# codegen.py: code generator functions for wxPanel objects # $Id: codegen.py,v 1.19 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, panel): pygen = common.code_writers['python'] cn = pygen.cn cn_f = pygen.cn_f prop = panel.properties try: scrollable = int(prop['scrollable']) except: scrollable = False id_name, id = pygen.generate_code_id(panel) if not panel.parent.is_toplevel: parent = 'self.%s' % panel.parent.name else: parent = 'self' if panel.is_toplevel: l = [] if id_name: l.append(id_name) l.append('self.%s = %s(%s, %s)\n' % (panel.name, pygen.without_package(panel.klass), parent, id)) return l, [], [] init = [] if id_name: init.append(id_name) style = prop.get("style", 'wxTAB_TRAVERSAL') if scrollable or style != 'wxTAB_TRAVERSAL': style = ", style=%s" % cn_f(style) else: style = '' # ALB 2005-11-19 if not int(panel.properties.get('no_custom_class', False)) \ or panel.preview: if scrollable: klass = cn('wxScrolledWindow') else: klass = cn('wxPanel') else: klass = panel.klass init.append('self.%s = %s(%s, %s%s)\n' % \ (panel.name, klass, parent, id, style)) props_buf = pygen.generate_common_properties(panel) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('self.%s.SetScrollRate(%s)\n' % (panel.name, sr)) return init, props_buf, [] def get_properties_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties try: scrollable = int(prop['scrollable']) except: scrollable = False props_buf = pygen.generate_common_properties(obj) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('self.SetScrollRate(%s)\n' % sr) return props_buf # end of class PythonCodeGenerator class CppCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', '0')] def get_code(self, panel): """\ generates the C++ code for wxPanel objects """ cppgen = common.code_writers['C++'] prop = panel.properties try: scrollable = int(prop['scrollable']) except: scrollable = False id_name, id = cppgen.generate_code_id(panel) if id_name: ids = [ id_name ] else: ids = [] if not panel.parent.is_toplevel: parent = '%s' % panel.parent.name else: parent = 'this' if panel.is_toplevel: l = ['%s = new %s(%s, %s);\n' % (panel.name, panel.klass, parent, id)] return l, ids, [], [] extra = '' style = prop.get("style", 'wxTAB_TRAVERSAL') if scrollable or style != 'wxTAB_TRAVERSAL': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style # ALB 2005-11-19 if not int(panel.properties.get('no_custom_class', False)): if scrollable: klass = 'wxScrolledWindow' else: klass = 'wxPanel' else: klass = panel.klass init = ['%s = new %s(%s, %s%s);\n' % (panel.name, klass, parent, id, extra) ] props_buf = cppgen.generate_common_properties(panel) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('%s->SetScrollRate(%s);\n' % (panel.name, sr)) return init, ids, props_buf, [] def get_properties_code(self, obj): cppgen = common.code_writers['C++'] prop = obj.properties try: scrollable = int(prop['scrollable']) except: scrollable = False props_buf = cppgen.generate_common_properties(obj) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('SetScrollRate(%s);\n' % sr) return props_buf # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): def write(self, *args, **kwds): if 'scrollable' in self.properties: style = self.properties.get('style', '').split('|') try: style.remove('wxTAB_TRAVERSAL') except ValueError: pass self.properties['style'] = '|'.join(style) for prop in ('scrollable', 'scroll_rate'): try: del self.properties[prop] except KeyError: pass if 'no_custom_class' in self.properties: del self.properties['no_custom_class'] xrcgen.DefaultXrcObject.write(self, *args, **kwds) return XrcCodeGenerator(obj) def initialize(): common.class_names['EditPanel'] = 'wxPanel' common.class_names['EditTopLevelPanel'] = 'wxPanel' common.toplevels['EditPanel'] = 1 common.toplevels['EditTopLevelPanel'] = 1 common.class_names['EditScrolledWindow'] = 'wxScrolledWindow' common.class_names['EditTopLevelScrolledWindow'] = 'wxScrolledWindow' common.toplevels['EditScrolledWindow'] = 1 common.toplevels['EditTopLevelScrolledWindow'] = 1 # python code generation functions pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxPanel', PythonCodeGenerator()) pygen.add_widget_handler('wxScrolledWindow', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxPanel', CppCodeGenerator()) cppgen.add_widget_handler('wxScrolledWindow', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxPanel', xrc_code_generator) xrcgen.add_widget_handler('wxScrolledWindow', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/perl_codegen.py0000644000175000017500000000571410743421035023333 0ustar stanistani# perl_codegen.py : perl generator functions for wxPanel objects # $Id: perl_codegen.py,v 1.11 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: #wxScrolledWindow(parent, id, pos, size, style, name ) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, panel): plgen = common.code_writers['perl'] prop = panel.properties try: scrollable = int(prop['scrollable']) except: scrollable = False id_name, id = plgen.generate_code_id(panel) if not panel.parent.is_toplevel: parent = '$self->{%s}' % panel.parent.name else: parent = '$self' if panel.is_toplevel: l = [] if id_name: l.append(id_name) klass = panel.base; if klass != panel.klass : klass = panel.klass; else: klass = klass.replace('wx','Wx::',1); l.append('$self->{%s} = %s->new(%s, %s);\n' % (panel.name, klass, parent, id)) return l, [], [] init = [] if id_name: init.append(id_name) style = prop.get("style", 'wxTAB_TRAVERSAL') if not( scrollable or style != 'wxTAB_TRAVERSAL' ): style = '' # ALB 2005-11-19 if not int(panel.properties.get('no_custom_class', False)): if scrollable: klass = 'Wx::ScrolledWindow' else: klass = 'Wx::Panel' else: klass = plgen.cn(panel.klass) init.append('$self->{%s} = %s->new(%s, %s, \ wxDefaultPosition, wxDefaultSize, %s);\n' % (panel.name, klass, parent, id, style)) props_buf = plgen.generate_common_properties(panel) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('$self->{%s}->SetScrollRate(%s);\n' % (panel.name, sr)) return init, props_buf, [] def get_properties_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties try: scrollable = int(prop['scrollable']) except: scrollable = False props_buf = plgen.generate_common_properties(obj) if scrollable: sr = prop.get('scroll_rate', '0, 0') props_buf.append('$self->SetScrollRate(%s);\n' % sr) return props_buf # end of class PerlCodeGenerator def initialize(): common.class_names['EditPanel'] = 'wxPanel' common.class_names['EditTopLevelPanel'] = 'wxPanel' common.toplevels['EditPanel'] = 1 common.toplevels['EditTopLevelPanel'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxPanel', PerlCodeGenerator()) plgen.add_widget_handler('wxScrolledWindow', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/lisp_codegen.py0000644000175000017500000000563010743421035023335 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxPanel objects # $Id: lisp_codegen.py,v 1.2 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: #wxScrolledWindow(parent, id, pos, size, style, name ) new_signature = [ '$parent', '$id', '$pos', '$size', '$style', '$name' ] def get_code(self, panel): plgen = common.code_writers['lisp'] prop = panel.properties try: scrollable = int(prop['scrollable']) except: scrollable = False id_name, id = plgen.generate_code_id(panel) if not panel.parent.is_toplevel: parent = '(slot-%s obj)' % panel.parent.name else: parent = '(slot-top-window obj)' if panel.is_toplevel: l = [] if id_name: l.append(id_name) l.append('(setf (slot-%s obj) (wxPanel_Create %s %s -1 -1 -1 -1))\n' % (panel.name, parent, id)) return l, [], [] init = [] if id_name: init.append(id_name) style = prop.get("style", 'wxTAB_TRAVERSAL') if not( scrollable or style != 'wxTAB_TRAVERSAL' ): style = 'wxTAB_TRAVERSAL' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init.append('(setf (slot-%s obj) ' '(wxPanel_Create %s %s -1 -1 -1 -1 %s))\n' % (panel.name, parent, id, style)) props_buf = plgen.generate_common_properties(panel) if scrollable: sr = prop.get('scroll_rate', '0 0') sr = sr.replace(',',' ') props_buf.append('(wxScrolledWindow:wxScrolledWindow_SetScrollRate' ' (slot-%s obj) %s)\n' % (panel.name, sr)) return init, props_buf, [] def get_properties_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties try: scrollable = int(prop['scrollable']) except: scrollable = False props_buf = plgen.generate_common_properties(obj) if scrollable: sr = prop.get('scroll_rate', '0 0') props_buf.append('(wxScrolledWindow:wxScrolledWindow_SetScrollRate ' '(slot-%s obj))\n' % sr) return props_buf # end of class LispCodeGenerator def initialize(): common.class_names['EditPanel'] = 'wxPanel' common.class_names['EditTopLevelPanel'] = 'wxPanel' common.toplevels['EditPanel'] = 1 common.toplevels['EditTopLevelPanel'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxPanel', LispCodeGenerator()) plgen.add_widget_handler('wxScrolledWindow', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/__init__.py0000644000175000017500000000104610743421035022436 0ustar stanistani# __init__.py: panel widget module initialization # $Id: __init__.py,v 1.10 2007/03/27 07:01:56 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import panel global EditTopLevelPanel; EditTopLevelPanel = panel.EditTopLevelPanel global EditPanel; EditPanel = panel.EditPanel return panel.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/panel/panel.py0000644000175000017500000004354310743421035022006 0ustar stanistani# panel.py: wxPanel objects # $Id: panel.py,v 1.38 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase, TopLevelBase class PanelBase(object): _custom_base_classes = True def __init__(self, style=wx.TAB_TRAVERSAL): """\ Class to handle wxPanel objects """ super(PanelBase, self).__init__() self.top_sizer = None # sizer to handle the layout of children # ------ ALB 2005-11-19: option to disable custom class code generation self.no_custom_class = False self.access_functions['no_custom_class'] = (self.get_no_custom_class, self.set_no_custom_class) self.properties['no_custom_class'] = CheckBoxProperty( self, 'no_custom_class', label=_("Don't generate code for this custom class")) # ------ self.style = style self.access_functions['style'] = (self.get_style, self.set_style) self.style_pos = [wx.SIMPLE_BORDER, wx.DOUBLE_BORDER, wx.SUNKEN_BORDER, wx.RAISED_BORDER, wx.STATIC_BORDER, wx.NO_BORDER, wx.NO_3D, wx.TAB_TRAVERSAL, wx.WANTS_CHARS, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE, wx.CLIP_CHILDREN] style_labels = ('#section#' + _('Style'), 'wxSIMPLE_BORDER', 'wxDOUBLE_BORDER', 'wxSUNKEN_BORDER', 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_BORDER', 'wxNO_3D', 'wxTAB_TRAVERSAL', 'wxWANTS_CHARS', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE', 'wxCLIP_CHILDREN') self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self.access_functions['scrollable'] = (self.get_scrollable, self.set_scrollable) self.scrollable = False self.properties['scrollable'] = CheckBoxProperty( self, 'scrollable', None, label=_("scrollable")) self.scroll_rate = (10, 10) self.access_functions['scroll_rate'] = (self.get_scroll_rate, self.set_scroll_rate) self.properties['scroll_rate'] = TextProperty(self, 'scroll_rate', None, can_disable=True, label=_("scroll_rate")) def finish_widget_creation(self): super(PanelBase, self).finish_widget_creation( sel_marker_parent=self.widget) if not self.scrollable: self.widget.SetScrollRate(0, 0) else: self.widget.SetScrollRate(*self.scroll_rate) # this must be done here since ManagedBase.finish_widget_creation # normally sets EVT_LEFT_DOWN to update_wiew if not self.widget.Disconnect(-1, -1, wx.wxEVT_LEFT_DOWN): print _("EditPanel: Unable to disconnect the event hanlder") wx.EVT_LEFT_DOWN(self.widget, self.drop_sizer) #wx.EVT_SCROLLWIN(self.widget, self._update_markers) def _update_markers(self, event): def get_pos(): x, y = self.widget.GetPosition() xx, yy = self.widget.GetViewStart() return x+xx, y+yy old = self.widget.GetPosition self.widget.GetPosition = get_pos #print self.widget, self.sel_marker.owner self.sel_marker.update() self.widget.GetPosition = old event.Skip() def create_properties(self): super(PanelBase, self).create_properties() panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) panel.SetScrollRate(5, 5) szr = wx.BoxSizer(wx.VERTICAL) self.properties['no_custom_class'].display(panel) szr.Add(self.properties['no_custom_class'].panel, 0, wx.EXPAND) label = self.properties['no_custom_class'].cb label.SetToolTip( wx.ToolTip(_('If this is a custom class, setting this property ' 'prevents wxGlade\nfrom generating the class definition' ' code'))) self.properties['style'].display(panel) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) self.properties['scrollable'].display(panel) szr.Add(self.properties['scrollable'].panel, 0, wx.EXPAND) self.properties['scroll_rate'].display(panel) szr.Add(self.properties['scroll_rate'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def on_enter(self, event): if not self.top_sizer and common.adding_sizer: self.widget.SetCursor(wx.CROSS_CURSOR) else: self.widget.SetCursor(wx.STANDARD_CURSOR) def set_sizer(self, sizer): self.top_sizer = sizer if self.top_sizer and self.top_sizer.widget and self.widget: self.widget.SetAutoLayout(True) self.widget.SetSizer(self.top_sizer.widget) self.widget.Layout() elif self.top_sizer is None and self.widget: self.widget.SetSizer(None) def drop_sizer(self, event): if self.top_sizer or not common.adding_sizer: self.on_set_focus(event) # default behaviour: call show_properties return self.widget.SetCursor(wx.NullCursor) common.widgets[common.widget_to_add](self, None, None) common.adding_widget = common.adding_sizer = False common.widget_to_add = None common.app_tree.app.saved = False def get_widget_best_size(self): if self.top_sizer and self.widget.GetSizer(): self.top_sizer.fit_parent() return self.widget.GetSize() return wx.ScrolledWindow.GetBestSize(self.widget) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] def get_scrollable(self): return self.scrollable def set_scrollable(self, value): self.scrollable = bool(int(value)) if self.scrollable: if self.klass == 'wxPanel': self.klass = 'wxScrolledWindow' self.klass_prop.set_value(self.klass) else: if self.klass == 'wxScrolledWindow': self.klass = 'wxPanel' self.klass_prop.set_value(self.klass) if not self.widget: return if self.scrollable: self.properties['scroll_rate'].toggle_active(True) self.widget.SetScrollRate(*self.scroll_rate) else: self.properties['scroll_rate'].toggle_active(False) self.widget.SetScrollRate(0, 0) def get_scroll_rate(self): return '%d, %d' % self.scroll_rate def set_scroll_rate(self, value): invalid = False try: srx, sry = [int(t) for t in value.split(',', 1)] if srx < 0 or sry < 0: invalid = True except: invalid = True if invalid: self.properties['scroll_rate'].set_value(self.get_scroll_rate()) return self.scroll_rate = srx, sry if self.widget: self.widget.SetScrollRate(srx, sry) def get_no_custom_class(self): return self.no_custom_class def set_no_custom_class(self, value): self.no_custom_class = bool(int(value)) # end of class PanelBase class EditPanel(PanelBase, ManagedBase): def __init__(self, name, parent, id, sizer, pos, property_window, show=True, style=wx.TAB_TRAVERSAL): """\ Class to handle wxPanel objects """ ManagedBase.__init__(self, name, 'wxPanel', parent, id, sizer, pos, property_window, show=show) PanelBase.__init__(self, style) def create_widget(self): #self.widget = wx.Panel(self.parent.widget, self.id, style=0) self.widget = wx.ScrolledWindow(self.parent.widget, self.id, style=0) wx.EVT_ENTER_WINDOW(self.widget, self.on_enter) self.widget.GetBestSize = self.get_widget_best_size if self.sizer.is_virtual(): def GetBestSize(): if self.widget and self.widget.GetSizer(): return self.widget.GetSizer().GetMinSize() #return wx.Panel.GetBestSize(self.widget) return wx.ScrolledWindow.GetBestSize(self.widget) self.widget.GetBestSize = GetBestSize def set_sizer(self, sizer): super(EditPanel, self).set_sizer(sizer) if self.top_sizer and self.top_sizer.widget and self.widget: self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def set_scrollable(self, value): super(EditPanel, self).set_scrollable(value) if self.scrollable: # 2003-06-26 ALB: change the "class name", to allow code generation # for a wxScrolledWindow (see Tree.Node.write and # common.class_names usage in xml_parse.py) self._classname = 'EditScrolledWindow' else: self._classname = self.__class__.__name__ def popup_menu(self, event): if self.widget: if not self._rmenu: COPY_ID, REMOVE_ID, CUT_ID = [wx.NewId() for i in range(3)] self._rmenu = misc.wxGladePopupMenu(self.name) misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self._rmenu, COPY_ID, _('Copy\tCtrl+C'), wx.ART_COPY) misc.append_item(self._rmenu, CUT_ID, _('Cut\tCtrl+X'), wx.ART_CUT) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, COPY_ID, bind(self.clipboard_copy)) wx.EVT_MENU(self.widget, CUT_ID, bind(self.clipboard_cut)) # paste PASTE_ID = wx.NewId() misc.append_item(self._rmenu, PASTE_ID, _('Paste\tCtrl+V'), wx.ART_PASTE) wx.EVT_MENU(self.widget, PASTE_ID, bind(self.clipboard_paste)) PREVIEW_ID = wx.NewId() self._rmenu.AppendSeparator() misc.append_item(self._rmenu, PREVIEW_ID, _('Preview')) wx.EVT_MENU(self.widget, PREVIEW_ID, bind(self.preview_parent)) self.setup_preview_menu() self.widget.PopupMenu(self._rmenu, event.GetPosition()) def clipboard_paste(self, *args): import clipboard, xml_parse size = self.widget.GetSize() try: if clipboard.paste(self, None, 0): common.app_tree.app.saved = False self.widget.SetSize(size) except xml_parse.XmlParsingError, e: print _('\nwxGlade-WARNING: only sizers can be pasted here') # end of class EditPanel class EditTopLevelPanel(PanelBase, TopLevelBase): _is_toplevel = False # used to avoid to appear in the "Top Window" property # of the app def __init__(self, name, parent, id, property_window, klass='wxPanel', show=True, style=wx.TAB_TRAVERSAL): TopLevelBase.__init__(self, name, klass, parent, id, property_window, show=show, has_title=False) PanelBase.__init__(self, style) self.base = 'wxPanel' self.skip_on_size = False def create_widget(self): win = wx.Frame(common.palette, -1, misc.design_title(self.name), size=(400, 300)) import os icon = wx.EmptyIcon() xpm = os.path.join(common.wxglade_path, 'icons', 'panel.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) win.SetIcon(icon) #self.widget = wx.Panel(win, self.id, style=0) self.widget = wx.ScrolledWindow(win, self.id, style=0) wx.EVT_ENTER_WINDOW(self.widget, self.on_enter) self.widget.GetBestSize = self.get_widget_best_size #self.widget.SetSize = win.SetSize wx.EVT_CLOSE(win, self.hide_widget) if wx.Platform == '__WXMSW__': win.CentreOnScreen() def show_widget(self, yes): oldval = self.get_size() super(EditTopLevelPanel, self).show_widget(yes) if self.widget: if yes and not self.properties['size'].is_active() \ and self.top_sizer: self.top_sizer.fit_parent() self.widget.GetParent().Show(yes) self.set_size(oldval) def hide_widget(self, *args): super(EditTopLevelPanel, self).hide_widget(*args) self.widget.GetParent().Hide() def set_name(self, name): super(EditTopLevelPanel, self).set_name(name) if self.widget: self.widget.GetParent().SetTitle(misc.design_title(self.name)) def delete(self): win = None if self.widget: win = self.widget.GetParent() super(EditTopLevelPanel, self).delete() if win is not None: win.Destroy() def on_size(self, event): w, h = event.GetSize() if self.skip_on_size: self.skip_on_size = False return super(EditTopLevelPanel, self).on_size(event) self.skip_on_size = True if self.widget.GetParent().GetClientSize() != (w, h): self.widget.GetParent().SetClientSize((w+2, h+2)) def set_scrollable(self, value): super(EditTopLevelPanel, self).set_scrollable(value) if self.scrollable: # 2003-06-26 ALB: change the "class name", to allow code generation # for a wxScrolledWindow (see Tree.Node.write and # common.class_names usage in xml_parse.py) self._classname = 'EditTopLevelScrolledWindow' else: self._classname = self.__class__.__name__ # end of class EditTopLevelPanel def builder(parent, sizer, pos, number=[1]): """\ factory function for EditPanel objects. """ name = 'panel_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'panel_%d' % number[0] panel = EditPanel(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(panel) panel.node = node panel.set_option(1) panel.set_flag("wxEXPAND") panel.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) sizer.set_item(panel.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditPanel objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if not sizer or not sizeritem: raise XmlParsingError, _("sizer or sizeritem object cannot be None") panel = EditPanel(name, parent, wx.NewId(), sizer, pos, common.property_panel, True, style=0) sizer.set_item(panel.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(panel) panel.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return panel def xml_toplevel_builder(attrs, parent, sizer, sizeritem, pos=None): from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") panel = EditTopLevelPanel(label, parent, wx.NewId(), common.property_panel, show=False, style=0) node = Tree.Node(panel) panel.node = node common.app_tree.add(node) return panel def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditPanel'] = builder common.widgets_from_xml['EditPanel'] = xml_builder #common.widgets['EditScrolledWindow'] = builder common.widgets_from_xml['EditScrolledWindow'] = xml_builder common.widgets_from_xml['EditTopLevelPanel'] = xml_toplevel_builder common.widgets_from_xml['EditTopLevelScrolledWindow'] = \ xml_toplevel_builder from tree import WidgetTree import os.path icon = os.path.join(common.wxglade_path, 'icons/panel.xpm') WidgetTree.images['EditTopLevelPanel'] = icon WidgetTree.images['EditScrolledWindow'] = icon WidgetTree.images['EditTopLevelScrolledWindow'] = icon # these are for backwards compatibility (may be removed someday...) common.widgets_from_xml['SplitterPane'] = xml_builder WidgetTree.images['SplitterPane'] = os.path.join(common.wxglade_path, 'icons/panel.xpm') common.widgets_from_xml['NotebookPane'] = xml_builder WidgetTree.images['NotebookPane'] = os.path.join(common.wxglade_path, 'icons/panel.xpm') return common.make_object_button('EditPanel', 'icons/panel.xpm', tip='Add a Panel/ScrolledWindow') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/codegen.py0000644000175000017500000003621110743421035022650 0ustar stanistani# codegen.py: code generator functions for wxToolBar objects # $Id: codegen.py,v 1.23 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os from tool import * class PythonCodeGenerator: def get_properties_code(self, obj): prop = obj.properties pygen = common.code_writers['python'] out = [] append = out.append if obj.is_toplevel: obj_name = 'self' else: obj_name = 'self.' + obj.name bitmapsize = prop.get('bitmapsize') if bitmapsize: try: w, h = [int(i) for i in bitmapsize.split(',')] append('%s.SetToolBitmapSize((%s, %s))\n' % (obj_name, w, h)) except: pass margins = prop.get('margins') if margins: try: w, h = [int(i) for i in margins.split(',')] append('%s.SetMargins((%s, %s))\n' % (obj_name, w, h)) except: pass packing = prop.get('packing') if packing: append('%s.SetToolPacking(%s)\n' % (obj_name, packing)) separation = prop.get('separation') if separation: append('%s.SetToolSeparation(%s)\n' % (obj_name, separation)) append('%s.Realize()\n' % obj_name) return out def get_init_code(self, obj): prop = obj.properties pygen = common.code_writers['python'] cn = pygen.cn out = [] append = out.append tools = obj.properties['toolbar'] ids = [] if obj.is_toplevel: obj_name = 'self' else: obj_name = 'self.' + obj.name def _get_bitmap(bitmap): bmp_preview_path = os.path.join(common.wxglade_path, "icons", "icon.xpm") if not bitmap: return cn('wxNullBitmap') elif bitmap.startswith('var:'): if obj.preview: return "%s('%s', %s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM') ) else: return (cn('wxBitmap') + '(%s,' + cn('wxBITMAP_TYPE_ANY') + ')') % (bitmap[4:].strip()) elif bitmap.startswith('code:'): if obj.preview: return "%s('%s', %s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM') ) else: return '(%s)' % bitmap[5:].strip() else: if obj.preview: import misc bitmap = misc.get_relative_path(bitmap, True) return cn('wxBitmap') + \ ('(%s, ' + cn('wxBITMAP_TYPE_ANY') + ')') % \ pygen.quote_str(bitmap, False, False) for tool in tools: if tool.id == '---': # item is a separator append('%s.AddSeparator()\n' % obj_name) else: name, val = pygen.generate_code_id(None, tool.id) if obj.preview or (not name and (not val or val == '-1')): id = cn('wxNewId()') else: if name: ids.append(name) id = val kinds = ['wxITEM_NORMAL', 'wxITEM_CHECK', 'wxITEM_RADIO'] try: kind = kinds[int(tool.type)] except (IndexError, ValueError): kind = 'wxITEM_NORMAL' bmp1 = _get_bitmap(tool.bitmap1) bmp2 = _get_bitmap(tool.bitmap2) append('%s.AddLabelTool(%s, %s, %s, %s, %s, %s, %s)\n' % (obj_name, id, pygen.quote_str(tool.label), bmp1, bmp2, cn(kind), pygen.quote_str(tool.short_help), pygen.quote_str(tool.long_help))) return ids + out def get_code(self, obj): """\ function that generates Python code for the menubar of a wxFrame. """ pygen = common.code_writers['python'] style = obj.properties.get('style') if style: style = ', style=' + pygen.cn_f('wxTB_HORIZONTAL|' + style) else: style = '' klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init = [ '\n', '# Tool Bar\n', 'self.%s = %s(self, -1%s)\n' % (obj.name, klass, style), 'self.SetToolBar(self.%s)\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append('# Tool Bar end\n') return init, self.get_properties_code(obj), [] def get_events(self, obj): pygen = common.code_writers['python'] cn = pygen.cn out = [] def do_get(tool): ret = [] name, val = pygen.generate_code_id(None, tool.id) if not val: val = '-1' # but this is wrong anyway... if tool.handler: ret.append((val, 'EVT_TOOL', tool.handler)) return ret for tool in obj.properties['toolbar']: out.extend(do_get(tool)) return out # end of class PythonCodeGenerator class ToolsHandler: """Handler for tools of a toolbar""" item_attrs = ('label', 'id', 'short_help', 'type', 'long_help', 'bitmap1', 'bitmap2', 'handler') def __init__(self): self.tools = [] self.curr_tool = None self.attr_val = [] def start_elem(self, name, attrs): if name == 'tool': self.curr_tool = Tool() def end_elem(self, name, code_obj): if name == 'tools': code_obj.properties['toolbar'] = self.tools return True if name == 'tool' and self.curr_tool: self.tools.append(self.curr_tool) elif name in self.item_attrs: setattr(self.curr_tool, name, "".join(self.attr_val)) self.attr_val = [] def char_data(self, data): self.attr_val.append(data) # end of class ToolsHandler def xrc_code_generator(obj): """\ function that generates XRC code for a toolbar """ from xml.sax.saxutils import escape, quoteattr xrcgen = common.code_writers['XRC'] class ToolBarXrcObject(xrcgen.DefaultXrcObject): def append_item(self, item, outfile, tabs): write = outfile.write if item.id == '---': # item is a separator write(' '*tabs + '\n') else: if item.id: name = item.id.split('=', 1)[0] if name: write(' '*tabs + '\n' % quoteattr(name)) else: write(' '*tabs + '\n') else: write(' '*tabs + '\n') # why XRC seems to ignore label?? # this has been fixed on CVS, so add it (it shouldn't hurt...) if item.label: write(' '*(tabs+1) + '\n' % escape(item.label)) if item.short_help: write(' '*(tabs+1) + '%s\n' % \ escape(item.short_help)) if item.long_help: write(' '*(tabs+1) + '%s\n' % \ escape(item.long_help)) if item.bitmap1: write(' '*(tabs+1) + '%s\n' % \ escape(item.bitmap1)) if item.bitmap2: write(' '*(tabs+1) + '%s\n' % \ escape(item.bitmap2)) try: # again, it seems that XRC doesn't support "radio" tools if int(item.type) == 1: write(' '*(tabs+1) + '1\n') # the above has been fixed on CVS, so add a radio if # it's there elif int(item.type) == 2: write(' '*(tabs+1) + '1\n') except ValueError: pass write(' '*tabs + '\n') def write(self, outfile, tabs): tools = self.code_obj.properties['toolbar'] write = outfile.write write(' '*tabs + '\n' % \ quoteattr(self.name)) for prop_name in 'bitmapsize', 'margins': prop = self.code_obj.properties.get(prop_name) if prop: try: w, h = [int(i) for i in prop.split(',')] write(' ' * (tabs+1) + '<%s>%s, %s\n' \ % (prop_name, w, h, prop_name)) except: pass for prop_name in 'packing', 'separation': prop = self.code_obj.properties.get(prop_name) if prop: write(' ' * (tabs+1) + '<%s>%s\n' % \ (prop_name, escape(prop), prop_name)) style = self.code_obj.properties.get('style') if style: style = style.split('|') style.append('wxTB_HORIZONTAL') write(' '*(tabs+1) + '\n' % \ escape('|'.join(style))) for t in tools: self.append_item(t, outfile, tabs+1) write(' '*tabs + '\n') # end of class ToolBarXrcObject return ToolBarXrcObject(obj) class CppCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', 'wxTB_HORIZONTAL|wxTB_NOBORDER')] def get_code(self, obj): """\ generates C++ code for the toolbar of a wxFrame. """ cppgen = common.code_writers['C++'] style = obj.properties.get('style') if style: style = ', wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL|' + \ style else: style = '' init = [ '%s = new %s(this, -1%s);\n' % (obj.name, obj.klass, style), 'SetToolBar(%s);\n' % obj.name ] init.extend(self.get_properties_code(obj)) ids = self.get_ids_code(obj) return init, ids, [], [] def get_properties_code(self, obj): cppgen = common.code_writers['C++'] tools = obj.properties['toolbar'] out = [] append = out.append prop = obj.properties if obj.is_toplevel: obj_name = '' else: obj_name = obj.name + '->' bitmapsize = obj.properties.get('bitmapsize') if bitmapsize: try: w, h = [int(i) for i in bitmapsize.split(',')] append('%sSetToolBitmapSize(wxSize(%s, %s));\n' % \ (obj_name, w, h)) except: pass margins = obj.properties.get('margins') if margins: try: w, h = [int(i) for i in margins.split(',')] append('%sSetMargins(wxSize(%s, %s));\n' % \ (obj_name, w, h)) except: pass packing = prop.get('packing') if packing: append('%sSetToolPacking(%s);\n' % (obj_name, packing)) separation = prop.get('separation') if separation: append('%sSetToolSeparation(%s);\n' % (obj_name, separation)) def _get_bitmap(bitmap): if not bitmap: return 'wxNullBitmap' elif bitmap.startswith('var:'): return 'wxBitmap(%s, wxBITMAP_TYPE_ANY)' % bitmap[4:].strip() elif bitmap.startswith('code:'): return '(%s)' % bitmap[5:].strip() else: return 'wxBitmap(%s, wxBITMAP_TYPE_ANY)' % \ cppgen.quote_str(bitmap, False, False) for tool in tools: if tool.id == '---': # item is a separator append('%sAddSeparator();\n' % obj_name) else: name, val = cppgen.generate_code_id(None, tool.id) if not name and (not val or val == '-1'): id = 'wxNewId()' else: id = val kinds = ['wxITEM_NORMAL', 'wxITEM_CHECK', 'wxITEM_RADIO'] try: kind = kinds[int(tool.type)] except (IndexError, ValueError): kind = 'wxITEM_NORMAL' bmp1 = _get_bitmap(tool.bitmap1) bmp2 = _get_bitmap(tool.bitmap2) append('%sAddTool(%s, %s, %s, %s, %s, %s, %s);\n' % (obj_name, id, cppgen.quote_str(tool.label), bmp1, bmp2, kind, cppgen.quote_str(tool.short_help), cppgen.quote_str(tool.long_help))) append('%sRealize();\n' % obj_name) return out def get_ids_code(self, obj): cppgen = common.code_writers['C++'] ids = [] tools = obj.properties['toolbar'] for item in tools: if item.id == '---': # item is a separator pass # do nothing else: name, val = cppgen.generate_code_id(None, item.id) if name.find('=') != -1: ids.append(name) ## if item.id: ## tokens = item.id.split('=') ## if len(tokens) > 1: ## id = tokens[0] ## ids.append(' = '.join(tokens)) return ids def get_events(self,obj): cppgen = common.code_writers['C++'] out = [] def do_get(tool): ret = [] name, val = cppgen.generate_code_id(None, tool.id) if not val: val = '-1' # but this is wrong anyway... if tool.handler: ret.append((val, 'EVT_TOOL', tool.handler, 'wxCommandEvent')) return ret for tool in obj.properties['toolbar']: out.extend(do_get(tool)) return out # end of class CppCodeGenerator def initialize(): common.class_names['EditToolBar'] = 'wxToolBar' common.toplevels['EditToolBar'] = 1 pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxToolBar', PythonCodeGenerator()) pygen.add_property_handler('tools', ToolsHandler) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxToolBar', xrc_code_generator) xrcgen.add_property_handler('tools', ToolsHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxToolBar', CppCodeGenerator()) cppgen.add_property_handler('tools', ToolsHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/perl_codegen.py0000644000175000017500000001132410743421035023670 0ustar stanistani# perl_codegen.py : perl generator functions for wxMenuBar objects # $Id: perl_codegen.py,v 1.11 2005/08/15 08:03:02 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from tool import * # yay from codegen import ToolsHandler class PerlCodeGenerator: def get_properties_code(self, obj): prop = obj.properties plgen = common.code_writers['perl'] out = [] append = out.append if obj.is_toplevel: obj_name = '$self' else: obj_name = '$self->{%s}' % obj.name bitmapsize = prop.get('bitmapsize') if bitmapsize: try: w, h = [int(i) for i in bitmapsize.split(',')] append('%s->SetToolBitmapSize(wxSIZE(%s, %s));\n' % \ (obj_name, w, h)) except: pass margins = prop.get('margins') if margins: try: w, h = [int(i) for i in margins.split(',')] append('%s->SetMargins(%s, %s);\n' % (obj_name, w, h)) except: pass packing = prop.get('packing') if packing: append('%s->SetToolPacking(%s);\n' % (obj_name, packing)) separation = prop.get('separation') if separation: append('%s->SetToolSeparation(%s);\n' % (obj_name, separation)) append('%s->Realize();\n' % obj_name) return out def get_init_code(self, obj): prop = obj.properties plgen = common.code_writers['perl'] out = [] append = out.append tools = obj.properties['toolbar'] ids = [] if obj.is_toplevel: obj_name = '$self' else: obj_name = '$self->{%s}' % obj.name def _get_bitmap(bitmap): if not bitmap: return 'wxNullBitmap' elif bitmap.startswith('var:'): # this is a variable holding bitmap path var = bitmap[4:].strip() if var[0] != "$": var = "$" + var return 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % var elif bitmap.startswith('code:'): return '(%s)' % bitmap[5:].strip() else: return 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % \ plgen.quote_path(bitmap) for tool in tools: if tool.id == '---': # item is a separator append('%s->AddSeparator();\n' % obj_name) else: name, val = plgen.generate_code_id(None, tool.id) if not name and (not val or val == '-1'): id = 'Wx::NewId()' else: if name: ids.append(name) id = val kinds = ['wxITEM_NORMAL', 'wxITEM_CHECK', 'wxITEM_RADIO'] try: kind = kinds[int(tool.type)] except (IndexError, ValueError): kind = 'wxITEM_NORMAL' bmp1 = _get_bitmap(tool.bitmap1) bmp2 = _get_bitmap(tool.bitmap2) # append('%s->AddLabelTool(%s, %s, %s, %s, %s, %s, %s);\n' % append('%s->AddTool(%s, %s, %s, %s, %s, %s, %s);\n' % (obj_name, id, plgen.quote_str(tool.label), bmp1, bmp2, kind, plgen.quote_str(tool.short_help), plgen.quote_str(tool.long_help))) return ids + out def get_code(self, obj): """\ function that generates Perl code for the menubar of a wxFrame. """ plgen = common.code_writers['perl'] style = obj.properties.get('style') if style: style = 'wxTB_HORIZONTAL|' + style else: style = '' klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init = [ '\n# Tool Bar\n', '$self->{%s} = %s->new($self, -1, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, style), '$self->SetToolBar($self->{%s});\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append('# Tool Bar end\n') return init, self.get_properties_code(obj), [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditToolBar'] = 'wxToolBar' common.toplevels['EditToolBar'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxToolBar', PerlCodeGenerator()) plgen.add_property_handler('tools', ToolsHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/lisp_codegen.py0000644000175000017500000001145710743421035023704 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxMenuBar objects # $Id: lisp_codegen.py,v 1.2 2005/09/25 08:23:40 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from tool import * # yay from codegen import ToolsHandler class LispCodeGenerator: def get_properties_code(self, obj): prop = obj.properties plgen = common.code_writers['lisp'] out = [] append = out.append obj_name = '(slot-%s obj)' % obj.name bitmapsize = prop.get('bitmapsize') if bitmapsize: try: w, h = [int(i) for i in bitmapsize.split(',')] append('(wxToolBar_SetToolBitmapSize %s %s %s)\n' % \ (obj_name, w, h)) except: pass margins = prop.get('margins') if margins: try: w, h = [int(i) for i in margins.split(',')] append('(wxToolBar_SetMargins %s %s %s)\n' % (obj_name, w, h)) except: pass packing = prop.get('packing') if packing: append('(wxToolBar_SetToolPacking %s %s)\n' % (obj_name, packing)) separation = prop.get('separation') if separation: append('(wxToolBar_SetToolSeparation %s %s)\n' % (obj_name, separation)) append('(wxToolBar_Realize %s)\n' % obj_name) return out def get_init_code(self, obj): prop = obj.properties plgen = common.code_writers['lisp'] out = [] append = out.append tools = obj.properties['toolbar'] ids = [] obj_name = '(slot-%s obj)' % obj.name def _get_bitmap(bitmap): if not bitmap: return 'wxNullBitmap' elif bitmap.startswith('var:'): # this is a variable holding bitmap path var = bitmap[4:].strip() if var[0] != "$": var = "$" + var return '(wxBitmap:wxBitmap_CreateLoad %s wxBITMAP_TYPE_ANY)' % var elif bitmap.startswith('code:'): return '(%s)' % bitmap[5:].strip() else: return '(wxBitmap:wxBitmap_CreateLoad %s wxBITMAP_TYPE_ANY)' % \ plgen.quote_str(bitmap) for tool in tools: if tool.id == '---': # item is a separator append('(wxToolBar_AddSeparator %s)\n' % obj_name) else: name, val = plgen.generate_code_id(None, tool.id) if not name and (not val or val == '-1'): id = 'Wx::NewId()' else: if name: ids.append(name) id = val kinds = ['wxITEM_NORMAL', 'wxITEM_CHECK', 'wxITEM_RADIO'] try: kind = kinds[int(tool.type)] except (IndexError, ValueError): kind = 'wxITEM_NORMAL' bmp1 = _get_bitmap(tool.bitmap1) bmp2 = _get_bitmap(tool.bitmap2) # append('%s->AddLabelTool(%s, %s, %s, %s, %s, %s, %s);\n' % append('(wxToolBar_AddTool %s %s %s %s %s %s %s %s)\n' % (obj_name, id, plgen.quote_str(tool.label), bmp1, bmp2, kind, plgen.quote_str(tool.short_help), plgen.quote_str(tool.long_help))) return ids + out def get_code(self, obj): """\ function that generates Lisp code for the toolbar of a wxFrame. """ plgen = common.code_writers['lisp'] style = obj.properties.get('style') if style: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior wxTB_HORIZONTAL %s)' % style else: style = 'wxTB_HORIZONTAL' if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' init = [ '\n\t;;; Tool Bar\n', '(setf (slot-%s obj) (wxToolBar_Create %s -1 -1 -1 -1 -1 %s))\n' % (obj.name, parent, style), '(wxFrame_SetToolBar (slot-top-window obj) (slot-%s obj))\n' % obj.name ] init.extend(self.get_init_code(obj)) init.append(';;; Tool Bar end\n') return init, self.get_properties_code(obj), [] # end of class LispCodeGenerator def initialize(): common.class_names['EditToolBar'] = 'wxToolBar' common.toplevels['EditToolBar'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxToolBar', LispCodeGenerator()) plgen.add_property_handler('tools', ToolsHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/__init__.py0000644000175000017500000000074510743421035023006 0ustar stanistani# __init__.py: toolbar widget module initialization # $Id: __init__.py,v 1.5 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import toolbar global EditToolBar; EditToolBar = toolbar.EditToolBar return toolbar.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/toolbar.py0000644000175000017500000011143410743421035022707 0ustar stanistani# toolbar.py: wxToolBar objects # $Id: toolbar.py,v 1.26 2007/08/07 12:18:33 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx #from wxPython.lib.filebrowsebutton import FileBrowseButton from wx.lib.filebrowsebutton import FileBrowseButton import common, math, misc, os from tree import Tree from tool import * from widget_properties import * from edit_windows import EditBase, TopLevelBase, PreviewMixin class _MyBrowseButton(FileBrowseButton): def createBrowseButton( self): """Create the browse-button control""" ID = wx.NewId() button =wx.Button(self, ID, misc.wxstr(self.buttonText)) button.SetToolTipString(misc.wxstr(self.toolTip)) w = button.GetTextExtent(self.buttonText)[0] + 10 if not misc.check_wx_version(2, 5, 2): button.SetSize((w, -1)) else: button.SetMinSize((w, -1)) wx.EVT_BUTTON(button, ID, self.OnBrowse) return button def OnBrowse (self, event=None): """ Going to browse for file... """ current = self.GetValue() directory = os.path.split(current) if os.path.isdir(current): directory = current current = '' elif directory and os.path.isdir(directory[0]): current = directory[1] directory = directory [0] else: directory = self.startDirectory value = misc.FileSelector(self.dialogTitle, directory, current, wildcard=self.fileMask, flags=self.fileMode) if value: self.SetValue(value) # end of class _MyBrowseButton class ToolsDialog(wx.Dialog): def __init__(self, parent, owner, items=None): wx.Dialog.__init__(self, parent, -1, _("Toolbar editor"), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) ADD_ID, REMOVE_ID, NAME_ID, LABEL_ID, ID_ID, CHECK_RADIO_ID, LIST_ID, \ ADD_SEP_ID, MOVE_UP_ID, MOVE_DOWN_ID, HELP_STR_ID, \ LONG_HELP_STR_ID, BITMAP1_ID, BITMAP2_ID \ = [wx.NewId() for i in range(14)] self._staticbox = wx.StaticBox(self, -1, _("Tool:")) self.owner = owner self.tool_items = wx.ListCtrl(self, LIST_ID, style=wx.LC_REPORT | \ wx.LC_SINGLE_SEL|wx.SUNKEN_BORDER, size=(300, -1)) self.selected_index = -1 # index of the selected element in the # wxListCtrl self.tool_items.InsertColumn(0, _("Label")) self.tool_items.InsertColumn(1, _("Id")) self.tool_items.InsertColumn(2, _("Normal Bitmap")) self.tool_items.InsertColumn(3, _("Second Bitmap")) self.tool_items.InsertColumn(4, _("Short Help")) self.tool_items.InsertColumn(5, _("Long Help")) self.tool_items.InsertColumn(6, _("Type")) # ALB 2004-12-05 self.tool_items.InsertColumn(7, _("Event Handler")) self.tool_items.SetColumnWidth(0, 100) self.tool_items.SetColumnWidth(2, 100) self.tool_items.SetColumnWidth(3, 150) self.tool_items.SetColumnWidth(4, 150) self.tool_items.SetColumnWidth(5, 100) self.tool_items.SetColumnWidth(6, 150) self.tool_items.SetColumnWidth(7, 150) # tool fields self.id = wx.TextCtrl(self, ID_ID) self.label = wx.TextCtrl(self, LABEL_ID) self.help_str = wx.TextCtrl(self, HELP_STR_ID) self.long_help_str = wx.TextCtrl(self, LONG_HELP_STR_ID) # ALB 2004-12-05 self.event_handler = wx.TextCtrl(self, -1) import re self.handler_re = re.compile(r'^\s*\w*\s*$') self.bitmap1 = _MyBrowseButton( self, BITMAP1_ID, labelText=_('Normal Bitmap'), buttonText='...', changeCallback=self.update_tool) self.bitmap2 = _MyBrowseButton( self, BITMAP2_ID, labelText=_('Second Bitmap'), buttonText='...', changeCallback=self.update_tool) self.check_radio = wx.RadioBox( self, CHECK_RADIO_ID, _("Type"), choices=['Normal', 'Checkable', 'Radio'], majorDimension=3) self.add = wx.Button(self, ADD_ID, _("Add")) self.remove = wx.Button(self, REMOVE_ID, _("Remove")) self.add_sep = wx.Button(self, ADD_SEP_ID, _("Add separator")) # tools navigation self.move_up = wx.Button(self, MOVE_UP_ID, _("Up")) self.move_down = wx.Button(self, MOVE_DOWN_ID, _("Down")) self.ok = wx.Button(self, wx.ID_OK, _("OK")) self.apply = wx.Button(self, wx.ID_APPLY, _("Apply")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.do_layout() # event handlers wx.EVT_BUTTON(self, ADD_ID, self.add_tool) wx.EVT_BUTTON(self, REMOVE_ID, self.remove_tool) wx.EVT_BUTTON(self, ADD_SEP_ID, self.add_separator) wx.EVT_BUTTON(self, MOVE_UP_ID, self.move_item_up) wx.EVT_BUTTON(self, MOVE_DOWN_ID, self.move_item_down) wx.EVT_BUTTON(self, wx.ID_APPLY, self.on_apply) wx.EVT_KILL_FOCUS(self.label, self.update_tool) wx.EVT_KILL_FOCUS(self.id, self.update_tool) wx.EVT_KILL_FOCUS(self.help_str, self.update_tool) wx.EVT_KILL_FOCUS(self.long_help_str, self.update_tool) wx.EVT_KILL_FOCUS(self.event_handler, self.update_tool) wx.EVT_RADIOBOX(self, CHECK_RADIO_ID, self.update_tool) wx.EVT_LIST_ITEM_SELECTED(self, LIST_ID, self.show_tool) if items: self.add_tools(items) def do_layout(self): self.label.Enable(False) self.id.Enable(False) self.help_str.Enable(False) self.long_help_str.Enable(False) self.event_handler.Enable(False) self.bitmap1.Enable(False) self.bitmap2.Enable(False) self.check_radio.Enable(False) sizer = wx.BoxSizer(wx.VERTICAL) sizer2 = wx.StaticBoxSizer(self._staticbox, wx.VERTICAL) self.label.SetSize((150, -1)) self.id.SetSize((150, -1)) self.help_str.SetSize((150, -1)) self.long_help_str.SetSize((150, -1)) self.event_handler.SetSize((150, -1)) szr = wx.FlexGridSizer(0, 2) if misc.check_wx_version(2, 5, 2): flag = wx.FIXED_MINSIZE else: flag = 0 label_flag = wx.ALIGN_CENTER_VERTICAL szr.Add(wx.StaticText(self, -1, _("Id ")), flag=label_flag) szr.Add(self.id, flag=flag) szr.Add(wx.StaticText(self, -1, _("Label ")), flag=label_flag) szr.Add(self.label, flag=flag) szr.Add(wx.StaticText(self, -1, _("Short Help ")), flag=label_flag) szr.Add(self.help_str, flag=flag) szr.Add(wx.StaticText(self, -1, _("Long Help ")), flag=label_flag) szr.Add(self.long_help_str, flag=flag) szr.Add(wx.StaticText(self, -1, _("Event Handler ")), flag=label_flag) szr.Add(self.event_handler, flag=flag) sizer2.Add(szr, 1, wx.ALL|wx.EXPAND, 5) label_w = self.bitmap1.browseButton.GetTextExtent('...')[0] sizer2.Add(self.bitmap1, 0, wx.EXPAND) sizer2.Add(self.bitmap2, 0, wx.EXPAND) sizer2.Add(self.check_radio, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 4) szr = wx.GridSizer(0, 2, 3, 3) szr.Add(self.add, 0, wx.EXPAND); szr.Add(self.remove, 0, wx.EXPAND) sizer2.Add(szr, 0, wx.EXPAND) sizer2.Add(self.add_sep, 0, wx.TOP|wx.EXPAND, 3) sizer3 = wx.BoxSizer(wx.VERTICAL) sizer3.Add(self.tool_items, 1, wx.ALL|wx.EXPAND, 5) sizer4 = wx.BoxSizer(wx.HORIZONTAL) sizer4.Add(self.move_up, 0, wx.LEFT|wx.RIGHT, 3) sizer4.Add(self.move_down, 0, wx.LEFT|wx.RIGHT, 5) sizer3.Add(sizer4, 0, wx.ALIGN_CENTER|wx.ALL, 5) szr = wx.BoxSizer(wx.HORIZONTAL) szr.Add(sizer3, 1, wx.ALL|wx.EXPAND, 5) szr.Add(sizer2, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 5) sizer.Add(szr, 1, wx.EXPAND) sizer2 = wx.BoxSizer(wx.HORIZONTAL) sizer2.Add(self.ok, 0, wx.ALL, 5) sizer2.Add(self.apply, 0, wx.ALL, 5) sizer2.Add(self.cancel, 0, wx.ALL, 5) sizer.Add(sizer2, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(1) self.SetSizer(sizer) sizer.Fit(self) #self.SetSize((-1, 350)) self.CenterOnScreen() def add_tool(self, event): """\ Event handler called when the Add button is clicked """ index = self.selected_index = self.selected_index+1 if not self.tool_items.GetItemCount(): for s in (self.label, self.id, self.help_str, self.long_help_str, self.bitmap1, self.bitmap2, self.check_radio, self.event_handler): s.Enable(True) if index < 0: index = self.tool_items.GetItemCount() name, label, id, check_radio = "", "item", "", "0" bitmap1, bitmap2, help_str, long_help_str = [""] * 4 self.tool_items.InsertStringItem(index, label) self.tool_items.SetStringItem(index, 1, id) self.tool_items.SetStringItem(index, 2, bitmap1) self.tool_items.SetStringItem(index, 3, bitmap2) self.tool_items.SetStringItem(index, 4, help_str) self.tool_items.SetStringItem(index, 5, long_help_str) self.tool_items.SetStringItem(index, 6, check_radio) self.tool_items.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) self.label.SetValue(label) self.id.SetValue(id) self.check_radio.SetSelection(int(check_radio)) self.bitmap1.SetValue(bitmap1, False) self.bitmap2.SetValue(bitmap2, False) self.help_str.SetValue(help_str) self.long_help_str.SetValue(long_help_str) self.event_handler.SetValue("") def add_separator(self, event): """\ Event handler called when the Add Separator button is clicked """ index = self.selected_index+1 if not self.tool_items.GetItemCount(): for s in (self.label, self.id, self.help_str, self.long_help_str, self.bitmap1, self.bitmap2, self.check_radio, self.event_handler): s.Enable(True) if index < 0: index = self.tool_items.GetItemCount() self.tool_items.InsertStringItem(index, '---')#label) for i in range(1, 5): self.tool_items.SetStringItem(index, i, '---') self.tool_items.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) def show_tool(self, event): """\ Event handler called when a tool in the list is selected """ self.selected_index = index = event.GetIndex() get_item = self.tool_items.GetItem if not self.tool_items.GetItem(index, 2).m_text == '---': # skip if the selected item is a separator for (s, i) in ((self.label, 0), (self.id, 1), (self.help_str, 4), (self.long_help_str, 5), (self.event_handler, 7)): s.SetValue(get_item(index, i).m_text) self.bitmap1.SetValue(get_item(index, 2).m_text, False) self.bitmap2.SetValue(get_item(index, 3).m_text, False) try: self.check_radio.SetSelection( int(self.tool_items.GetItem(index, 6).m_text)) except: self.check_radio.SetSelection(0) event.Skip() def update_tool(self, event): """\ Event handler called when some of the properties of the current tool changes """ set_item = self.tool_items.SetStringItem index = self.selected_index handler = self.event_handler.GetValue() if not self.handler_re.match(handler): event.GetEventObject().SetFocus() return if index < 0: return event.Skip() set_item(index, 0, self.label.GetValue()) set_item(index, 1, self.id.GetValue()) set_item(index, 2, self.bitmap1.GetValue()) set_item(index, 3, self.bitmap2.GetValue()) set_item(index, 4, self.help_str.GetValue()) set_item(index, 5, self.long_help_str.GetValue()) set_item(index, 6, str(self.check_radio.GetSelection())) set_item(index, 7, self.event_handler.GetValue()) try: event.Skip() except AttributeError: # this happens on wx2.4.0.1 for FileBrowseButton events pass # update the directory of the browse buttons directory = os.path.split(self.bitmap1.GetValue())[0] if not os.path.isdir(directory): directory = os.path.split(self.bitmap2.GetValue())[0] if os.path.isdir(directory): self.bitmap1.startDirectory = directory self.bitmap2.startDirectory = directory def remove_tool(self, event): """\ Event handler called when the Remove button is clicked """ if self.selected_index >= 0: for s in (self.id, self.label, self.help_str, self.long_help_str, self.event_handler): s.SetValue("") for s in (self.bitmap1, self.bitmap2): s.SetValue("", False) self.check_radio.SetSelection(0) self.tool_items.DeleteItem(self.selected_index) if not self.tool_items.GetItemCount(): for s in (self.id, self.label, self.help_str, self.long_help_str, self.bitmap1, self.bitmap2, self.check_radio, self.event_handler): s.Enable(False) def add_tools(self, tools): """\ adds the content of 'tools' to self.tool_items. tools is a sequence of (simple) tool items for the toolbar. At the moment there is no control support, but I hope to add it soon """ set_item = self.tool_items.SetStringItem add_item = self.tool_items.InsertStringItem index = [0] def add(tool): i = index[0] add_item(i, misc.wxstr(tool.label)) set_item(i, 1, misc.wxstr(tool.id)) set_item(i, 2, misc.wxstr(tool.bitmap1)) set_item(i, 3, misc.wxstr(tool.bitmap2)) set_item(i, 4, misc.wxstr(tool.short_help)) set_item(i, 5, misc.wxstr(tool.long_help)) set_item(i, 7, misc.wxstr(tool.handler)) item_type = 0 set_item(i, 6, misc.wxstr(tool.type)) index[0] += 1 for tool in tools: add(tool) if self.tool_items.GetItemCount(): for s in (self.id, self.label, self.help_str, self.long_help_str, self.bitmap1, self.bitmap2, self.check_radio, self.event_handler): s.Enable(True) def get_tools(self): """\ returns the contents of self.tool_items as a list of tools that describes the contents of the ToolBar """ def get(i, j): return self.tool_items.GetItem(i, j).m_text tools = [] def add(index): label = get(index, 0) id = get(index, 1) bitmap1 = get(index, 2) bitmap2 = get(index, 3) short_help = get(index, 4) long_help = get(index, 5) event_handler = get(index, 7) try: item_type = int(get(index, 6)) except ValueError: item_type = 0 tools.append(Tool(label=label, id=id, type=item_type, short_help=short_help, long_help=long_help, bitmap1=bitmap1, bitmap2=bitmap2, handler=event_handler)) for index in range(self.tool_items.GetItemCount()): add(index) return tools def move_item_up(self, event): """\ moves the selected tool before the previous one at the same level in self.tool_items """ self.tool_items.SetFocus() if self.selected_index > 0: index = self.selected_index - 1 vals1 = [ self.tool_items.GetItem(self.selected_index, i).m_text \ for i in range(8) ] vals2 = [ self.tool_items.GetItem(index, i).m_text \ for i in range(8) ] for i in range(8): self.tool_items.SetStringItem(index, i, vals1[i]) self.tool_items.SetStringItem(self.selected_index, i, vals2[i]) state = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED self.tool_items.SetItemState(index, state, state) self.selected_index = index def move_item_down(self, event): """\ moves the selected tool after the next one at the same level in self.tool_items """ self.tool_items.SetFocus() if self.selected_index < self.tool_items.GetItemCount()-1: index = self.selected_index + 1 vals1 = [ self.tool_items.GetItem(self.selected_index, i).m_text \ for i in range(8) ] vals2 = [ self.tool_items.GetItem(index, i).m_text \ for i in range(8) ] for i in range(8): self.tool_items.SetStringItem(index, i, vals1[i]) self.tool_items.SetStringItem(self.selected_index, i, vals2[i]) state = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED self.tool_items.SetItemState(index, state, state) self.selected_index = index def on_apply(self, event): self.owner.set_tools(self.get_tools()) common.app_tree.app.saved = False # end of class ToolsDialog class ToolsProperty(Property): """\ Property to edit the tools of an EditToolBar instance. """ def __init__(self, owner, name, parent): Property.__init__(self, owner, name, parent) self.panel = None self.tools = {} if parent is not None: self.display(parent) def display(self, parent): self.panel = wx.Panel(parent, -1) edit_btn_id = wx.NewId() self.edit_btn = wx.Button(self.panel, edit_btn_id, _("Edit tools...")) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.edit_btn, 1, wx.EXPAND|wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 4) self.panel.SetAutoLayout(1) self.panel.SetSizer(sizer) self.panel.SetSize(sizer.GetMinSize()) wx.EVT_BUTTON(self.panel, edit_btn_id, self.edit_tools) def bind_event(*args): pass def edit_tools(self, event): dialog = ToolsDialog(self.panel, self.owner, items=self.owner.get_tools()) if dialog.ShowModal() == wx.ID_OK: self.owner.set_tools(dialog.get_tools()) common.app_tree.app.saved = False # update the status of the app def write(self, outfile, tabs): fwrite = outfile.write fwrite(' ' * tabs + '\n') for tool in self.owner[self.name][0](): tool.write(outfile, tabs+1) fwrite(' ' * tabs + '\n') # end of class ToolsProperty class EditToolBar(EditBase, PreviewMixin): def __init__(self, name, klass, parent, property_window): custom_class = parent is None EditBase.__init__(self, name, klass, parent, wx.NewId(), property_window, custom_class=custom_class, show=False) self.base = 'wx.ToolBar' def nil(*args): return () self.tools = [] # list of Tool objects self._tb = None # the real toolbar self.style = 0 self.access_functions['style'] = (self.get_style, self.set_style) self.style_pos = [wx.TB_FLAT, wx.TB_DOCKABLE, wx.TB_3DBUTTONS] if misc.check_wx_version(2, 3, 3): self.style_pos += [wx.TB_TEXT, wx.TB_NOICONS, wx.TB_NODIVIDER, wx.TB_NOALIGN] if misc.check_wx_version(2, 5, 0): self.style_pos += [wx.TB_HORZ_LAYOUT, wx.TB_HORZ_TEXT] style_labels = ['#section#' + _('Style'), 'wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_3DBUTTONS'] if misc.check_wx_version(2, 3, 3): style_labels += ['wxTB_TEXT', 'wxTB_NOICONS', 'wxTB_NODIVIDER', 'wxTB_NOALIGN'] if misc.check_wx_version(2, 5, 0): style_labels += ['wxTB_HORZ_LAYOUT', 'wxTB_HORZ_TEXT'] self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self.bitmapsize = '16, 15' self.access_functions['bitmapsize'] = (self.get_bitmapsize, self.set_bitmapsize) self.properties['bitmapsize'] = TextProperty(self, 'bitmapsize', None, can_disable=True, label=_("bitmapsize")) self.margins = '0, 0' self.access_functions['margins'] = (self.get_margins, self.set_margins) self.properties['margins'] = TextProperty(self, 'margins', None, can_disable=True, label=_("margins")) self.access_functions['tools'] = (self.get_tools, self.set_tools) prop = self.properties['tools'] = ToolsProperty(self, 'tools', None) self.packing = 1 self.access_functions['packing'] = (self.get_packing, self.set_packing) self.properties['packing'] = SpinProperty(self, 'packing', None, r=(0, 100), can_disable=True, label=_("packing")) self.separation = 5 self.access_functions['separation'] = (self.get_separation, self.set_separation) self.properties['separation'] = SpinProperty( self, 'separation', None, r=(0, 100), can_disable=True, label=_("separation")) # 2003-05-07 preview support PreviewMixin.__init__(self) def create_widget(self): tb_style = wx.TB_HORIZONTAL|self.style if wx.Platform == '__WXGTK__': tb_style |= wx.TB_DOCKABLE|wx.TB_FLAT if self.parent: self.widget = self._tb = wx.ToolBar( self.parent.widget, -1, style=tb_style) self.parent.widget.SetToolBar(self.widget) else: # "top-level" toolbar self.widget = wx.Frame(None, -1, misc.design_title(self.name)) self.widget.SetClientSize((400, 30)) self._tb = wx.ToolBar(self.widget, -1, style=tb_style) self.widget.SetToolBar(self._tb) self.widget.SetBackgroundColour(self._tb.GetBackgroundColour()) import os icon = wx.EmptyIcon() xpm = os.path.join(common.wxglade_path, 'icons', 'toolbar.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) self.widget.SetIcon(icon) wx.EVT_CLOSE(self.widget, lambda e: self.hide_widget()) wx.EVT_LEFT_DOWN(self._tb, self.on_set_focus) if wx.Platform == '__WXMSW__': # MSW isn't smart enough to avoid overlapping windows, so # at least move it away from the 3 wxGlade frames self.widget.CenterOnScreen() wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) # set the various property values prop = self.properties if prop['bitmapsize'].is_active(): self.set_bitmapsize(self.bitmapsize, refresh=False) if prop['margins'].is_active(): self.set_margins(self.margins, refresh=False) if prop['packing'].is_active(): self.set_packing(self.packing, refresh=False) if prop['separation'].is_active(): self.set_separation(self.separation, refresh=False) self.set_tools(self.tools) # show the menus def create_properties(self): EditBase.create_properties(self) page = self._common_panel sizer = page.GetSizer() self.properties['bitmapsize'].display(page) self.properties['margins'].display(page) self.properties['packing'].display(page) self.properties['separation'].display(page) self.properties['style'].display(page) self.properties['tools'].display(page) if not sizer: sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.name_prop.panel, 0, wx.EXPAND) sizer.Add(self.klass_prop.panel, 0, wx.EXPAND) page.SetAutoLayout(1) page.SetSizer(sizer) sizer.Add(self.properties['bitmapsize'].panel, 0, wx.EXPAND) sizer.Add(self.properties['margins'].panel, 0, wx.EXPAND) sizer.Add(self.properties['packing'].panel, 0, wx.EXPAND) sizer.Add(self.properties['separation'].panel, 0, wx.EXPAND) sizer.Add(self.properties['style'].panel, 0, wx.EXPAND) sizer.Add(self.properties['tools'].panel, 0, wx.ALL|wx.EXPAND, 3) sizer.Layout() sizer.Fit(page) w, h = page.GetClientSize() self.notebook.AddPage(page, _("Common")) if self.parent is not None: self.property_window.Layout() page.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) else: PreviewMixin.create_properties(self) def __getitem__(self, key): return self.access_functions[key] def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if (self.style & self.style_pos[i]) == self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value, refresh=True): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self._tb: self._tb.SetWindowStyleFlag(self.style) if refresh: self._refresh_widget() def get_margins(self): return self.margins def set_margins(self, value, refresh=True): try: margins = [int(t.strip()) for t in value.split(',')] except: self.properties['margins'].set_value(self.margins) else: self.margins = value if self._tb: self._tb.SetMargins(margins) if refresh: self._refresh_widget() def get_packing(self): return self.packing def set_packing(self, value, refresh=True): try: value = int(value) except: self.properties['packing'].set_value(self.packing) else: self.packing = value if self._tb: self._tb.SetToolPacking(self.packing) if refresh: self._refresh_widget() def get_separation(self): return self.separation def set_separation(self, value, refresh=True): try: value = int(value) except: self.properties['separation'].set_value(self.separation) else: self.separation = value if self._tb: self._tb.SetToolSeparation(self.separation) if refresh: self._refresh_widget() def get_bitmapsize(self): return self.bitmapsize def set_bitmapsize(self, value, refresh=True): try: size = [int(t.strip()) for t in value.split(',')] except: self.properties['bitmapsize'].set_value(self.bitmapsize) else: self.bitmapsize = value if self._tb: self._tb.SetToolBitmapSize(size) if refresh: self._refresh_widget() def get_tools(self): return self.tools def set_tools(self, tools): self.tools = tools if not self._tb: return # nothing left to do while self._tb.DeleteToolByPos(0): pass # clear the toolbar # now add all the tools for tool in self.tools: if misc.streq(tool.id, '---'): # the tool is a separator self._tb.AddSeparator() else: if tool.bitmap1: bmp1 = None if not (tool.bitmap1.startswith('var:') or tool.bitmap1.startswith('code:')): bmp1 = wx.Bitmap( misc.get_relative_path(misc.wxstr(tool.bitmap1)), wx.BITMAP_TYPE_ANY) if not bmp1 or not bmp1.Ok(): bmp1 = wx.EmptyBitmap(1, 1) else: bmp1 = wx.NullBitmap if tool.bitmap2: bmp2 = None if not (tool.bitmap2.startswith('var:') or tool.bitmap2.startswith('code:')): bmp2 = wx.Bitmap( misc.get_relative_path(misc.wxstr(tool.bitmap2)), wx.BITMAP_TYPE_ANY) if not bmp2 or not bmp2.Ok(): bmp2 = wx.EmptyBitmap(1, 1) else: bmp2 = wx.NullBitmap # signature of AddTool for 2.3.2.1: # wxToolBarToolBase *AddTool( # int id, const wxBitmap& bitmap, # const wxBitmap& pushedBitmap, bool toggle = FALSE, # wxObject *clientData = NULL, # const wxString& shortHelpString = wxEmptyString, # const wxString& longHelpString = wxEmptyString) if not misc.check_wx_version(2, 3, 3): # use the old signature, some of the entries are ignored self._tb.AddTool(wx.NewId(), bmp1, bmp2, tool.type == 1, shortHelpString=\ misc.wxstr(tool.short_help), longHelpString=misc.wxstr(tool.long_help)) else: kinds = [wx.ITEM_NORMAL, wx.ITEM_CHECK, wx.ITEM_RADIO] try: kind = kinds[int(tool.type)] except (ValueError, IndexError): kind = wx.ITEM_NORMAL self._tb.AddLabelTool(wx.NewId(), misc.wxstr(tool.label), bmp1, bmp2, kind, misc.wxstr(tool.short_help), misc.wxstr(tool.long_help)) # this is required to refresh the toolbar properly self._refresh_widget() def _refresh_widget(self): self._tb.Realize() self._tb.SetSize((-1, self._tb.GetBestSize()[1])) if self.parent: widget = self.parent.widget w, h = widget.GetClientSize() widget.SetClientSize((w, h+1)) widget.SetClientSize((w, h)) else: widget = self.widget w = widget.GetClientSize()[0] h = self._tb.GetSize()[1] / 2 widget.SetClientSize((w, h)) def remove(self, *args, **kwds): if self.parent is not None: self.parent.properties['toolbar'].set_value(0) if kwds.get('do_nothing', False): # and wxPlatform == '__WXGTK__': # this probably leaks memory, but avoids segfaults self.widget = None else: if self.parent.widget: self.parent.widget.SetToolBar(None) else: if self.widget: self.widget.Destroy() self.widget = None EditBase.remove(self) def popup_menu(self, event): if self.parent is not None: return # do nothing in this case if self.widget: if not self._rmenu: REMOVE_ID, HIDE_ID = [wx.NewId() for i in range(2)] self._rmenu = misc.wxGladePopupMenu(self.name) misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self._rmenu, HIDE_ID, _('Hide')) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, HIDE_ID, bind(self.hide_widget)) self.widget.PopupMenu(self._rmenu, event.GetPosition()) def hide_widget(self, *args): if self.widget and self.widget is not self._tb: self.widget.Hide() common.app_tree.expand(self.node, False) common.app_tree.select_item(self.node.parent) common.app_tree.app.show_properties() def set_name(self, name): EditBase.set_name(self, name) if self.widget is not self._tb: self.widget.SetTitle(misc.design_title(misc.wxstr(self.name))) def get_property_handler(self, name): class ToolsHandler: itemattrs = ['label', 'id', 'short_help', 'long_help', 'bitmap1', 'bitmap2', 'type', 'handler'] def __init__(self, owner): self.owner = owner self.tools = [] self.curr_tool = None self.curr_index = -1 def start_elem(self, name, attrs): if name == 'tools': return if name == 'tool': self.curr_tool = Tool() else: try: self.curr_index = self.itemattrs.index(name) except ValueError: self.curr_index = -1 pass # just ignore the attributes we don't know ## from xml_parse import XmlParsingError ## raise XmlParsingError, _("invalid tool attribute") def end_elem(self, name): if name == 'tool': self.tools.append(self.curr_tool) if name == 'tools': self.owner.set_tools(self.tools) return True def char_data(self, data): if self.curr_index >= 0: setattr(self.curr_tool, self.itemattrs[self.curr_index], data) if name == 'tools': return ToolsHandler(self) return None # end of class EditToolBar def builder(parent, sizer, pos, number=[0]): """\ factory function for EditToolBar objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select toolbar class')) if common.app_tree.app.get_language().lower() == 'xrc': self.klass = 'wxToolBar' else: if not number[0]: self.klass = 'MyToolBar' else: self.klass = 'MyToolBar%s' % number[0] number[0] += 1 klass_prop = TextProperty(self, 'class', self) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(klass_prop.panel, 0, wx.EXPAND) sz2 = wx.BoxSizer(wx.HORIZONTAL) sz2.Add(wx.Button(self, wx.ID_OK, _('OK')), 0, wx.ALL, 3) sz2.Add(wx.Button(self, wx.ID_CANCEL, _('Cancel')), 0, wx.ALL, 3) szr.Add(sz2, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) #self.SetSize((150, -1)) def undo(self): if number[0] > 0: number[0] -= 1 def __getitem__(self, value): if value == 'class': def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) # end of inner class dialog = Dialog() if dialog.ShowModal() == wx.ID_CANCEL: # cancel the operation dialog.undo() dialog.Destroy() return name = 'toolbar_%d' % (number[0] or 1) while common.app_tree.has_name(name): number[0] += 1 name = 'toolbar_%d' % number[0] tb = EditToolBar(name, dialog.klass, parent, common.property_panel) tb.node = Tree.Node(tb) common.app_tree.add(tb.node) tb.show_widget(True) tb.show_properties() def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditMenuBar objects from an xml file """ name = attrs.get('name') if parent is not None: if name: parent.toolbar.set_name(name) parent.toolbar.name_prop.set_value(name) return parent.toolbar else: tb = EditToolBar(name, attrs.get('class', 'wxMenuBar'), None, common.property_panel) tb.node = Tree.Node(tb) common.app_tree.add(tb.node) return tb def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ cwx = common.widgets_from_xml cwx['EditToolBar'] = xml_builder common.widgets['EditToolBar'] = builder return common.make_object_button('EditToolBar', 'icons/toolbar.xpm', 1) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/toolbar/tool.py0000644000175000017500000000330310743421035022215 0ustar stanistani# tool.py: Tool objects # $Id: tool.py,v 1.8 2007/03/27 07:01:51 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY from xml.sax.saxutils import escape, quoteattr from common import _encode_to_xml class Tool: def __init__(self, id='', label='', type=0, short_help='', long_help='', bitmap1='', bitmap2='', handler=''): self.id = id self.label = label self.type = type self.short_help = short_help self.long_help = long_help self.bitmap1 = bitmap1 self.bitmap2 = bitmap2 self.handler = handler def write(self, outfile, tabs): fwrite = outfile.write fwrite(" " * tabs + '\n') tab_s = " " * (tabs+1) fwrite(tab_s + '%s\n' % escape(_encode_to_xml(self.id))) fwrite(tab_s + '\n' % \ escape(_encode_to_xml(self.label))) fwrite(tab_s + '%s\n' % escape(str(self.type))) fwrite(tab_s + '%s\n' % \ escape(_encode_to_xml(self.short_help))) fwrite(tab_s + '%s\n' % \ escape(_encode_to_xml(self.long_help))) fwrite(tab_s + '%s\n' % \ escape(_encode_to_xml(self.bitmap1))) fwrite(tab_s + '%s\n' % \ escape(_encode_to_xml(self.bitmap2))) if self.handler: fwrite(tab_s + '%s\n' % \ escape(_encode_to_xml(self.handler.strip()))) fwrite(" " * tabs + '\n') # end of class Tool spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/codegen.py0000644000175000017500000001021110743421035023144 0ustar stanistani# codegen.py: code generator functions for wxRadioBox objects # $Id: codegen.py,v 1.13 2007/03/27 07:01:55 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) label = pygen.quote_str(prop.get('label', '')) choices = prop.get('choices', []) major_dim = prop.get('dimension', '0') if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) choices = ', '.join([pygen.quote_str(c) for c in choices]) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s, choices=[%s], ' 'majorDimension=%s%s)\n' % (obj.name, klass, parent, id, label, choices, major_dim, style)) props_buf = pygen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('self.%s.SetSelection(%s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class RadioBoxXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'choices': xrc_write_choices_property(self, outfile, tabs) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class RadioBoxXrcObject return RadioBoxXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxRadioBox objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] choices = prop.get('choices', []) major_dim = prop.get('dimension', '0') if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' number = len(choices) ch_arr = '{\n %s\n };\n' % \ ',\n '.join([cppgen.quote_str(c) for c in choices]) label = cppgen.quote_str(prop.get('label', '')) style = prop.get("style", "0") init = [] init.append('const wxString %s_choices[] = %s' % (obj.name, ch_arr)) init.append('%s = new %s(%s, %s, %s, wxDefaultPosition, ' 'wxDefaultSize, %s, %s_choices, %s, %s);\n' % \ (obj.name, obj.klass, parent, id, label, number, obj.name, major_dim, style)) props_buf = cppgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('%s->SetSelection(%s);\n' % (obj.name, selection)) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditRadioBox'] = 'wxRadioBox' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxRadioBox', PythonCodeGenerator()) pygen.add_property_handler('choices', ChoicesCodeHandler) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxRadioBox', xrc_code_generator) xrcgen.add_property_handler('choices', ChoicesCodeHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxRadioBox', CppCodeGenerator()) cppgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/perl_codegen.py0000644000175000017500000000354610743421035024203 0ustar stanistani# perl_codegen.py : perl generator functions for wxRadioBox objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:41:59 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) choices = prop.get('choices', []) major_dim = prop.get('dimension', '0') if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style : style = '' if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); choices = ', '.join([plgen.quote_str(c) for c in choices]) init.append('$self->{%s} = %s->new(%s, %s, %s, wxDefaultPosition, \ wxDefaultSize, [%s], %s, %s);\n' % (obj.name, klass, parent, id, label, choices, major_dim, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('$self->{%s}->SetSelection(%s);\n' % (obj.name, selection)) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditRadioBox'] = 'wxRadioBox' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxRadioBox', PerlCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/radio_box.py0000644000175000017500000002631210743421035023517 0ustar stanistani# radio_box.py: wxRadioBox objects # $Id: radio_box.py,v 1.18 2007/03/28 12:40:12 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from misc import wxGladeRadioButton from ChoicesProperty import * class EditRadioBox(ManagedBase): events = ['EVT_RADIOBOX'] def __init__(self, name, parent, id, label, choices, major_dim, style, sizer, pos, property_window, show=True): """\ Class to handle wxRadioBox objects """ ManagedBase.__init__(self, name, 'wxRadioBox', parent, id, sizer, pos, property_window, show=show) self.static_box = None self.selection = 0 self.choices = choices self.buttons = None self.major_dim = major_dim if not style: self.style = wx.RA_SPECIFY_ROWS else: self.style = style self.label = label # properties self.access_functions['label'] = (self.get_label, self.set_label) self.access_functions['choices'] = (self.get_choices, self.set_choices) self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['dimension'] = (self.get_major_dimension, self.set_major_dimension) self.access_functions['selection'] = (self.get_selection, self.set_selection) self.properties['label'] = TextProperty(self, 'label', None, label=_("label")) self.properties['selection'] = SpinProperty(self, 'selection', None, r=(0, len(choices)-1), label=_("selection")) self.properties['choices'] = ChoicesProperty(self, 'choices', None, [('Label', GridProperty.STRING)], len(choices), label=_("choices")) self.style_pos = [wx.RA_SPECIFY_ROWS, wx.RA_SPECIFY_COLS] self.properties['style'] = RadioProperty(self, 'style', None, ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS'], label=_("style")) self.properties['dimension'] = SpinProperty(self, 'dimension', None, label=_("dimension")) def create_widget(self): self.widget = wx.Panel(self.parent.widget, self.id) self.static_box = self.create_static_box() self.buttons = [ self.create_button(c) for c in self.choices ] if self.buttons: self.buttons[0].SetValue(True) self.widget.GetBestSize = self.GetBestSize self.widget.SetForegroundColour = self.SetForegroundColour self.widget.SetBackgroundColour = self.SetBackgroundColour self.widget.SetFont = self.SetFont self.set_selection(self.selection) self.do_layout() def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['label'].display(panel) self.properties['style'].display(panel) self.properties['dimension'].display(panel) self.properties['selection'].display(panel) self.properties['choices'].display(panel) self.properties['style'].set_value(self.get_style()) szr.Add(self.properties['label'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.ALL|wx.EXPAND, 3) szr.Add(self.properties['dimension'].panel, 0, wx.EXPAND) szr.Add(self.properties['selection'].panel, 0, wx.EXPAND) szr.Add(self.properties['choices'].panel, 1, wx.ALL|wx.EXPAND, 3) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') self.properties['choices'].set_col_sizes([-1]) def create_button(self, label): r = wxGladeRadioButton(self.widget, -1, label) wx.EVT_LEFT_DOWN(r, self.on_set_focus) wx.EVT_RIGHT_DOWN(r, self.popup_menu) return r def create_static_box(self): sb = wx.StaticBox(self.widget, -1, self.label) wx.EVT_LEFT_DOWN(sb, self.on_set_focus) wx.EVT_RIGHT_DOWN(sb, self.popup_menu) return sb def do_layout(self): """\ Lays out the radio buttons according to the values of self.style and self.major_dim """ if not self.widget: return buttons_layout = self.buttons if self.major_dim: if self.style & wx.RA_SPECIFY_COLS: cols = self.major_dim; rows = 0 else: cols = 0; rows = self.major_dim sizer = wx.GridSizer(rows, cols) if wx.Platform == '__WXGTK__': # we need to reorder self.buttons 'cos wxRadioBox lays out its # elements by colums, while wxGridSizer by rows import math if not rows: step = int(math.ceil(1.0*len(self.buttons)/cols)) else: step = rows start = 0 tmp = [ [] for i in range(step) ] for i in range(len(self.buttons)): tmp[i%step].append(self.buttons[i]) buttons_layout = [] for t in tmp: buttons_layout.extend(t) else: sizer = wx.BoxSizer(wx.VERTICAL) for button in buttons_layout: w, h = button.GetBestSize() sizer.Add(button, 0, wx.EXPAND) sizer.SetItemMinSize(button, w, h) self.widget.SetAutoLayout(True) sb_sizer = wx.StaticBoxSizer(self.static_box, wx.VERTICAL) self.widget.SetSizer(sb_sizer) sb_sizer.Add(sizer, 1, wx.EXPAND) sb_sizer.SetMinSize(sizer.GetMinSize()) sb_sizer.Fit(self.widget) sp = self.sizer_properties self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_label(self): return self.label def set_label(self, value): value = misc.wxstr(value) if not misc.streq(value, self.label): self.label = value if self.static_box: self.static_box.SetLabel(value) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_style(self): if self.style == wx.RA_SPECIFY_ROWS: return 0 else: return 1 def set_style(self, value): if value == 0 or value == 'wxRA_SPECIFY_ROWS': self.style = wx.RA_SPECIFY_ROWS else: self.style = wx.RA_SPECIFY_COLS self.set_choices(self.get_choices()) #self.do_layout() def get_major_dimension(self): return self.major_dim def set_major_dimension(self, value): self.major_dim = int(value) self.set_choices(self.get_choices()) #self.do_layout() def get_choices(self): return zip(self.choices) def set_choices(self, values): self.choices = [ misc.wxstr(v[0]) for v in values ] self.properties['selection'].set_range(0, len(self.choices)-1) if not self.widget: return ## delta = len(values) - len(self.buttons) ## if delta > 0: ## self.buttons.extend([ self.create_button("") ## for i in range(delta) ]) ## elif delta < 0: ## to_remove = self.buttons[delta:] ## self.buttons = self.buttons[:delta] ## for b in to_remove: b.Hide(); b.Destroy() for b in self.buttons: b.Hide() b.Destroy() self.static_box = self.create_static_box() self.buttons = [ self.create_button("") for i in range(len(values)) ] for i in range(len(values)): self.buttons[i].SetLabel(values[i][0]) self.do_layout() def get_selection(self): return self.selection def set_selection(self, index): self.selection = int(index) if self.widget: for b in self.buttons: b.SetValue(False) try: self.buttons[self.selection].SetValue(True) except IndexError: pass def get_property_handler(self, prop_name): if prop_name == 'choices': return ChoicesHandler(self) return ManagedBase.get_property_handler(self, prop_name) def GetBestSize(self): w, h = self.widget.GetSizer().GetMinSize() w2, h2 = self.static_box.GetBestSize() return max(w, w2), h def SetBackgroundColour(self, colour): wx.Panel.SetBackgroundColour(self.widget, colour) self.static_box.SetBackgroundColour(colour) for b in self.buttons: b.SetBackgroundColour(colour) self.widget.Refresh() def SetForegroundColour(self, colour): wx.Panel.SetForegroundColour(self.widget, colour) self.static_box.SetForegroundColour(colour) for b in self.buttons: b.SetForegroundColour(colour) self.widget.Refresh() def SetFont(self, font): wx.Panel.SetFont(self.widget, font) self.static_box.SetFont(font) for b in self.buttons: b.SetFont(font) self.widget.Refresh() # end of class EditRadioBox def builder(parent, sizer, pos, number=[1]): """\ factory function for EditRadioBox objects. """ label = 'radio_box_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'radio_box_%d' % number[0] radio_box = EditRadioBox(label, parent, wx.NewId(), label, [misc._encode('choice 1')], 0, 0, sizer, pos, common.property_panel) #sizer.set_item(pos, 0, 0, size=radio_box.GetSize()) node = Tree.Node(radio_box) radio_box.node = node radio_box.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditRadioBox objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") radio_box = EditRadioBox(label, parent, wx.NewId(), '', [], 0, 0, sizer, pos, common.property_panel) sizer.set_item(radio_box.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=radio_box.GetBestSize()) node = Tree.Node(radio_box) radio_box.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return radio_box def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditRadioBox'] = builder common.widgets_from_xml['EditRadioBox'] = xml_builder return common.make_object_button('EditRadioBox', 'icons/radio_box.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/lisp_codegen.py0000644000175000017500000000371110743421035024202 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxRadioBox objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:20 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) label = plgen.quote_str(prop.get('label', '')) choices = prop.get('choices', []) major_dim = prop.get('dimension', '0') if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) length = len(choices) choices = ' '.join([plgen.quote_str(c) for c in choices]) init.append('(setf (slot-%s obj) (wxRadioBox_Create %s %s %s -1 -1 -1 -1 %s (vector %s) %s %s))\n' % (obj.name, parent, id, label, length, choices, major_dim, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('(wxRadioBox_SetSelection (slot-%s obj) %s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditRadioBox'] = 'wxRadioBox' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxRadioBox', LispCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/radio_box/__init__.py0000644000175000017500000000065510743421035023312 0ustar stanistani# __init__.py: radio box widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:55 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import radio_box return radio_box.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/codegen.py0000644000175000017500000000711610743421035022472 0ustar stanistani# codegen.py: code generator functions for wxSlider objects # $Id: codegen.py,v 1.15 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) value = prop.get('value', '0') try: min_v, max_v = [ s.strip() for s in prop['range'].split(',') ] except: min_v, max_v = '0', '10' if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style and style != 'wxSL_HORIZONTAL': style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, %s, %s, %s%s)\n' % (obj.name, klass, parent, id, value, min_v, max_v, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class SliderXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'range': try: min, max = val.split(',') except ValueError: pass else: tab_s = ' '*tabs outfile.write(tab_s + '%s\n' % min) outfile.write(tab_s + '%s\n' % max) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class SliderXrcObject return SliderXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxSlider objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] value = prop.get('value', '0') try: min_v, max_v = [ s.strip() for s in prop['range'].split(',') ] except: min_v, max_v = '0', '10' if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style and style != 'wxSL_HORIZONTAL': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s, %s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, value, min_v, max_v, extra)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxScrollEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditSlider'] = 'wxSlider' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxSlider', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxSlider', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxSlider', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/perl_codegen.py0000644000175000017500000000312110743421035023504 0ustar stanistani# perl_codegen.py : perl generator functions for wxSlider objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:42:36 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = prop.get('value', '0') try: min_v, max_v = [ s.strip() for s in prop['range'].split(',') ] except: min_v, max_v = '0', '10' if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not( style and style != 'wxSL_HORIZONTAL'): # default style style = '' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s, %s, %s, \ wxDefaultPosition, wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, value, min_v, max_v, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditSlider'] = 'wxSlider' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxSlider', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/slider.py0000644000175000017500000002142410743421035022346 0ustar stanistani# slider.py: wxSlider objects # $Id: slider.py,v 1.15 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditSlider(ManagedBase): events = [ 'EVT_COMMAND_SCROLL', 'EVT_COMMAND_SCROLL_TOP', 'EVT_COMMAND_SCROLL_BOTTOM', 'EVT_COMMAND_SCROLL_LINEUP', 'EVT_COMMAND_SCROLL_LINEDOWN', 'EVT_COMMAND_SCROLL_PAGEUP', 'EVT_COMMAND_SCROLL_PAGEDOWN', 'EVT_COMMAND_SCROLL_THUMBTRACK', 'EVT_COMMAND_SCROLL_THUMBRELEASE', 'EVT_COMMAND_SCROLL_ENDSCROLL', ] def __init__(self, name, parent, id, style, sizer, pos, property_window, show=True): """\ Class to handle wxSlider objects """ ManagedBase.__init__(self, name, 'wxSlider', parent, id, sizer, pos, property_window, show=show) self.style = style self.value = 0 self.range = (0, 10) prop = self.properties self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['value'] = (self.get_value, self.set_value) self.access_functions['range'] = (self.get_range, self.set_range) style_labels = ('#section#' + _('Style'), 'wxSL_HORIZONTAL', 'wxSL_VERTICAL', 'wxSL_AUTOTICKS', 'wxSL_LABELS', 'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP', 'wxSL_BOTTOM', 'wxSL_SELRANGE', 'wxSL_INVERSE') self.style_pos = (wx.SL_HORIZONTAL, wx.SL_VERTICAL, wx.SL_AUTOTICKS, wx.SL_LABELS, wx.SL_LEFT, wx.SL_RIGHT, wx.SL_TOP, wx.SL_BOTTOM, wx.SL_SELRANGE, wx.SL_INVERSE) tooltips = (_("Displays the slider horizontally (this is the default)."), _("Displays the slider vertically."), _("Displays tick marks."), _("Displays minimum, maximum and value labels."), _("Displays ticks on the left and forces the slider to be vertical."), _("Displays ticks on the right and forces the slider to be vertical."), _("Displays ticks on the top."), _("Displays ticks on the bottom (this is the default)."), _("Allows the user to select a range on the slider. Windows only."), _("Inverses the mininum and maximum endpoints on the slider. Not compatible with wxSL_SELRANGE.")) prop['style'] = CheckListProperty(self, 'style', None, style_labels, tooltips=tooltips) prop['range'] = TextProperty(self, 'range', None, can_disable=True, label=_("range")) prop['value'] = SpinProperty(self, 'value', None, can_disable=True, label=_("value")) def create_widget(self): self.widget = wx.Slider(self.parent.widget, self.id, self.value, self.range[0], self.range[1], style=self.style) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop = self.properties szr = wx.BoxSizer(wx.VERTICAL) prop['range'].display(panel) prop['value'].display(panel) prop['style'].display(panel) szr.Add(prop['range'].panel, 0, wx.EXPAND) szr.Add(prop['value'].panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, _('Widget')) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_range(self): return "%s, %s" % self.range def set_range(self, val): try: min_v, max_v = map(int, val.split(',')) except: self.properties['range'].set_value(self.get_range()) else: self.range = (min_v, max_v) self.properties['value'].set_range(min_v, max_v) if self.widget: self.widget.SetRange(min_v, max_v) def get_value(self): return self.value def set_value(self, value): value = int(value) if value != self.value: self.value = value if self.widget: self.widget.SetValue(value) # end of class EditSlider def builder(parent, sizer, pos, number=[1]): """\ factory function for EditStaticLine objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, -1, _('Select style')) self.orientations = [ wx.SL_HORIZONTAL, wx.SL_VERTICAL ] self.orientation = wx.SL_HORIZONTAL prop = RadioProperty(self, 'orientation', self, ['wxSL_HORIZONTAL', 'wxSL_VERTICAL'], label=_("orientation")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop.panel, 0, wx.ALL|wx.EXPAND, 10) style_labels = ('#section#', 'wxSL_AUTOTICKS', 'wxSL_LABELS', 'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP') self.style_pos = (wx.SL_AUTOTICKS, wx.SL_LABELS, wx.SL_LEFT, wx.SL_RIGHT, wx.SL_TOP) self.style = 0 self.style_prop = CheckListProperty(self, 'style', self, style_labels) szr.Add(self.style_prop.panel, 0, wx.ALL|wx.EXPAND, 10) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.BOTTOM|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, value): if value == 'orientation': def set_orientation(o): self.orientation = self.orientations[o] return (lambda: self.orientation, set_orientation) else: return (self.get_style, self.set_style) def get_style(self): retval = [0] * len(self.style_pos) try: style = self.style for i in range(len(self.style_pos)): if style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.style_prop.prepare_value(value) style = 0 for v in range(len(value)): if value[v]: style |= self.style_pos[v] self.style = style # end of inner class dialog = Dialog() dialog.ShowModal() label = 'slider_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'slider_%d' % number[0] slider = EditSlider(label, parent, wx.NewId(), dialog.orientation | dialog.style, sizer, pos, common.property_panel) node = Tree.Node(slider) slider.node = node slider.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditSlider objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") style = 0 if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") slider = EditSlider(name, parent, wx.NewId(), style, sizer, pos, common.property_panel) sizer.set_item(slider.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(slider) slider.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return slider def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditSlider'] = builder common.widgets_from_xml['EditSlider'] = xml_builder return common.make_object_button('EditSlider', 'icons/slider.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/lisp_codegen.py0000644000175000017500000000316410743421035023520 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxSlider objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:30 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = prop.get('value', '0') try: min_v, max_v = [ s.strip() for s in prop['range'].split(',') ] except: min_v, max_v = '0', '10' if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not( style and style != 'wxSL_HORIZONTAL'): # default style style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxSlider_Create %s %s %s %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, value, min_v, max_v, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditSlider'] = 'wxSlider' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxSlider', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/slider/__init__.py0000644000175000017500000000064410743421035022624 0ustar stanistani# __init__.py: slider widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import slider return slider.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/codegen.py0000644000175000017500000002433610743421035022140 0ustar stanistani# codegen.py: code generator functions for wxGrid objects # $Id: codegen.py,v 1.25 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class ColsCodeHandler: def __init__(self): self.columns = [] self.col_name = '' self.col_size = '' def start_elem(self, name, attrs): if name == 'column': s = attrs.get('size', '') self.col_size = s self.col_name = '' def end_elem(self, name, code_obj): if name == 'columns': code_obj.properties['columns'] = self.columns return True elif name == 'column': self.columns.append([self.col_name, self.col_size]) return False def char_data(self, data): self.col_name = self.col_name + data # end of class ColsCodeHandler def _check_label(label, col): """\ Checks if 'label' is not the default one for the columns 'col': returns True if the label is a custom one, False otherwise """ # build the default value s = [] while True: s.append(chr(ord('A') + col % 26)) col = col/26 - 1 if col < 0: break s.reverse() # then compare it with label return label != "".join(s) class PythonCodeGenerator(object): def __init__(self): self.pygen = common.code_writers['python'] def __get_import_modules(self): if self.pygen.use_new_namespace: return ['import wx.grid\n'] else: return ['from wxPython.grid import *\n'] import_modules = property(__get_import_modules) def cn(self, c): #print 'PythonCodeGenerator.cn with arg:', c if self.pygen.use_new_namespace: if c[:2] == 'wx': c = c[2:] return 'wx.grid.' + c else: return c def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = self.cn(klass) init.append('self.%s = %s(%s, %s, size=(1, 1))\n' % (obj.name, klass, parent, id)) props_buf = self.get_properties_code(obj) return init, props_buf, [] def get_properties_code(self, obj): pygen = common.code_writers['python'] out = [] name = 'self' if not obj.is_toplevel: name += '.%s' % obj.name prop = obj.properties try: create_grid = int(prop['create_grid']) except (KeyError, ValueError): create_grid = False if not create_grid: return [] columns = prop.get('columns', [['A', '-1']]) out.append('%s.CreateGrid(%s, %s)\n' % (name, prop.get('rows_number', '1'), len(columns))) if prop.get('row_label_size'): out.append('%s.SetRowLabelSize(%s)\n' % (name, prop['row_label_size'])) if prop.get('col_label_size'): out.append('%s.SetColLabelSize(%s)\n' % (name, prop['col_label_size'])) enable_editing = prop.get('enable_editing', '1') if enable_editing != '1': out.append('%s.EnableEditing(0)\n' % name) enable_grid_lines = prop.get('enable_grid_lines', '1') if enable_grid_lines != '1': out.append('%s.EnableGridLines(0)\n' % name) enable_col_resize = prop.get('enable_col_resize', '1') if enable_col_resize != '1': out.append('%s.EnableDragColSize(0)\n' % name) enable_row_resize = prop.get('enable_row_resize', '1') if enable_row_resize != '1': out.append('%s.EnableDragRowSize(0)\n' % name) enable_grid_resize = prop.get('enable_grid_resize', '1') if enable_grid_resize != '1': out.append('%s.EnableDragGridSize(0)\n' % name) if prop.get('lines_color', False): out.append(('%s.SetGridLineColour(' + pygen.cn('wxColour') + '(%s))\n') % (name, pygen._string_to_colour(prop['lines_color']))) if prop.get('label_bg_color', False): out.append(('%s.SetLabelBackgroundColour(' + pygen.cn('wxColour') + '(%s))\n') % (name, pygen._string_to_colour(prop['label_bg_color']))) sel_mode = prop.get('selection_mode') if sel_mode and sel_mode != 'wxGrid.wxGridSelectCells': out.append('%s.SetSelectionMode(%s)\n' % \ (name, self.cn('wxGrid') + sel_mode[6:])) i = 0 for label, size in columns: if _check_label(label, i): out.append('%s.SetColLabelValue(%s, %s)\n' % \ (name, i, pygen.quote_str(label))) try: if int(size) > 0: out.append('%s.SetColSize(%s, %s)\n' % \ (name, i, size)) except ValueError: pass i += 1 out.extend(pygen.generate_common_properties(obj)) return out # end of class PythonCodeGenerator class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxGrid objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' init = [ '%s = new %s(%s, %s);\n' % (obj.name, obj.klass, parent, id) ] props_buf = self.get_properties_code(obj) return init, ids, props_buf, [] def get_properties_code(self, obj): cppgen = common.code_writers['C++'] out = [] name = 'this' if not obj.is_toplevel: name = obj.name prop = obj.properties try: create_grid = int(prop['create_grid']) except (KeyError, ValueError): create_grid = False if not create_grid: return [] columns = prop.get('columns', [['A', '-1']]) out.append('%s->CreateGrid(%s, %s);\n' % (name, prop.get('rows_number', '1'), len(columns))) if prop.get('row_label_size'): out.append('%s->SetRowLabelSize(%s);\n' % \ (name, prop['row_label_size'])) if prop.get('col_label_size'): out.append('%s->SetColLabelSize(%s);\n' % \ (name, prop['col_label_size'])) enable_editing = prop.get('enable_editing', '1') if enable_editing != '1': out.append('%s->EnableEditing(false);\n' % name) enable_grid_lines = prop.get('enable_grid_lines', '1') if enable_grid_lines != '1': out.append('%s->EnableGridLines(false);\n' % name) enable_col_resize = prop.get('enable_col_resize', '1') if enable_col_resize != '1': out.append('%s->EnableDragColSize(false);\n' % name) enable_row_resize = prop.get('enable_row_resize', '1') if enable_row_resize != '1': out.append('%s->EnableDragRowSize(false);\n' % name) enable_grid_resize = prop.get('enable_grid_resize', '1') if enable_grid_resize != '1': out.append('%s->EnableDragGridSize(false);\n' % name) if prop.get('lines_color', False): out.append('%s->SetGridLineColour(wxColour(%s));\n' % (name, cppgen._string_to_colour(prop['lines_color']))) if prop.get('label_bg_color', False): out.append('%s->SetLabelBackgroundColour(wxColour(%s));\n' % (name, cppgen._string_to_colour(prop['label_bg_color']))) sel_mode = prop.get('selection_mode', '').replace('.', '::') if sel_mode and sel_mode != 'wxGrid::wxGridSelectCells': out.append('%s->SetSelectionMode(%s);\n' % (name, sel_mode)) i = 0 for label, size in columns: if _check_label(label, i): out.append('%s->SetColLabelValue(%s, %s);\n' % \ (name, i, cppgen.quote_str(label))) try: if int(size) > 0: out.append('%s->SetColSize(%s, %s);\n' % \ (name, i, size)) except ValueError: pass i += 1 out.extend(cppgen.generate_common_properties(obj)) return out def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxGridEvent') # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class GridXrcObject(xrcgen.DefaultXrcObject): unsupported = set(['column', 'create_grid', 'rows_number', 'row_label_size', 'col_label_size', 'enable_editing', 'enable_grid_lines', 'enable_col_resize', 'enable_row_resize', 'enable_grid_resize', 'lines_color', 'label_bg_color', 'selection_mode']) def write_property(self, name, val, outfile, tabs): if name not in self.unsupported: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) return GridXrcObject(obj) def initialize(): common.class_names['EditGrid'] = 'wxGrid' pygen = common.code_writers.get('python') if pygen: pygen.add_property_handler('columns', ColsCodeHandler, 'wxGrid') pygen.add_widget_handler('wxGrid', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxGrid', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_property_handler('columns', ColsCodeHandler, 'wxGrid') cppgen.add_widget_handler('wxGrid', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/perl_codegen.py0000644000175000017500000001003010743421035023144 0ustar stanistani# perl_codegen.py : perl generator functions for wxGrid objects # $Id: perl_codegen.py,v 1.7 2005/08/15 07:38:56 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import ColsCodeHandler, _check_label class PerlCodeGenerator: import_modules = ['use Wx::Grid;\n'] def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s);\n' % (obj.name, klass, parent, id)) props_buf = self.get_properties_code(obj) return init, props_buf, [] def get_properties_code(self, obj): plgen = common.code_writers['perl'] out = [] name = '$self' if not obj.is_toplevel: name += '->{%s}' % obj.name prop = obj.properties try: create_grid = int(prop['create_grid']) except (KeyError, ValueError): create_grid = False if not create_grid: return [] columns = prop.get('columns', [['A', '-1']]) out.append('%s->CreateGrid(%s, %s);\n' % (name, prop.get('rows_number', '1'), len(columns))) if prop.get('row_label_size'): out.append('%s->SetRowLabelSize(%s);\n' % (name, prop['row_label_size'])) if prop.get('col_label_size'): out.append('%s->SetColLabelSize(%s);\n' % (name, prop['col_label_size'])) enable_editing = prop.get('enable_editing', '1') if enable_editing != '1': out.append('%s->EnableEditing(0);\n' % name) enable_grid_lines = prop.get('enable_grid_lines', '1') if enable_grid_lines != '1': out.append('%s->EnableGridLines(0);\n' % name) enable_col_resize = prop.get('enable_col_resize', '1') if enable_col_resize != '1': out.append('%s->EnableDragColSize(0);\n' % name) enable_row_resize = prop.get('enable_row_resize', '1') if enable_row_resize != '1': out.append('%s->EnableDragRowSize(0);\n' % name) enable_grid_resize = prop.get('enable_grid_resize', '1') if enable_grid_resize != '1': out.append('%s->EnableDragGridSize(0);\n' % name) if prop.get('lines_color', False): out.append('%s->SetGridLineColour(Wx::Colour->new(%s));\n' % (name, plgen._string_to_colour(prop['lines_color']))) if prop.get('label_bg_color', False): out.append('%s->SetLabelBackgroundColour(Wx::Colour->new(%s));\n' % (name, plgen._string_to_colour(prop['label_bg_color']))) sel_mode = prop.get('selection_mode') if sel_mode and sel_mode != 'wxGridSelectCells': out.append('%s->SetSelectionMode(%s);\n' % (name, sel_mode.replace('wxGrid.',''))) i = 0 for label, size in columns: if _check_label(label, i): out.append('%s->SetColLabelValue(%s, %s);\n' % \ (name, i, plgen.quote_str(label))) try: if int(size) > 0: out.append('%s->SetColSize(%s, %s);\n' % \ (name, i, size)) except ValueError: pass i += 1 out.extend(plgen.generate_common_properties(obj)) return out # end of class PerlCodeGenerator def initialize(): common.class_names['EditGrid'] = 'wxGrid' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxGrid', PerlCodeGenerator()) plgen.add_property_handler('columns', ColsCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/lisp_codegen.py0000644000175000017500000001022210743421035023154 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxGrid objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:42 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import ColsCodeHandler, _check_label class LispCodeGenerator: # import_modules = ['use Wx::Grid;\n'] def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxGrid_Create %s %s -1 -1 -1 -1 wxWANTS_CHARS))\n' % (obj.name, parent, id)) props_buf = self.get_properties_code(obj) return init, props_buf, [] def get_properties_code(self, obj): plgen = common.code_writers['lisp'] out = [] name = obj.name prop = obj.properties try: create_grid = int(prop['create_grid']) except (KeyError, ValueError): create_grid = False if not create_grid: return [] columns = prop.get('columns', [['A', '-1']]) out.append('(wxGrid_CreateGrid (slot-%s obj) %s %s 0)\n' % (name, prop.get('rows_number', '1'), len(columns))) if prop.get('row_label_size'): out.append('(wxGrid_SetRowLabelSize (slot-%s obj) %s)\n' % (name, prop['row_label_size'])) if prop.get('col_label_size'): out.append('(wxGrid_SetColLabelSize (slot-%s obj) %s)\n' % (name, prop['col_label_size'])) enable_editing = prop.get('enable_editing', '1') if enable_editing != '1': out.append('(wxGrid_EnableEditing (slot-%s obj) 0)\n' % name) enable_grid_lines = prop.get('enable_grid_lines', '1') if enable_grid_lines != '1': out.append('(wxGrid_EnableGridLines (slot-%s obj) 0)\n' % name) enable_col_resize = prop.get('enable_col_resize', '1') if enable_col_resize != '1': out.append('(wxGrid_EnableDragColSize (slot-%s obj) 0)\n' % name) enable_row_resize = prop.get('enable_row_resize', '1') if enable_row_resize != '1': out.append('(wxGrid_EnableDragRowSize (slot-%s obj) 0)\n' % name) enable_grid_resize = prop.get('enable_grid_resize', '1') if enable_grid_resize != '1': out.append('(wxGrid_EnableDragGridSize (slot-%s obj) 0)\n' % name) if prop.get('lines_color', False): out.append('(wxGrid_SetGridLineColour (slot-%s obj) (wxColour:wxColour_CreateFromStock %s))\n' % (name, plgen._string_to_colour(prop['lines_color']))) if prop.get('label_bg_color', False): out.append('(wxGrid_SetLabelBackgroundColour (slot-%s obj) (wxColour:wxColour_CreateFromStock %s))\n' %(name, plgen._string_to_colour(prop['label_bg_color']))) sel_mode = prop.get('selection_mode') if sel_mode and sel_mode != 'wxGridSelectCells': out.append('(wxGrid_SetSelectionMode (slot-%s obj) %s)\n' % (name, sel_mode.replace('wxGrid.',''))) i = 0 for label, size in columns: if _check_label(label, i): out.append('(wxGrid_SetColLabelValue (slot-%s obj) %s %s)\n' % \ (name, i, plgen.quote_str(label))) try: if int(size) > 0: out.append('(wxGrid_SetColSize (slot-%s obj) %s %s)\n' % \ (name, i, size)) except ValueError: pass i += 1 out.extend(plgen.generate_common_properties(obj)) return out # end of class LispCodeGenerator def initialize(): common.class_names['EditGrid'] = 'wxGrid' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxGrid', LispCodeGenerator()) plgen.add_property_handler('columns', ColsCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/__init__.py0000644000175000017500000000063710743421035022271 0ustar stanistani# __init__.py: grid widget module initialization # $Id: __init__.py,v 1.7 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import grid return grid.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/grid/grid.py0000644000175000017500000004621610743421035021462 0ustar stanistani# Grid.py: wxGrid objects # $Id: grid.py,v 1.33 2007/03/27 07:01:58 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from wx.grid import * import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * class GridColsProperty(GridProperty): def write(self, outfile, tabs): from xml.sax.saxutils import escape, quoteattr write = outfile.write write(' ' * tabs + '\n') tab_s = ' ' * (tabs+1) import widget_properties value = self.get_value() # this is a list for i in range(len(value)): val = value[i] # this is another list _label = escape(widget_properties._encode(val[0])) _size = escape(widget_properties._encode(val[1])) write('%s%s\n' % (tab_s, quoteattr(_size), _label )) write(' ' * tabs + '\n') def _get_label(self, col): s = [] while True: s.append(chr(ord('A') + col%26)) col = col/26 - 1 if col < 0: break s.reverse() return "".join(s) def add_row(self, event): GridProperty.add_row(self, event) label = self._get_label(self.rows-1) self.grid.SetCellValue(self.rows-1, 0, label) self.grid.SetCellValue(self.rows-1, 1, '-1') def insert_row(self, event): GridProperty.insert_row(self, event) label = self._get_label(self.cur_row) self.grid.SetCellValue(self.cur_row, 0, label) self.grid.SetCellValue(self.cur_row, 1, '-1') # end of class GridColumnsProperty class ColsHandler: def __init__(self, parent): self.parent = parent self.columns = [] self.curr_col = [] self.curr_size = '-1' def start_elem(self, name, attrs): if name == 'column': self.curr_size = attrs.get('size', '-1') def end_elem(self, name): if name == 'columns': self.parent.set_columns(self.columns) self.parent.properties['columns'].set_value(self.columns) return True elif name == 'column': self.columns.append(["".join(self.curr_col), self.curr_size]) self.curr_col = [] return False def char_data(self, data): self.curr_col.append(data) # end of class ColsHandler class EditGrid(ManagedBase): events = [ 'EVT_GRID_CMD_CELL_LEFT_CLICK', 'EVT_GRID_CMD_CELL_RIGHT_CLICK', 'EVT_GRID_CMD_CELL_LEFT_DCLICK', 'EVT_GRID_CMD_CELL_RIGHT_DCLICK', 'EVT_GRID_CMD_LABEL_LEFT_CLICK', 'EVT_GRID_CMD_LABEL_RIGHT_CLICK', 'EVT_GRID_CMD_LABEL_LEFT_DCLICK', 'EVT_GRID_CMD_LABEL_RIGHT_DCLICK', 'EVT_GRID_CMD_CELL_CHANGE', 'EVT_GRID_CMD_SELECT_CELL', 'EVT_GRID_CMD_EDITOR_HIDDEN', 'EVT_GRID_CMD_EDITOR_SHOWN', 'EVT_GRID_CMD_COL_SIZE', 'EVT_GRID_CMD_ROW_SIZE', 'EVT_GRID_CMD_RANGE_SELECT', 'EVT_GRID_CMD_EDITOR_CREATED', ] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): """\ Class to handle wxGrid objects """ # values of properties for the grid: self.row_label_size = 30 self.col_label_size = 30 self.enable_editing = True self.enable_grid_lines = True self.rows_number = 10 self.enable_col_resize = True self.enable_row_resize = True self.enable_grid_resize = True self.lines_color = '#000000' self.label_bg_color = '#C0C0C0' self.selection_mode = 0 # == wxGrid.wxGridSelectCells self.create_grid = True self.columns = [ ['A','-1'] , ['B','-1'] , ['C','-1'] ] ManagedBase.__init__(self, name, 'wxGrid', parent, id, sizer, pos, property_window, show=show) props = self.properties af = self.access_functions af['create_grid'] = (self.get_create_grid, self.set_create_grid) props['create_grid'] = CheckBoxProperty(self, 'create_grid', None, write_always=True, label=_("create_grid")) af['row_label_size'] = (self.get_row_label_size, self.set_row_label_size) props['row_label_size'] = SpinProperty(self, 'row_label_size', None, can_disable=True, label=_("row_label_size")) af['col_label_size'] = (self.get_col_label_size, self.set_col_label_size) props['col_label_size'] = SpinProperty(self, 'col_label_size', None, can_disable=True, label=_("col_label_size")) af['enable_editing'] = (self.get_enable_editing, self.set_enable_editing) props['enable_editing'] = CheckBoxProperty(self, 'enable_editing', None, write_always=True, label=_("enable_editing")) af['enable_grid_lines'] = (self.get_enable_grid_lines, self.set_enable_grid_lines) props['enable_grid_lines']= CheckBoxProperty(self, 'enable_grid_lines', None, write_always=True, label=_("enable_grid_lines")) af['rows_number'] = (self.get_rows_number, self.set_rows_number) props['rows_number'] = SpinProperty(self, 'rows_number', None, label=_("rows_number")) af['enable_col_resize'] = (self.get_enable_col_resize, self.set_enable_col_resize) props['enable_col_resize']= CheckBoxProperty(self, 'enable_col_resize', None, write_always=True, label=_("enable_col_resize")) af['enable_row_resize'] = (self.get_enable_row_resize, self.set_enable_row_resize) props['enable_row_resize'] = CheckBoxProperty(self, 'enable_row_resize', None, write_always=True, label=_("enable_row_resize")) af['enable_grid_resize'] = (self.get_enable_grid_resize, self.set_enable_grid_resize) props['enable_grid_resize'] = CheckBoxProperty(self, 'enable_grid_resize', None, write_always=True, label=_("enable_grid_resize")) af['lines_color'] = (self.get_lines_color, self.set_lines_color) props['lines_color']= ColorDialogProperty(self, 'lines_color', None, label=_("lines_color")) af['label_bg_color'] = (self.get_label_bg_color, self.set_label_bg_color) props['label_bg_color']= ColorDialogProperty(self, 'label_bg_color', None, label=_("label_bg_color")) af['selection_mode'] = (self.get_selection_mode, self.set_selection_mode) props['selection_mode'] = RadioProperty(self, 'selection_mode', None, ['wxGrid.wxGridSelectCells', 'wxGrid.wxGridSelectRows', 'wxGrid.wxGridSelectColumns'], label=_("selection_mode")) af['columns'] = (self.get_columns, self.set_columns) props['columns'] = GridColsProperty(self, 'columns', None, [ ('Label', GridProperty.STRING), ('Size', GridProperty.INT) ], label=_("columns")) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) self.properties['create_grid'].display(panel) self.properties['columns'].display(panel) self.properties['rows_number'].display(panel) self.properties['row_label_size'].display(panel) self.properties['col_label_size'].display(panel) self.properties['enable_editing'].display(panel) self.properties['enable_grid_lines'].display(panel) self.properties['enable_col_resize'].display(panel) self.properties['enable_row_resize'].display(panel) self.properties['enable_grid_resize'].display(panel) self.properties['lines_color'].display(panel) self.properties['label_bg_color'].display(panel) self.properties['selection_mode'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.properties['create_grid'].panel, 0, wx.EXPAND) szr.Add(wx.StaticLine(panel, -1), 0, wx.ALL|wx.EXPAND, 5) szr.Add(wx.StaticText(panel, -1, _("The following properties are " "meaningful\nonly if 'Create grid' is selected")), 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) szr.Add(wx.StaticLine(panel, -1), 0, wx.ALL|wx.EXPAND, 5) szr.Add(self.properties['columns'].panel, 0, wx.ALL|wx.EXPAND, 2) szr.SetItemMinSize(self.properties['columns'].panel, 1, 150) szr.Add(self.properties['rows_number'].panel, 0, wx.EXPAND) szr.Add(self.properties['row_label_size'].panel, 0, wx.EXPAND) szr.Add(self.properties['col_label_size'].panel, 0, wx.EXPAND) szr.Add(self.properties['lines_color'].panel, 0, wx.EXPAND) szr.Add(self.properties['label_bg_color'].panel, 0, wx.EXPAND) szr.Add(self.properties['enable_editing'].panel, 0, wx.EXPAND) szr.Add(self.properties['enable_grid_lines'].panel, 0, wx.EXPAND) szr.Add(self.properties['enable_col_resize'].panel, 0, wx.EXPAND) szr.Add(self.properties['enable_row_resize'].panel, 0, wx.EXPAND) szr.Add(self.properties['enable_grid_resize'].panel, 0, wx.EXPAND) szr.Add(self.properties['selection_mode'].panel, 0, wx.ALL|wx.EXPAND, 5) panel.SetAutoLayout(1) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, _('Widget')) import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) self.properties['columns'].set_col_sizes([-1, 0]) def create_widget(self): self.widget = Grid(self.parent.widget, self.id,(200,200)) self.widget.CreateGrid(self.rows_number, len(self.columns)) if not self.properties['label_bg_color'].is_active(): self.label_bg_color = misc.color_to_string( self.widget.GetLabelBackgroundColour()) self.properties['label_bg_color'].set_value(self.label_bg_color) if not self.properties['lines_color'].is_active(): self.lines_color = misc.color_to_string( self.widget.GetGridLineColour()) self.properties['lines_color'].set_value(self.lines_color) self.widget.SetRowLabelSize(self.row_label_size) self.widget.SetColLabelSize(self.col_label_size) self.widget.EnableEditing(self.enable_editing) self.widget.EnableGridLines(self.enable_grid_lines) self.widget.EnableDragColSize(self.enable_col_resize) self.widget.EnableDragRowSize(self.enable_row_resize) self.widget.EnableDragGridSize(self.enable_grid_resize) self.widget.SetGridLineColour(misc.string_to_color(self.lines_color)) self.widget.SetLabelBackgroundColour(misc.string_to_color( self.label_bg_color)) i = 0 for l, s in self.columns: try: s1 = int(s) except: s1 = 0 self.widget.SetColLabelValue(i, l) if s1 > 0: self.widget.SetColSize(i, s1) i += 1 self.set_selection_mode(self.selection_mode) # following two events are to permit select grid from designer frame EVT_GRID_CELL_LEFT_CLICK(self.widget, self.on_set_focus) EVT_GRID_LABEL_LEFT_CLICK(self.widget, self.on_set_focus) # these are to show the popup menu on right click EVT_GRID_CELL_RIGHT_CLICK(self.widget, self.popup_menu) EVT_GRID_LABEL_RIGHT_CLICK(self.widget, self.popup_menu) def get_create_grid(self): return self.create_grid def set_create_grid(self, value): self.create_grid = bool(int(value)) def get_row_label_size(self): return self.row_label_size def set_row_label_size(self, value): self.row_label_size = int(value) if value and self.widget: self.widget.SetRowLabelSize(self.row_label_size) def get_col_label_size(self): return self.col_label_size def set_col_label_size(self, value): self.col_label_size = int(value) if value and self.widget: self.widget.SetColLabelSize(self.col_label_size) def get_enable_editing(self): return self.enable_editing def set_enable_editing(self, value): self.enable_editing = bool(int(value)) # Do nothing. ## if value and self.widget: ## self.widget.EnableEditing(self.enable_editing) # NO! def get_enable_grid_lines(self): return self.enable_grid_lines def set_enable_grid_lines(self, value): self.enable_grid_lines = bool(int(value)) if self.widget: self.widget.EnableGridLines(self.enable_grid_lines) #self.widget.Update() def get_rows_number(self): return self.rows_number def set_rows_number(self, value): self.rows_number = int(value) # the value the user entered if value > 0 and self.widget: # the value that the grid has actual_rows_number = self.widget.GetNumberRows() if self.rows_number > actual_rows_number: # we have to add rows self.widget.AppendRows(self.rows_number - actual_rows_number) if actual_rows_number > self.rows_number: # we have to delete rows self.widget.DeleteRows(self.rows_number, actual_rows_number - self.rows_number) #self.widget.Update() def get_enable_col_resize(self): return self.enable_col_resize def set_enable_col_resize(self, value): self.enable_col_resize = bool(int(value)) if self.widget: self.widget.EnableDragColSize(self.enable_col_resize) def get_enable_row_resize(self): return self.enable_row_resize def set_enable_row_resize(self, value): self.enable_row_resize = bool(int(value)) if self.widget: self.widget.EnableDragRowSize(self.enable_row_resize) def get_enable_grid_resize(self): return self.enable_grid_resize def set_enable_grid_resize(self, value): self.enable_grid_resize = bool(int(value)) if self.widget: self.widget.EnableDragGridSize(self.enable_grid_resize) def get_lines_color(self): return self.lines_color def set_lines_color(self, value): self.lines_color = str(value) if self.widget: self.widget.SetGridLineColour(misc.string_to_color( self.lines_color)) def get_label_bg_color(self): return self.label_bg_color def set_label_bg_color(self, value): self.label_bg_color = str(value) if self.widget: self.widget.SetLabelBackgroundColour(misc.string_to_color( self.label_bg_color)) def get_selection_mode(self): return self.selection_mode ## if self.selection_mode == wxGrid.wxGridSelectCells: return 0 ## if self.selection_mode == wxGrid.wxGridSelectRows: return 1 ## if self.selection_mode == wxGrid.wxGridSelectColumns: return 2 def set_selection_mode(self, value): _sel_modes = { 'wxGrid.wxGridSelectCells': 0, 'wxGrid.wxGridSelectRows': 1, 'wxGrid.wxGridSelectColumns': 2, } if value in _sel_modes: self.selection_mode = _sel_modes[value] else: try: value = int(value) except: pass else: self.selection_mode = value ## if value == 0: ## self.selection_mode = wxGrid.wxGridSelectCells ## elif value == 1: ## self.selection_mode = wxGrid.wxGridSelectRows ## else: ## self.selection_mode = wxGrid.wxGridSelectColumns # no operation on the grid. def get_columns(self): return self.columns def set_columns(self, cols): # first of all, adjust col number _oldcolnum = len(self.columns) _colnum = len(cols) self.columns = cols if not self.widget: return if _colnum > _oldcolnum: self.widget.AppendCols(_colnum - _oldcolnum) if _colnum < _oldcolnum: self.widget.DeleteCols(0, _oldcolnum - _colnum) i = 0 for l, s in cols: try: s1 = int(s) except: s1 = 0 self.widget.SetColLabelValue(i, misc.wxstr(l)) if s1 > 0: self.widget.SetColSize(i, s1) i += 1 self.widget.ForceRefresh() def get_property_handler(self, name): if name == 'columns': return ColsHandler(self) return ManagedBase.get_property_handler(self, name) # end of class EditGrid def builder(parent, sizer, pos, number=[1]): """\ factory function for EditGrid objects. """ label = 'grid_%d' % number[0] while common.app_tree.has_name(label): number[0] += 1 label = 'grid_%d' % number[0] grid = EditGrid(label, parent, wx.NewId(), sizer, pos, common.property_panel) # A grid should be wx.EXPANDed and 'option' should be 1, # or you can't see it. grid.set_option(1) grid.set_flag("wxEXPAND") node = Tree.Node(grid) grid.node = node grid.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditGrid objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") grid = EditGrid(label, parent, wx.NewId(), sizer, pos, common.property_panel, show=False) sizer.set_item(grid.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) #, size=(100,100)) #HELP# node = Tree.Node(grid) grid.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return grid def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditGrid'] = builder common.widgets_from_xml['EditGrid'] = xml_builder return common.make_object_button('EditGrid', 'icons/grid.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/codegen.py0000644000175000017500000001151710743421035024033 0ustar stanistani# codegen.py: code generator functions for wxStaticBitmap objects # $Id: codegen.py,v 1.26 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn prop = obj.properties attribute = pygen.test_attribute(obj) id_name, id = pygen.generate_code_id(obj) bmp_file = prop.get('bitmap', '') bmp_preview_path = os.path.join(common.wxglade_path, "icons", "icon.xpm") if not bmp_file: bmp = cn('wxNullBitmap') elif bmp_file.startswith('var:'): if obj.preview: bmp = "%s('%s',%s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM') ) else: bmp = cn('wxBitmap') + '(%s, %s)' % (bmp_file[4:].strip(), cn('wxBITMAP_TYPE_ANY')) elif bmp_file.startswith('code:'): if obj.preview: bmp = "%s('%s',%s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM') ) else: bmp = '(%s)' % bmp_file[5:].strip() else: if obj.preview: import misc bmp_file = misc.get_relative_path(bmp_file, True) bmp = (cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + ')') % pygen.quote_str(bmp_file, False, False) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' init = [] if id_name: init.append(id_name) if attribute: prefix = 'self.' else: prefix = '' style = prop.get('style') if style: style = ', style=%s' % pygen.cn_f(style) else: style = '' klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('%s%s = %s(%s, %s, %s%s)\n' % (prefix, obj.name, klass, parent, id, bmp, style)) props_buf = pygen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): cppgen = common.code_writers['C++'] prop = obj.properties attribute = cppgen.test_attribute(obj) id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] bmp_file = prop.get('bitmap', '') if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): bmp = 'wxBitmap(%s,wxBITMAP_TYPE_ANY)' % bmp_file[4:].strip() elif bmp_file.startswith('code:'): bmp = '(%s)' % bmp_file[5:].strip() else: bmp = 'wxBitmap(%s, wxBITMAP_TYPE_ANY)' % \ cppgen.quote_str(bmp_file, False, False) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' if attribute: prefix = '' else: prefix = '%s* ' % obj.klass style = prop.get('style') if style: style = ', wxDefaultPosition, wxDefaultSize, ' + style else: style = '' init = [ '%s%s = new %s(%s, %s, %s%s);\n' % (prefix, obj.name, obj.klass, parent, id, bmp, style) ] props_buf = cppgen.generate_common_properties(obj) if not attribute: return [], ids, [], init + props_buf return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class XrcCodeGenerator(xrcgen.DefaultXrcObject): def write(self, *args, **kwds): try: del self.properties['attribute'] except KeyError: pass xrcgen.DefaultXrcObject.write(self, *args, **kwds) return XrcCodeGenerator(obj) def initialize(): common.class_names['EditStaticBitmap'] = 'wxStaticBitmap' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxStaticBitmap', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxStaticBitmap', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxStaticBitmap', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/perl_codegen.py0000644000175000017500000000506610743421035025057 0ustar stanistani# codegen.py: code generator functions for wxStaticBitmap objects # $Id: perl_codegen.py,v 1.11 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os #this should be in common _bmp_str_types = { '.bmp' : 'wxBITMAP_TYPE_BMP', '.gif' : 'wxBITMAP_TYPE_GIF', '.xpm' : 'wxBITMAP_TYPE_XPM', '.jpg' : 'wxBITMAP_TYPE_JPEG', '.jpeg': 'wxBITMAP_TYPE_JPEG', '.png' : 'wxBITMAP_TYPE_PNG', '.pcx' : 'wxBITMAP_TYPE_PCX' } class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' bmp_file = prop.get('bitmap', '') if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): # this is a variable holding bitmap path var = bmp_file[4:].strip() if var[0] != "$": var = "$" + var bmp = 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % var elif bmp_file.startswith('code:'): bmp = '(%s)' % bmp_file[5:].strip() else: bmp = 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % \ plgen.quote_path(bmp_file) if id_name: init.append(id_name) if attribute: prefix = '$self->{%s}' % obj.name else: prefix = '$self' style = prop.get('style') if not style: style = '' klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('%s = %s->new(%s, %s, %s, wxDefaultPosition, wxDefaultSize,' ' %s);\n' % (prefix, klass, parent, id, bmp, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditStaticBitmap'] = 'wxStaticBitmap' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxStaticBitmap', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/lisp_codegen.py0000644000175000017500000000514210743421035025057 0ustar stanistani# codegen.py: code generator functions for wxStaticBitmap objects # $Id: lisp_codegen.py,v 1.2 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os #this should be in common _bmp_str_types = { '.bmp' : 'wxBITMAP_TYPE_BMP', '.gif' : 'wxBITMAP_TYPE_GIF', '.xpm' : 'wxBITMAP_TYPE_XPM', '.jpg' : 'wxBITMAP_TYPE_JPEG', '.jpeg': 'wxBITMAP_TYPE_JPEG', '.png' : 'wxBITMAP_TYPE_PNG', '.pcx' : 'wxBITMAP_TYPE_PCX' } class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties attribute = plgen.test_attribute(obj) id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' bmp_file = prop.get('bitmap', '') if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): # this is a variable holding bitmap path var = bmp_file[4:].strip() if var[0] != "$": var = "$" + var bmp = '(wxBitmap_CreateLoad %s wxBITMAP_TYPE_ANY)' % var elif bmp_file.startswith('code:'): bmp = '(%s)' % bmp_file[5:].strip() else: bmp = '(wxBitmap_CreateLoad %s wxBITMAP_TYPE_ANY)' % \ plgen.quote_path(bmp_file) if id_name: init.append(id_name) if attribute: prefix = '(slot-%s obj)' % obj.name else: prefix = '$self' style = prop.get('style') if not style: style = '0' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init.append('(setf %s (wxStaticBitmap_Create %s %s %s -1 -1 -1 -1 %s))\n' % (prefix, parent, id, bmp, style)) props_buf = plgen.generate_common_properties(obj) if not attribute: # the object doesn't have to be stored as an attribute of the # custom class, but it is just considered part of the layout return [], [], init + props_buf return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditStaticBitmap'] = 'wxStaticBitmap' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxStaticBitmap', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/__init__.py0000644000175000017500000000067110743421035024165 0ustar stanistani# __init__.py: static bitmap widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import static_bitmap return static_bitmap.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/static_bitmap/static_bitmap.py0000644000175000017500000001546610743421035025261 0ustar stanistani# static_bitmap.py: wxStaticBitmap objects # $Id: static_bitmap.py,v 1.21 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * import os class EditStaticBitmap(ManagedBase): def __init__(self, name, parent, id, bmp_file, sizer, pos, property_window, show=True): """\ Class to handle wxStaticBitmap objects """ self.attribute = True ManagedBase.__init__(self, name, 'wxStaticBitmap', parent, id, sizer, pos, property_window, show=show) self.set_bitmap(bmp_file) # bitmap property self.access_functions['bitmap'] = (self.get_bitmap, self.set_bitmap) def set_attribute(v): self.attribute = int(v) self.access_functions['attribute'] = (lambda : self.attribute, set_attribute) self.bitmap_prop = FileDialogProperty(self, 'bitmap', None, #panel, style=wx.OPEN|wx.FILE_MUST_EXIST, can_disable=False, label=_("bitmap")) self.properties['bitmap'] = self.bitmap_prop self.properties['attribute'] = CheckBoxProperty( self, 'attribute', None, _('Store as attribute'), write_always=True) self.style = 0 self.access_functions['style'] = (self.get_style, self.set_style) self.style_pos = (wx.SIMPLE_BORDER, wx.DOUBLE_BORDER, wx.SUNKEN_BORDER, wx.RAISED_BORDER, wx.STATIC_BORDER, wx.NO_3D, wx.TAB_TRAVERSAL, wx.WANTS_CHARS, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE, wx.CLIP_CHILDREN) style_labels = (u'#section#' + _('Style'), 'wxSIMPLE_BORDER', 'wxDOUBLE_BORDER', 'wxSUNKEN_BORDER', 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_3D', 'wxTAB_TRAVERSAL', 'wxWANTS_CHARS', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE', 'wxCLIP_CHILDREN') self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) def create_widget(self): bmp = self.load_bitmap() self.widget = wx.StaticBitmap(self.parent.widget, self.id, bmp) if wx.Platform == '__WXMSW__': def get_best_size(): bmp = self.widget.GetBitmap() if bmp and bmp.Ok(): return bmp.GetWidth(), bmp.GetHeight() return wx.StaticBitmap.GetBestSize(self.widget) self.widget.GetBestSize = get_best_size def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) self.properties['bitmap'].display(panel) self.properties['attribute'].display(panel) self.properties['style'].display(panel) szr.Add(self.properties['bitmap'].panel, 0, wx.EXPAND) szr.Add(self.properties['attribute'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, "Widget") self.property_window.Layout() import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def get_bitmap(self): return self.bitmap def set_bitmap(self, value): self.bitmap = value if self.widget: bmp = self.load_bitmap() self.widget.SetBitmap(bmp) self.set_size("%s, %s" % tuple(self.widget.GetBestSize())) def load_bitmap(self, empty=[None]): if self.bitmap and \ not (self.bitmap.startswith('var:') or self.bitmap.startswith('code:')): path = misc.get_relative_path(self.bitmap) print "LOADING FROM:", path return wx.Bitmap(path, wx.BITMAP_TYPE_ANY) else: if empty[0] is None: empty[0] = wx.EmptyBitmap(1, 1) return empty[0] def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditStaticBitmap def builder(parent, sizer, pos, number=[1]): """\ factory function for EditStaticBitmap objects. """ name = 'bitmap_%s' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'bitmap_%s' % number[0] bitmap = misc.FileSelector("Select the image") static_bitmap = EditStaticBitmap(name, parent, wx.NewId(), bitmap, sizer, pos, common.property_panel) node = Tree.Node(static_bitmap) static_bitmap.node = node static_bitmap.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditStaticBitmap objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, "'name' attribute missing" if sizer is None or sizeritem is None: raise XmlParsingError, "sizer or sizeritem object cannot be None" bitmap = EditStaticBitmap(label, parent, wx.NewId(), '', sizer, pos, common.property_panel) sizer.set_item(bitmap.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) #, size=bitmap.GetBestSize()) node = Tree.Node(bitmap) bitmap.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return bitmap def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditStaticBitmap'] = builder common.widgets_from_xml['EditStaticBitmap'] = xml_builder return common.make_object_button('EditStaticBitmap', 'icons/static_bitmap.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/codegen.py0000644000175000017500000001536410743421035024063 0ustar stanistani# codegen.py: code generator functions for wxBitmapButton objects # $Id: codegen.py,v 1.26 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn prop = obj.properties id_name, id = pygen.generate_code_id(obj) bmp_file = prop.get('bitmap', '') bmp_preview_path = os.path.join(common.wxglade_path, "icons", "icon.xpm") if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' if not bmp_file: bmp = cn('wxNullBitmap') elif bmp_file.startswith('var:'): if obj.preview: bmp = "%s('%s', %s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM')) else: bmp = (cn('wxBitmap') + '(%s,' + cn('wxBITMAP_TYPE_ANY)')) % \ bmp_file[4:].strip() elif bmp_file.startswith('code:'): if obj.preview: bmp = "%s('%s', %s)" % (cn('wxBitmap'), bmp_preview_path, cn('wxBITMAP_TYPE_XPM')) else: bmp = '(%s)' % \ bmp_file[5:].strip() else: if obj.preview: import misc bmp_file = misc.get_relative_path(bmp_file, True) bmp = (cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + ')') % pygen.quote_str(bmp_file, False, False) init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = cn(klass) init.append('self.%s = %s(%s, %s, %s%s)\n' % (obj.name, klass, parent, id, bmp,style)) props_buf = pygen.generate_common_properties(obj) disabled_bmp = prop.get('disabled_bitmap') if disabled_bmp: if disabled_bmp.startswith('var:'): if not obj.preview: var = disabled_bmp[4:].strip() props_buf.append( ('self.%s.SetBitmapDisabled(' + cn('wxBitmap') +'(%s,' + cn('wxBITMAP_TYPE_ANY') + '))\n') % (obj.name, var)) elif disabled_bmp.startswith('code:'): if not obj.preview: var = disabled_bmp[5:].strip() props_buf.append( ('self.%s.SetBitmapDisabled(' + '(%s))\n') % \ (obj.name, var)) else: props_buf.append(('self.%s.SetBitmapDisabled(' + cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + '))\n') % \ (obj.name, pygen.quote_str(disabled_bmp, False, False))) if not prop.has_key('size'): props_buf.append('self.%s.SetSize(self.%s.GetBestSize())\n' % \ (obj.name, obj.name)) if prop.get('default', False): props_buf.append('self.%s.SetDefault()\n' % obj.name) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, obj): """\ fuction that generates C++ code for wxBitmapButton objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] bmp_file = prop.get('bitmap', '') if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get("style") if style: extra = ', wxDefaultPosition, wxDefaultSize, %s' % style if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): bmp = 'wxBitmap(%s, wxBITMAP_TYPE_ANY)' % bmp_file[4:].strip() elif bmp_file.startswith('code:'): bmp = '(%s)' % bmp_file[5:].strip() else: bmp = 'wxBitmap(%s, wxBITMAP_TYPE_ANY)' % \ cppgen.quote_str(bmp_file, False, False) init = [ '%s = new %s(%s, %s, %s%s);\n' % (obj.name, obj.klass, parent, id, bmp,extra) ] props_buf = cppgen.generate_common_properties(obj) disabled_bmp = prop.get('disabled_bitmap') if disabled_bmp: if disabled_bmp.startswith('var:'): var = disabled_bmp[4:].strip() props_buf.append('%s->SetBitmapDisabled(' 'wxBitmap(%s,wxBITMAP_TYPE_ANY));\n' % (obj.name, var)) elif disabled_bmp.startswith('code:'): var = disabled_bmp[5:].strip() props_buf.append('%s->SetBitmapDisabled(' '(%s));\n' % (obj.name, var)) else: props_buf.append( '%s->SetBitmapDisabled(' 'wxBitmap(%s, wxBITMAP_TYPE_ANY));\n' % \ (obj.name, cppgen.quote_str(disabled_bmp, False, False))) if not prop.has_key('size'): props_buf.append('%s->SetSize(%s->GetBestSize());\n' % \ (obj.name, obj.name)) if prop.get('default', False): props_buf.append('%s->SetDefault();\n' % obj.name) return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class BitmapButtonXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'disabled_bitmap': name = 'disabled' xrcgen.DefaultXrcObject.write_property( self, name, val, outfile, tabs) # end of class BitmapButtonXrcObject return BitmapButtonXrcObject(obj) def initialize(): common.class_names['EditBitmapButton'] = 'wxBitmapButton' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxBitmapButton', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxBitmapButton', CppCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxBitmapButton', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/perl_codegen.py0000644000175000017500000000650410743421035025101 0ustar stanistani# perl_codegen.py : perl generator functions for wxBitmapButton objects # $Id: perl_codegen.py,v 1.10 2005/08/15 07:35:15 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os #this should be in common _bmp_str_types = { '.bmp' : 'wxBITMAP_TYPE_BMP', '.gif' : 'wxBITMAP_TYPE_GIF', '.xpm' : 'wxBITMAP_TYPE_XPM', '.jpg' : 'wxBITMAP_TYPE_JPEG', '.jpeg': 'wxBITMAP_TYPE_JPEG', '.png' : 'wxBITMAP_TYPE_PNG', '.pcx' : 'wxBITMAP_TYPE_PCX' } class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) bmp_file = prop.get('bitmap', '') if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): # this is a variable holding pathname of bitmap var = bmp_file[4:].strip() if var[0] != "$": var = "$" + var bmp = 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % var elif bmp_file.startswith('code:'): # this is a code chunk bmp = '(%s)' % bmp_file[5:].strip() else: bmp = 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY)' % \ plgen.quote_path(bmp_file) init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, %s);\n' % ( obj.name, klass, parent, id, bmp) ) props_buf = plgen.generate_common_properties(obj) disabled_bmp = prop.get('disabled_bitmap') if disabled_bmp: if disabled_bmp.startswith('var:'): var = disabled_bmp[4:].strip() if var[0] != "$": var = "$" + var props_buf.append( '$self->{%s}->SetBitmapDisabled(' 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY));\n' % (obj.name, var)) elif disabled_bmp.startswith('code:'): var = disabled_bmp[5:].strip() props_buf.append( '$self->{%s}->SetBitmapDisabled(' '%s);\n' % (obj.name, var)) else: props_buf.append( '$self->{%s}->SetBitmapDisabled(' 'Wx::Bitmap->new(%s, wxBITMAP_TYPE_ANY));\n' % \ (obj.name, plgen.quote_path(disabled_bmp))) if not prop.has_key('size'): props_buf.append( '$self->{%s}->SetSize($self->{%s}->GetBestSize());\n' % (obj.name, obj.name) ) if prop.get('default', False): props_buf.append('$self->{%s}->SetDefault();\n' % obj.name) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditBitmapButton'] = 'wxBitmapButton' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxBitmapButton', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/bitmap_button.py0000644000175000017500000002027710743421035025325 0ustar stanistani# bitmap_button.py: wxBitmapButton objects # $Id: bitmap_button.py,v 1.26 2007/04/12 07:15:34 guyru Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc, os from edit_windows import ManagedBase from tree import Tree from widget_properties import * class EditBitmapButton(ManagedBase): events = ['EVT_BUTTON'] def __init__(self, name, parent, id, bmp_file, sizer, pos, property_window, show=True): """\ Class to handle wxBitmapButton objects """ import config ManagedBase.__init__(self, name, 'wxBitmapButton', parent, id, sizer, pos, property_window, show=show) self.default = False self.set_bitmap(bmp_file) # bitmap property self.access_functions['bitmap'] = (self.get_bitmap, self.set_bitmap) self.properties['bitmap'] = FileDialogProperty(self, 'bitmap', None, style=wx.OPEN | wx.FILE_MUST_EXIST, can_disable=False, label=_("bitmap")) self.access_functions['default'] = (self.get_default, self.set_default) self.access_functions['style'] = (self.get_style, self.set_style) self.properties['default'] = CheckBoxProperty(self, 'default', None, label=_("default")) # 2003-08-07: added 'disabled_bitmap' property self.disabled_bitmap = "" self.access_functions['disabled_bitmap'] = (self.get_disabled_bitmap, self.set_disabled_bitmap) self.properties['disabled_bitmap'] = FileDialogProperty( self, 'disabled_bitmap', None, style=wx.OPEN|wx.FILE_MUST_EXIST, label=_("disabled bitmap")) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL self.style_pos = (wx.BU_AUTODRAW, wx.BU_LEFT, wx.BU_RIGHT, wx.BU_TOP, wx.BU_BOTTOM, wx.NO_BORDER) style_labels = ('#section#' + _('Style'), 'wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_RIGHT', 'wxBU_TOP', 'wxBU_BOTTOM', 'wxNO_BORDER') #The tooltips tuple self.tooltips=(_("If this is specified, the button will be drawn " "automatically using the label bitmap only, providing" " a 3D-look border. If this style is not specified, the " "button will be drawn without borders and using all " "provided bitmaps. WIN32 only." "Left-justifies the bitmap label. WIN32 only."), _("Right-justifies the bitmap label. WIN32 only."), _("Aligns the bitmap label to the top of the button." " WIN32 only."), _("Aligns the bitmap label to the bottom of the button." " WIN32 only."), _("Creates a flat button. Windows and GTK+ only.")) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels,tooltips=self.tooltips) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) self.properties['bitmap'].display(panel) self.properties['disabled_bitmap'].display(panel) self.properties['default'].display(panel) self.properties['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.properties['bitmap'].panel, 0, wx.EXPAND) szr.Add(self.properties['disabled_bitmap'].panel, 0, wx.EXPAND) szr.Add(self.properties['default'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_bitmap(self): return self.bitmap def set_bitmap(self, value): self.bitmap = value if self.widget: bmp = self.load_bitmap() self.widget.SetBitmapLabel(bmp) self.widget.SetBitmapSelected(bmp) self.widget.SetBitmapFocus(bmp) self.set_size("%s, %s" % tuple(self.widget.GetBestSize())) def get_disabled_bitmap(self): return self.disabled_bitmap def set_disabled_bitmap(self, value): self.disabled_bitmap = value if self.widget: bmp = self.load_bitmap(self.disabled_bitmap) self.widget.SetBitmapDisabled(bmp) self.set_size("%s, %s" % tuple(self.widget.GetBestSize())) def create_widget(self): bmp = self.load_bitmap() try: self.widget = wx.BitmapButton(self.parent.widget, self.id, bmp, style=self.style) except AttributeError: self.widget = wx.BitmapButton(self.parent.widget, self.id, bmp) def load_bitmap(self, which=None, empty=[None]): if which is None: which = self.bitmap if which and \ not (which.startswith('var:') or which.startswith('code:')): which = misc.get_relative_path(which) return wx.Bitmap(which, wx.BITMAP_TYPE_ANY) else: if empty[0] is None: empty[0] = wx.EmptyBitmap(1, 1) return empty[0] def get_default(self): return self.default def set_default(self, value): self.default = bool(int(value)) ## if value and self.widget: ## self.widget.SetDefault() # end of class EditBitmapButton def builder(parent, sizer, pos, number=[1]): """\ factory function for EditBitmapButton objects. """ name = 'bitmap_button_%s' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'bitmap_button_%s' % number[0] bitmap = misc.FileSelector(_("Select the image for the button")) button = EditBitmapButton(name, parent, wx.NewId(), bitmap, sizer, pos, common.property_panel) node = Tree.Node(button) button.node = node button.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditBitmapButton objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") button = EditBitmapButton(label, parent, wx.NewId(), '', sizer, pos, common.property_panel, show=False) sizer.set_item(button.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) #, size=button.GetBestSize()) node = Tree.Node(button) button.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return button def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditBitmapButton'] = builder common.widgets_from_xml['EditBitmapButton'] = xml_builder return common.make_object_button('EditBitmapButton', 'icons/bitmap_button.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/lisp_codegen.py0000644000175000017500000000624510743421035025110 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxBitmapButton objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:33:57 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common, os #this should be in common _bmp_str_types = { '.bmp' : 'wxBITMAP_TYPE_BMP', '.gif' : 'wxBITMAP_TYPE_GIF', '.xpm' : 'wxBITMAP_TYPE_XPM', '.jpg' : 'wxBITMAP_TYPE_JPEG', '.jpeg': 'wxBITMAP_TYPE_JPEG', '.png' : 'wxBITMAP_TYPE_PNG', '.pcx' : 'wxBITMAP_TYPE_PCX' } class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) bmp_file = prop.get('bitmap', '') if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' if not bmp_file: bmp = 'wxNullBitmap' elif bmp_file.startswith('var:'): # this is a variable holding pathname of bitmap var = bmp_file[4:].strip() if var[0] != "$": var = "$" + var bmp = '(wxBitmap_CreateLoad %s wxBITMAP_TYPE_ANY)' % var elif bmp_file.startswith('code:'): # this is a code chunk bmp = '(%s)' % bmp_file[5:].strip() else: bmp = '(wxBitmap_CreateLoad %s, wxBITMAP_TYPE_ANY)' % \ plgen.quote_path(bmp_file) init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxBitmapButton_Create %s %s %s -1 -1 -1 -1 0))\n' % ( obj.name, parent, id, bmp)) props_buf = plgen.generate_common_properties(obj) disabled_bmp = prop.get('disabled_bitmap') if disabled_bmp: if disabled_bmp.startswith('var:'): var = disabled_bmp[4:].strip() if var[0] != "$": var = "$" + var props_buf.append( '(wxBitmapButton_SetBitmapDisabled (slot-%s obj) %s)' %(obj.name, var)) elif disabled_bmp.startswith('code:'): var = disabled_bmp[5:].strip() props_buf.append( '(wxBitmapButton_SetBitmapDisabled (slot-%s obj) %s)' % (obj.name, var)) else: props_buf.append( '(wxBitmapButton_SetBitmapDisabled (slot-%s obj) %s)' % (obj.name, plgen.quote_path(disabled_bmp))) wxButton_SetDefault if not prop.has_key('size'): props_buf.append('(wxButton_SetDefault (slot-%s obj))' %(obj.name)) if prop.get('default', False): props_buf.append('(wxButton_SetDefault (slot-%s obj))' %(obj.name)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditBitmapButton'] = 'wxBitmapButton' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxBitmapButton', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/bitmap_button/__init__.py0000644000175000017500000000066210743421035024211 0ustar stanistani# __init__.py: button widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:05 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import bitmap_button return bitmap_button.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/codegen.py0000644000175000017500000000465010743421035023173 0ustar stanistani# codegen.py: code generator functions for wxTreeCtrl objects # $Id: codegen.py,v 1.8 2007/03/27 07:01:50 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style and style != 'wxTR_HAS_BUTTONS': # default style style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s%s)\n' % (obj.name, klass, parent, id, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxTreeCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' extra = '' style = prop.get('style') if style and style != 'wxTR_HAS_BUTTONS': extra = ', wxDefaultPosition, wxDefaultSize, %s' % style init = ['%s = new %s(%s, %s%s);\n' % (obj.name, obj.klass, parent, id, extra)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxTreeEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditTreeCtrl'] = 'wxTreeCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxTreeCtrl', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxTreeCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/perl_codegen.py0000644000175000017500000000257010743421035024214 0ustar stanistani# perl_codegen.py : perl generator functions for wxTreeCtrl objects # $Id: perl_codegen.py,v 1.4 2005/08/15 08:04:00 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not( style and style != 'wxLI_HORIZONTAL' ): # default style style = '' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, wxDefaultPosition, \ wxDefaultSize, %s);\n' % (obj.name, klass, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditTreeCtrl'] = 'wxTreeCtrl' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxTreeCtrl', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/tree_ctrl.py0000644000175000017500000001563310743421035023555 0ustar stanistani# text_ctrl.py: wxTreeCtrl objects # $Id: tree_ctrl.py,v 1.12 2007/03/27 07:01:50 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * class EditTreeCtrl(ManagedBase): """\ Class to handle wx.TreeCtrl objects """ events = [ 'EVT_TREE_BEGIN_DRAG', 'EVT_TREE_BEGIN_RDRAG', 'EVT_TREE_END_DRAG', 'EVT_TREE_END_RDRAG', 'EVT_TREE_BEGIN_LABEL_EDIT', 'EVT_TREE_END_LABEL_EDIT', 'EVT_TREE_DELETE_ITEM', 'EVT_TREE_GET_INFO', 'EVT_TREE_SET_INFO', 'EVT_TREE_ITEM_ACTIVATED', 'EVT_TREE_ITEM_COLLAPSED', 'EVT_TREE_ITEM_COLLAPSING', 'EVT_TREE_ITEM_EXPANDED', 'EVT_TREE_ITEM_EXPANDING', 'EVT_TREE_SEL_CHANGED', 'EVT_TREE_SEL_CHANGING', 'EVT_TREE_KEY_DOWN', 'EVT_TREE_ITEM_GETTOOLTIP', ] def __init__(self, name, parent, id, sizer, pos, property_window, show=True, style=wx.TR_HAS_BUTTONS|wx.SUNKEN_BORDER): ManagedBase.__init__(self, name, 'wxTreeCtrl', parent, id, sizer, pos, property_window, show=show) self.style = style self.access_functions['style'] = (self.get_style, self.set_style) # style property self.style_pos = (wx.TR_HAS_BUTTONS, wx.TR_NO_LINES, wx.TR_LINES_AT_ROOT, wx.TR_EDIT_LABELS, wx.TR_MULTIPLE, wx.TR_NO_BUTTONS, wx.TR_TWIST_BUTTONS, wx.TR_FULL_ROW_HIGHLIGHT, wx.TR_HIDE_ROOT, wx.TR_ROW_LINES, wx.TR_HAS_VARIABLE_ROW_HEIGHT, wx.TR_SINGLE, wx.TR_MULTIPLE, wx.TR_EXTENDED, wx.TR_DEFAULT_STYLE, wx.SIMPLE_BORDER, wx.DOUBLE_BORDER, wx.SUNKEN_BORDER, wx.RAISED_BORDER, wx.STATIC_BORDER, wx.NO_BORDER, wx.WANTS_CHARS, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE) style_labels = ('#section#' + _('Style'), 'wxTR_HAS_BUTTONS', 'wxTR_NO_LINES', 'wxTR_LINES_AT_ROOT', 'wxTR_EDIT_LABELS', 'wxTR_MULTIPLE', 'wxTR_NO_BUTTONS', 'wxTR_TWIST_BUTTONS', 'wxTR_FULL_ROW_HIGHLIGHT', 'wxTR_HIDE_ROOT', 'wxTR_ROW_LINES', 'wxTR_HAS_VARIABLE_ROW_HEIGHT','wxTR_SINGLE', 'wxTR_MULTIPLE', 'wxTR_EXTENDED', 'wxTR_DEFAULT_STYLE', 'wxSIMPLE_BORDER', 'wxDOUBLE_BORDER', 'wxSUNKEN_BORDER', 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_BORDER', 'wxWANTS_CHARS', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE') self.properties['style'] = CheckListProperty(self, 'style', None, style_labels) self._item_with_name = None def create_widget(self): self.widget = wx.TreeCtrl(self.parent.widget, self.id, style=wx.TR_HAS_BUTTONS|wx.SUNKEN_BORDER) # add a couple of items just for a better appearence root = self.widget.AddRoot(_(' Tree Control:')) self._item_with_name = self.widget.AppendItem(root, ' ' + self.name) self.widget.AppendItem(self._item_with_name, _(' on wxGlade %s') % common.version) self.widget.Expand(root) self.widget.Expand(self._item_with_name) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self, sel_marker_parent=self.widget) def set_name(self, name): ManagedBase.set_name(self, name) if self.widget and self._item_with_name: self.widget.SetItemText(self._item_with_name, ' ' + self.name) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) prop = self.properties prop['style'].display(panel) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) w, h = panel.GetClientSize() self.notebook.AddPage(panel, _('Widget')) self.property_window.Layout() import math panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] # end of class EditTreeCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditTreeCtrl objects. """ name = 'tree_ctrl_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'tree_ctrl_%d' % number[0] tree_ctrl = EditTreeCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(tree_ctrl) tree_ctrl.node = node tree_ctrl.set_option(1) tree_ctrl.set_flag("wxEXPAND") tree_ctrl.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) sizer.set_item(tree_ctrl.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditTreeCtrl objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, "'name' attribute missing" if sizer is None or sizeritem is None: raise XmlParsingError, "sizer or sizeritem object cannot be None" tree_ctrl = EditTreeCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel, style=0) sizer.set_item(tree_ctrl.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(tree_ctrl) tree_ctrl.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return tree_ctrl def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditTreeCtrl'] = builder common.widgets_from_xml['EditTreeCtrl'] = xml_builder return common.make_object_button('EditTreeCtrl', 'icons/tree_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/lisp_codegen.py0000644000175000017500000000264110743421035024220 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxTreeCtrl objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:39:48 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) if not obj.parent.is_toplevel: parent = '(object-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not( style and style != 'wxLI_HORIZONTAL' ): # default style style = '' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxTreeCtrl_Create %s %s -1 -1 -1 -1 %s))\n' % (obj.name, parent, id, style)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditTreeCtrl'] = 'wxTreeCtrl' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxTreeCtrl', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/tree_ctrl/__init__.py0000644000175000017500000000065510743421035023327 0ustar stanistani# __init__.py: tree ctrl widget module initialization # $Id: __init__.py,v 1.5 2007/03/27 07:01:50 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import tree_ctrl return tree_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/codegen.py0000644000175000017500000000725010743421035023204 0ustar stanistani# codegen.py: code generator functions for wxSpinCtrl objects # $Id: codegen.py,v 1.15 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) value = prop.get('value', '') try: min_v, max_v = [ s.strip() for s in \ prop.get('range', '0, 100').split(',') ] except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style") if style: style = ", style=%s" % pygen.cn_f(style) else: style = '' init = [] if id_name: init.append(id_name) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, "%s", min=%s, max=%s%s)\n' % (obj.name, klass, parent, id, value, min_v, max_v, style)) props_buf = pygen.generate_common_properties(obj) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class SpinCtrlXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'range': try: min, max = val.split(',') except ValueError: pass else: tab_s = ' '*tabs outfile.write(tab_s + '%s\n' % min) outfile.write(tab_s + '%s\n' % max) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class SpinCtrlXrcObject return SpinCtrlXrcObject(obj) class CppCodeGenerator: extra_headers = [''] def get_code(self, obj): """\ generates C++ code for wxSpinCtrl objects. """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] value = prop.get('value', '') try: min_v, max_v = [ s.strip() for s in \ prop.get('range', '0, 100').split(',') ] except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' style = prop.get('style') if not style: style = 'wxSP_ARROW_KEYS' init = ['%s = new %s(%s, %s, wxT("%s"), wxDefaultPosition, ' 'wxDefaultSize, %s, %s, %s);\n' % (obj.name, obj.klass, parent, id, value, style, min_v, max_v)] props_buf = cppgen.generate_common_properties(obj) return init, ids, props_buf, [] def get_events(self, obj): cppgen = common.code_writers['C++'] return cppgen.get_events_with_type(obj, 'wxSpinEvent') # end of class CppCodeGenerator def initialize(): common.class_names['EditSpinCtrl'] = 'wxSpinCtrl' pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxSpinCtrl', PythonCodeGenerator()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxSpinCtrl', xrc_code_generator) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxSpinCtrl', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/perl_codegen.py0000644000175000017500000000312310743421035024221 0ustar stanistani# perl_codegen.py : perl generator functions for wxSpinCtrl objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:43:17 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, obj): plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = prop.get('value', '') try: min_v, max_v = [ s.strip() for s in \ prop.get('range', '0, 100').split(',') ] except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style") if not style: style = 'wxSP_ARROW_KEYS' init = [] if id_name: init.append(id_name) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, "%s", wxDefaultPosition, \ wxDefaultSize, %s, %s, %s, %s);\n' % (obj.name, klass, parent, id, value, style, min_v, max_v, value)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditSpinCtrl'] = 'wxSpinCtrl' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxSpinCtrl', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/lisp_codegen.py0000644000175000017500000000315110743421035024227 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxSpinCtrl objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 07:00:42 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, obj): plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) value = prop.get('value', '') try: min_v, max_v = [ s.strip() for s in \ prop.get('range', '0, 100').split(',') ] except: min_v, max_v = '0', '100' if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style") if not style: style = 'wxSP_ARROW_KEYS' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style init = [] if id_name: init.append(id_name) init.append('(setf (slot-%s obj) (wxSpinCtrl_Create %s %s %s -1 -1 -1 -1 %s %s %s %s))\n' % (obj.name, parent, id, value, style, min_v, max_v, value)) props_buf = plgen.generate_common_properties(obj) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditSpinCtrl'] = 'wxSpinCtrl' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxSpinCtrl', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/__init__.py0000644000175000017500000000065510743421035023341 0ustar stanistani# __init__.py: spin ctrl widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import spin_ctrl return spin_ctrl.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spin_ctrl/spin_ctrl.py0000644000175000017500000001424310743421035023575 0ustar stanistani# spin_ctrl.py: wxSpinCtrl objects # $Id: spin_ctrl.py,v 1.16 2007/03/27 07:01:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from edit_windows import ManagedBase from tree import Tree import common, misc from widget_properties import * class EditSpinCtrl(ManagedBase): """\ Class to handle wxSpinCtrl objects """ events = ['EVT_SPINCTRL'] def __init__(self, name, parent, id, sizer, pos, property_window, show=True): import config ManagedBase.__init__(self, name, 'wxSpinCtrl', parent, id, sizer, pos, property_window, show=show) self.style = 0 self.value = 0 self.range = (0, 100) # Default values in wxSpinCtrl constructor. prop = self.properties self.access_functions['style'] = (self.get_style, self.set_style) self.access_functions['value'] = (self.get_value, self.set_value) self.access_functions['range'] = (self.get_range, self.set_range) style_labels = ('#section#' + _('Style'), 'wxSP_ARROW_KEYS', 'wxSP_WRAP', 'wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE', 'wxTE_PASSWORD', 'wxTE_READONLY', 'wxHSCROLL', 'wxTE_RICH', 'wxTE_RICH2', 'wxTE_AUTO_URL', 'wxTE_NOHIDESEL', 'wxTE_CENTRE', 'wxTE_RIGHT', 'wxTE_LINEWRAP', 'wxTE_WORDWRAP', 'wxNO_BORDER') self.style_pos = (wx.SP_ARROW_KEYS, wx.SP_WRAP, wx.TE_PROCESS_ENTER, wx.TE_PROCESS_TAB, wx.TE_MULTILINE,wx.TE_PASSWORD, wx.TE_READONLY, wx.HSCROLL, wx.TE_RICH, wx.TE_RICH2, wx.TE_AUTO_URL, wx.TE_NOHIDESEL, wx.TE_CENTRE, wx.TE_RIGHT, wx.TE_LINEWRAP, wx.TE_WORDWRAP, wx.NO_BORDER) prop['style'] = CheckListProperty(self, 'style', None, style_labels) prop['range'] = TextProperty(self, 'range', None, can_disable=True, label=_("range")) prop['value'] = SpinProperty(self, 'value', None, can_disable=True, label=_("value")) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wx.SpinCtrl(self.parent.widget, self.id, min=self.range[0], max=self.range[1], initial=self.value) def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) prop = self.properties prop['range'].display(panel) prop['value'].display(panel) prop['style'].display(panel) szr.Add(prop['range'].panel, 0, wx.EXPAND) szr.Add(prop['value'].panel, 0, wx.EXPAND) szr.Add(prop['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_range(self): # we cannot return self.range since this would become a "(0, 100)" # string, and we don't want the parens return "%s, %s" % self.range def set_range(self, val): try: min_v, max_v = map(int, val.split(',')) except: self.properties['range'].set_value(self.get_range()) else: self.range = (min_v, max_v) self.properties['value'].set_range(min_v, max_v) if self.widget: self.widget.SetRange(min_v, max_v) def get_value(self): return self.value def set_value(self, value): value = int(value) if self.value != value: self.value = value if self.widget: self.widget.SetValue(self.value) # end of class EditSpinCtrl def builder(parent, sizer, pos, number=[1]): """\ factory function for EditSpinCtrl objects. """ name = 'spin_ctrl_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'spin_ctrl_%d' % number[0] text = EditSpinCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(text) text.node = node text.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditSpinCtrl objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") text = EditSpinCtrl(name, parent, wx.NewId(), sizer, pos, common.property_panel) sizer.set_item(text.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(text) text.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return text def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditSpinCtrl'] = builder common.widgets_from_xml['EditSpinCtrl'] = xml_builder return common.make_object_button('EditSpinCtrl', 'icons/spin_ctrl.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/codegen.py0000644000175000017500000000261110743421035022460 0ustar stanistani# codegen.py: code generator functions for spacers # $Id: codegen.py,v 1.9 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, spacer): prop = spacer.properties width = prop.get('width', '0') height = prop.get('height', '0') # we must use the hack in pygen.add_sizeritem (see py_codegen.py) spacer.name = '%s, %s' % (width, height) return [], [], [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, spacer): """\ generates the C++ code for a spacer """ prop = spacer.properties width = prop.get('width', '0') height = prop.get('height', '0') # we must use the hack in cppgen.add_sizeritem (see cpp_codegen.py) spacer.name = '%s, %s' % (width, height) return [], [], [], [] # end of class CppCodeGenerator def initialize(): common.class_names['EditSpacer'] = 'spacer' # python code generation functions pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('spacer', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('spacer', CppCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/perl_codegen.py0000644000175000017500000000147010743421035023504 0ustar stanistani# perl_codegen.py : perl generator functions for spacers # $Id: perl_codegen.py,v 1.2 2004/09/17 13:09:50 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: def get_code(self, spacer): prop = spacer.properties width = prop.get('width', '0') height = prop.get('height', '0') # we must use the hack in plgen.add_sizeritem (see pl_codegen.py) spacer.name = '%s, %s' % (width, height) return [], [], [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditSpacer'] = 'spacer' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('spacer', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/lisp_codegen.py0000644000175000017500000000147010743421035023511 0ustar stanistani # lisp_codegen.py : lisp generator functions for spacers # $Id: lisp_codegen.py,v 1.2 2007/02/09 22:24:06 dinogen Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: def get_code(self, spacer): prop = spacer.properties width = prop.get('width', '0') height = prop.get('height', '0') # we must use the hack in plgen.add_sizeritem (see pl_codegen.py) spacer.name = '%s, %s' % (width, height) return [], [], [] # end of class LispCodeGenerator def initialize(): common.class_names['EditSpacer'] = 'spacer' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('spacer', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/__init__.py0000644000175000017500000000064410743421035022617 0ustar stanistani# __init__.py: spacer widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:01:54 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import spacer return spacer.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/spacer/spacer.py0000644000175000017500000001374010743421035022336 0ustar stanistani# spacer.py: spacers to use in sizers # $Id: spacer.py,v 1.13 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase class EditSpacer(ManagedBase): def __init__(self, name, parent, id, width, height, sizer, pos, property_window, show=True): """\ Class to handle spacers for sizers """ ManagedBase.__init__(self, name, 'spacer', parent, id, sizer, pos, property_window, show=show) self.__size = [width, height] self.access_functions['width'] = (self.get_width, self.set_width) self.access_functions['height'] = (self.get_height, self.set_height) self.properties['width'] = SpinProperty(self, 'width', None, label=_("width")) self.properties['height'] = SpinProperty(self, 'height', None, label=_("height")) def create_widget(self): self.widget = wx.Window(self.parent.widget, self.id, size=self.__size, style=wx.SIMPLE_BORDER) self.widget.GetBestSize = self.widget.GetSize wx.EVT_PAINT(self.widget, self.on_paint) def create_properties(self): ManagedBase.create_properties(self) page = self.notebook.GetPage(1) wp = self.properties['width'] hp = self.properties['height'] wp.display(page) hp.display(page) szr = page.GetSizer() szr.Insert(0, hp.panel, 0, wx.EXPAND) szr.Insert(0, wp.panel, 0, wx.EXPAND) szr.Layout() szr.Fit(page) import math w, h = page.GetClientSize() page.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) common_page = self.notebook.GetPage(0) common_page.Hide() self.notebook.RemovePage(0) self.notebook.SetSelection(0) def get_width(self): return self.__size[0] def get_height(self): return self.__size[1] def set_width(self, value): value = int(value) self.__size[0] = value if self.widget: self.widget.SetSize(self.__size) self.sizer.set_item(self.pos, size=self.__size) def set_height(self, value): value = int(value) self.__size[1] = value if self.widget: self.widget.SetSize(self.__size) self.sizer.set_item(self.pos, size=self.__size) def set_flag(self, value): ManagedBase.set_flag(self, value) if not (self.get_int_flag() & wx.EXPAND): self.sizer.set_item(self.pos, size=self.__size) def on_paint(self, event): dc = wx.PaintDC(self.widget) dc.BeginDrawing() brush = wx.TheBrushList.FindOrCreateBrush( self.widget.GetBackgroundColour()) dc.SetBrush(brush) dc.SetPen(wx.ThePenList.FindOrCreatePen(wx.BLACK, 1, wx.SOLID)) dc.SetBackground(brush) dc.Clear() w, h = self.widget.GetClientSize() dc.DrawLine(0, 0, w, h) dc.DrawLine(w, 0, 0, h) text = _('Spacer') tw, th = dc.GetTextExtent(text) x = (w - tw)/2 y = (h - th)/2 dc.SetPen(wx.ThePenList.FindOrCreatePen(wx.BLACK, 0, wx.TRANSPARENT)) dc.DrawRectangle(x-1, y-1, tw+2, th+2) dc.DrawText(text, x, y) dc.EndDrawing() # end of class EditSpacer def builder(parent, sizer, pos): """\ factory function for EditSpacer objects. """ class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, misc.get_toplevel_parent(parent), -1, _("Enter size")) self.width = SpinProperty(self, 'width', self, label=_("width")) self.height = SpinProperty(self, 'height', self, label=_("height")) self.width.set_value(20) self.height.set_value(20) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.width.panel, 0, wx.EXPAND) szr.Add(self.height.panel, 0, wx.EXPAND) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(wx.Button(self, wx.ID_OK, _('OK'))) szr.Add(sz, 0, wx.ALL|wx.ALIGN_CENTER, 4) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, name): return (lambda : 0, lambda v: None) # end of inner class dialog = Dialog() dialog.ShowModal() name = 'spacer' spacer = EditSpacer(name, parent, wx.NewId(), dialog.width.get_value(), dialog.height.get_value(), sizer, pos, common.property_panel) node = Tree.Node(spacer) spacer.node = node spacer.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) #sizer.set_item(spacer.pos, size=spacer.GetSize()) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditSpacer objects from an xml file """ from xml_parse import XmlParsingError if not sizer or not sizeritem: raise XmlParsingError, _("sizer or sizeritem object cannot be None") spacer = EditSpacer('spacer', parent, wx.NewId(), 1, 1, sizer, pos, common.property_panel, True) sizer.set_item(spacer.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(spacer) spacer.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return spacer def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['EditSpacer'] = builder common.widgets_from_xml['EditSpacer'] = xml_builder return common.make_object_button('EditSpacer', 'icons/spacer.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/codegen.py0000644000175000017500000001166210743421035022450 0ustar stanistani# codegen.py: code generator functions for wxDialog objects # $Id: codegen.py,v 1.15 2007/03/27 07:02:00 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonCodeGenerator: def get_code(self, obj): return [], [], [] def get_properties_code(self, dialog): prop = dialog.properties pygen = common.code_writers['python'] cn = pygen.cn out = [] title = prop.get('title') if title: out.append('self.SetTitle(%s)\n' % pygen.quote_str(title)) icon = prop.get('icon') if icon: if icon.startswith('var:'): if not dialog.preview: out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(' + cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + '))\n') % \ icon[4:].strip()) out.append('self.SetIcon(_icon)\n') elif icon.startswith('code:'): if not dialog.preview: out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(%s)\n') % \ icon[5:].strip()) out.append('self.SetIcon(_icon)\n') else: if dialog.preview: import misc icon = misc.get_relative_path(icon, True) out.append('_icon = ' + cn('wxEmptyIcon') + '()\n') out.append(('_icon.CopyFromBitmap(' + cn('wxBitmap') + '(%s, ' + cn('wxBITMAP_TYPE_ANY') + '))\n') % \ pygen.quote_str(icon, False, False)) out.append('self.SetIcon(_icon)\n') out.extend(pygen.generate_common_properties(dialog)) return out def get_layout_code(self, dialog): ret = ['self.Layout()\n'] try: if int(dialog.properties['centered']): ret.append('self.Centre()\n') except (KeyError, ValueError): pass return ret # end of class PythonCodeGenerator class CppCodeGenerator: constructor = [('wxWindow*', 'parent'), ('int', 'id'), ('const wxString&', 'title'), ('const wxPoint&', 'pos', 'wxDefaultPosition'), ('const wxSize&', 'size', 'wxDefaultSize'), ('long', 'style', 'wxDEFAULT_DIALOG_STYLE')] def get_code(self, obj): return [], [], [], [] def get_properties_code(self, dialog): """\ generates the code for the various wxDialog specific properties. Returns a list of strings containing the generated code """ prop = dialog.properties cppgen = common.code_writers['C++'] out = [] title = prop.get('title') if title: out.append('SetTitle(%s);\n' % cppgen.quote_str(title)) icon = prop.get('icon') if icon: out.append('wxIcon _icon;\n') if icon.startswith('var:'): out.append('_icon.CopyFromBitmap(wxBitmap(' + '%s, wxBITMAP_TYPE_ANY));\n' % \ icon[4:].strip()) elif icon.startswith('code:'): out.append('_icon.CopyFromBitmap(%s);\n' % \ icon[5:].strip()) else: out.append('_icon.CopyFromBitmap(wxBitmap(%s, ' 'wxBITMAP_TYPE_ANY));\n' % \ cppgen.quote_str(icon, False, False)) out.append('SetIcon(_icon);\n') out.extend(cppgen.generate_common_properties(dialog)) return out def get_layout_code(self, dialog): ret = ['Layout();\n'] try: if int(dialog.properties['centered']): ret.append('Centre();\n') except (KeyError, ValueError): pass return ret # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class DialogXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, ntabs): if name != 'sizehints': xrcgen.DefaultXrcObject.write_property( self, name, val, outfile, ntabs) # end of class DialogXrcObject return DialogXrcObject(obj) def initialize(): cn = common.class_names cn['EditDialog'] = 'wxDialog' common.toplevels['EditDialog'] = 1 pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('wxDialog', PythonCodeGenerator()) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxDialog', CppCodeGenerator()) xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('wxDialog', xrc_code_generator) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/perl_codegen.py0000644000175000017500000000325510743421035023471 0ustar stanistani# perl_codegen.py : perl generator functions for wxDialog objects # $Id: perl_codegen.py,v 1.3 2004/09/17 13:09:53 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PerlCodeGenerator: #wxDialog( parent, id, title, pos, size, style, name ) new_signature = [ '$parent', '$id', '$title', '$pos', '$size', '$style', '$name' ] def get_code(self, obj): return [], [], [] def get_properties_code(self, dialog): prop = dialog.properties plgen = common.code_writers['perl'] out = [] title = prop.get('title') if title: out.append('$self->SetTitle(%s);\n' % plgen.quote_str(title)) icon = prop.get('icon') if icon: out.append('my $icon = &Wx::wxNullIcon();\n') out.append('$icon->CopyFromBitmap(Wx::Bitmap->new(%s, ' 'wxBITMAP_TYPE_ANY));\n' % plgen.quote_str(icon)) out.append('$self->SetIcon($icon);\n') out.extend(plgen.generate_common_properties(dialog)) return out def get_layout_code(self, dialog): ret = ['$self->Layout();\n'] try: if int(dialog.properties['centered']): ret.append('$self->Centre();\n') except (KeyError, ValueError): pass return ret # end of class PerlCodeGenerator def initialize(): cn = common.class_names cn['EditDialog'] = 'wxDialog' common.toplevels['EditDialog'] = 1 plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxDialog', PerlCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/lisp_codegen.py0000644000175000017500000000345310743421035023476 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxDialog objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:14 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class LispCodeGenerator: #wxDialog( parent, id, title, pos, size, style, name ) new_signature = [ '$parent', '$id', '$title', '$pos', '$size', '$style', '$name' ] def get_code(self, obj): return [], [], [] def get_properties_code(self, dialog): prop = dialog.properties plgen = common.code_writers['lisp'] out = [] title = prop.get('title') if title: out.append('(wxWindow_SetTitle (slot-%s self) %s)\n' % (dialog.name, plgen.quote_str(title))) icon = prop.get('icon') if icon: out.append('my $icon = &Wx::wxNullIcon();\n') out.append('$icon->CopyFromBitmap(Wx::Bitmap->new(%s, ' 'wxBITMAP_TYPE_ANY));\n' % plgen.quote_str(icon)) out.append('$self->SetIcon($icon);\n') out.extend(plgen.generate_common_properties(dialog)) return out def get_layout_code(self, dialog): ret = ['(wxWindow_layout (slot-%s slef))\n' % dialog.name] try: if int(dialog.properties['centered']): ret.append('(wxWindow_Centre (slot-%s slef) wxBOTH)\n' % dialog.name) except (KeyError, ValueError): pass return ret # end of class LispCodeGenerator def initialize(): cn = common.class_names cn['EditDialog'] = 'wxDialog' common.toplevels['EditDialog'] = 1 plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxDialog', LispCodeGenerator()) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/__init__.py0000644000175000017500000000064410743421035022601 0ustar stanistani# __init__.py: dialog widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:00 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import dialog return dialog.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/dialog/dialog.py0000644000175000017500000003127110743421035022301 0ustar stanistani# dialog.py: wxDialog objects # $Id: dialog.py,v 1.30 2007/08/07 12:18:34 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, math, misc from tree import Tree from widget_properties import * from edit_windows import TopLevelBase class EditDialog(TopLevelBase): def __init__(self, name, parent, id, title, property_window, style=wx.DEFAULT_DIALOG_STYLE, show=True, klass='wxDialog'): TopLevelBase.__init__(self, name, klass, parent, id, property_window, show=show, title=title) self.base = 'wxDialog' self.style = style prop = self.properties # style property self.access_functions['style'] = (self.get_style, self.set_style) style_labels = ('#section#' + _('Style'), 'wxDEFAULT_DIALOG_STYLE', 'wxDIALOG_MODAL', 'wxCAPTION', 'wxRESIZE_BORDER', 'wxSYSTEM_MENU') if misc.check_wx_version(2, 5): style_labels += ('wxCLOSE_BOX', 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX') style_labels += ('wxTHICK_FRAME', 'wxSTAY_ON_TOP', 'wxNO_3D', 'wxDIALOG_NO_PARENT', 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE', 'wxCLIP_CHILDREN') #note that the tooltips are only for wxPython>=2.5 self.tooltips = (_("Equivalent to a combination of wxCAPTION, wxCLOSE_BOX and wxSYSTEM_MENU (the last one is not used under Unix)"), _("NO DESCRIPTION"), _("Puts a caption on the dialog box."), _("Display a resizeable frame around the window."), _("Display a system menu."), _("Displays a close box on the frame."), _("Displays a maximize box on the dialog."), _("Displays a minimize box on the dialog."), _("Display a thick frame around the window."), _("The dialog stays on top of all other windows."), _("Under Windows, specifies that the child controls should not have 3D borders unless specified in the control."), _("By default, a dialog created with a NULL parent window will be given the application's top level window as parent. Use this style to prevent this from happening and create an orphan dialog. This is not recommended for modal dialogs."), _("NO DESCRIPTION"), _("NO DESCRIPTION"), _("NO DESCRIPTION")) self.style_pos = (wx.DEFAULT_DIALOG_STYLE, wx.DIALOG_MODAL, wx.CAPTION, wx.RESIZE_BORDER, wx.SYSTEM_MENU) if misc.check_wx_version(2, 5): self.style_pos += (wx.CLOSE_BOX, wx.MAXIMIZE_BOX, wx.MINIMIZE_BOX) self.style_pos += (wx.THICK_FRAME, wx.STAY_ON_TOP, wx.NO_3D, wx.DIALOG_NO_PARENT, wx.NO_FULL_REPAINT_ON_RESIZE, wx.FULL_REPAINT_ON_RESIZE, wx.CLIP_CHILDREN) prop['style'] = CheckListProperty(self, 'style', None, style_labels, tooltips=self.tooltips) # icon property self.icon = "" self.access_functions['icon'] = (self.get_icon, self.set_icon) prop['icon'] = FileDialogProperty(self, 'icon', None, style=wx.OPEN|wx.FILE_MUST_EXIST, can_disable=True, label=_("icon")) # centered property self.centered = False self.access_functions['centered'] = (self.get_centered, self.set_centered) prop['centered'] = CheckBoxProperty(self, 'centered', None, label=_("centered")) # size hints property self.sizehints = False self.access_functions['sizehints'] = (self.get_sizehints, self.set_sizehints) prop['sizehints'] = CheckBoxProperty(self, 'sizehints', None, label=_('Set Size Hints')) def create_widget(self): if self.parent: w = self.parent.widget else: w = common.palette # we set always a default style because this is the best one for # editing the dialog (for example, a dialog without a caption would # be hard to move, etc.) default_style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER # change 2002-10-09: now we create a wxFrame instead of a wxDialog, # because the latter gives troubles I wasn't able to solve when using # wxPython 2.3.3.1 :-/ self.widget = wx.Frame(w, self.id, "", style=default_style) self.widget.SetBackgroundColour(wx.SystemSettings_GetColour( wx.SYS_COLOUR_BTNFACE)) self.set_icon(self.icon) def finish_widget_creation(self): TopLevelBase.finish_widget_creation(self) if not self.properties['size'].is_active(): self.widget.SetSize((400, 300)) def create_properties(self): TopLevelBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) szr = wx.BoxSizer(wx.VERTICAL) self.properties['title'].display(panel) self.properties['icon'].display(panel) self.properties['centered'].display(panel) self.properties['style'].display(panel) szr.Add(self.properties['title'].panel, 0, wx.EXPAND) szr.Add(self.properties['icon'].panel, 0, wx.EXPAND) szr.Add(self.properties['centered'].panel, 0, wx.EXPAND) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') w, h = panel.GetClientSizeTuple() panel.SetScrollbars(5, 5, int(math.ceil(w/5.0)), int(math.ceil(h/5.0))) def get_style(self): retval = [0] * len(self.style_pos) style = self.style try: default = 0 if style & wx.DEFAULT_DIALOG_STYLE == wx.DEFAULT_DIALOG_STYLE: default = 1 style = style & ~wx.DEFAULT_DIALOG_STYLE for i in range(len(self.style_pos)): if style & self.style_pos[i]: retval[i] = 1 retval[0] = default except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] if self.widget: self.widget.SetWindowStyleFlag(self.style) def get_icon(self): return self.icon def set_icon(self, value): self.icon = value.strip() if self.widget: if self.icon and not (self.icon.startswith('var:') or self.icon.startswith('code:')): icon = misc.get_relative_path(self.icon) bmp = wx.Bitmap(icon, wx.BITMAP_TYPE_ANY) if not bmp.Ok(): self.set_icon("") else: icon = wx.EmptyIcon() icon.CopyFromBitmap(bmp) self.widget.SetIcon(icon) else: import os icon = wx.EmptyIcon() xpm = os.path.join(common.wxglade_path, 'icons', 'dialog.xpm') icon.CopyFromBitmap(misc.get_xpm_bitmap(xpm)) self.widget.SetIcon(icon) def get_centered(self): return self.centered def set_centered(self, value): try: self.centered = bool(int(value)) except ValueError: pass def get_sizehints(self): return self.sizehints def set_sizehints(self, value): try: self.sizehints = bool(int(value)) except ValueError: pass # end of class EditDialog def builder(parent, sizer, pos, number=[0]): """\ factory function for EditDialog objects. """ try: import panel has_panel = True except ImportError: has_panel = False class Dialog(wx.Dialog): def __init__(self): if has_panel: title = 'Select widget type' else: title = 'Select dialog class' wx.Dialog.__init__(self, None, -1, title) if common.app_tree.app.get_language().lower() == 'xrc': self.klass = 'wxDialog' else: if not number[0]: self.klass = 'MyDialog' else: self.klass = 'MyDialog%s' % number[0] number[0] += 1 self.klass_prop = TextProperty(self, 'class', None) #self) self.widget = 0 szr = wx.BoxSizer(wx.VERTICAL) if has_panel: widget_prop = RadioProperty(self, 'widget', self, ['wxDialog', 'wxPanel']) szr.Add(widget_prop.panel, 0, wx.ALL|wx.EXPAND, 5) self.klass_prop.display(self) szr.Add(self.klass_prop.panel, 0, wx.ALL|wx.EXPAND, 5) btnbox = wx.BoxSizer(wx.HORIZONTAL) btnOK = wx.Button(self, wx.ID_OK, _('OK')) btnCANCEL = wx.Button(self, wx.ID_CANCEL, _('Cancel')) btnbox.Add(btnOK, 0, wx.ALL, 3) btnbox.Add(btnCANCEL, 0, wx.ALL, 3) btnOK.SetFocus() szr.Add(btnbox, 0, wx.ALL|wx.ALIGN_CENTER, 3) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) if self.GetSize()[0] < 150: self.SetSize((150, -1)) self.klass_modified = False self.CenterOnScreen() def undo(self): if number[0] > 0: number[0] -= 1 def set_klass(self, c): self.klass = c self.klass_modified = True def set_widget(self, c): self.widget = int(c) if not self.klass_modified: try: number = str(int(self.klass[-1])) except ValueError: number = '' if common.app_tree.app.get_language().lower() == 'xrc': if self.widget == 0: self.klass = 'wxDialog' else: self.klass = 'wxPanel' else: if self.widget == 0: self.klass = 'MyDialog' + number else: self.klass = 'MyPanel' + number self.klass_prop.set_value(self.klass) def __getitem__(self, value): if value == 'class': return (lambda : self.klass, self.set_klass) else: return (lambda : self.widget, self.set_widget) # end of inner class class_dialog = Dialog() # Check if the user hit Cancel, if so then bail out if class_dialog.ShowModal() == wx.ID_CANCEL: # restore state class_dialog.undo() # clean up resources class_dialog.Destroy() return if class_dialog.widget == 0: name = 'dialog' else: name = 'panel' label = '%s_%d' % (name, (number[0] or 1)) while common.app_tree.has_name(label): number[0] += 1 label = '%s_%d' % (name, number[0]) if class_dialog.widget == 0: is_panel = False dialog = EditDialog(label, parent, wx.NewId(), label, common.property_panel, klass=class_dialog.klass) else: is_panel = True import panel dialog = panel.EditTopLevelPanel(label, parent, wx.NewId(), common.property_panel, klass=class_dialog.klass) node = Tree.Node(dialog) dialog.node = node dialog.show_widget(True) common.app_tree.add(node) class_dialog.Destroy() if wx.Platform == '__WXMSW__': if not is_panel: w = dialog.widget else: w = dialog.widget.GetParent() w.CenterOnScreen() w.Raise() def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditDialog objects from an xml file """ from xml_parse import XmlParsingError try: label = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") dialog = EditDialog(label, parent, wx.NewId(), "", common.property_panel, show=False) node = Tree.Node(dialog) dialog.node = node common.app_tree.add(node) return dialog def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ cwx = common.widgets_from_xml cwx['EditDialog'] = xml_builder common.widgets['EditDialog'] = builder return common.make_object_button('EditDialog', 'icons/dialog.xpm', 1, tip='Add a Dialog/Panel') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/codegen.py0000644000175000017500000001401110743421035024055 0ustar stanistani# codegen.py: code generator functions for CustomWidget objects # $Id: codegen.py,v 1.13 2007/08/07 12:13:43 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class ArgumentsCodeHandler: def __init__(self): self.arguments = [] self.curr_arg = [] def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): if name == 'arguments': code_obj.properties['arguments'] = self.arguments return True elif name == 'argument': tab_name = "".join(self.curr_arg) self.arguments.append(tab_name) self.curr_arg = [] return False def char_data(self, data): self.curr_arg.append(data) # end of class ArgumentsCodeHandler def _fix_arguments(arguments, parent, id, size): # Dinogen, 29 oct 2003 # adding $width e $height: vSize = size.split(',') for i in range(len(arguments)): if arguments[i] == '$parent': arguments[i] = parent elif arguments[i] == '$id': arguments[i] = id elif arguments[i] == '$width': arguments[i] = vSize[0] elif arguments[i] == '$height': arguments[i] = vSize[1] return arguments class PythonCodeGenerator: def get_code(self, widget): if widget.preview and widget.klass not in widget.parser.class_names: # if this CustomWidget refers to another class in the same wxg # file, use that for the preview #print "PREVIEW:", widget.klass, widget.parser.class_names return self.get_code_preview(widget) pygen = common.code_writers['python'] prop = widget.properties id_name, id = pygen.generate_code_id(widget) if not widget.parent.is_toplevel: parent = 'self.%s' % widget.parent.name else: parent = 'self' init = [] if id_name: init.append(id_name) arguments = _fix_arguments( prop.get('arguments', []), parent, id, prop.get('size', '-1, -1').strip()) init.append('self.%s = %s(%s)\n' % (widget.name, widget.klass, ", ".join(arguments))) props_buf = pygen.generate_common_properties(widget) return init, props_buf, [] def get_code_preview(self, widget): pygen = common.code_writers['python'] if not widget.parent.is_toplevel: parent = 'self.%s' % widget.parent.name else: parent = 'self' init = [] append = init.append append('self.%s = wx.Window(%s, -1)\n' % (widget.name, parent)) on_paint_code = """\ def self_%s_on_paint(event): widget = self.%s dc = wx.PaintDC(widget) dc.BeginDrawing() dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.BLACK_PEN) dc.SetBackground(wx.WHITE_BRUSH) dc.Clear() w, h = widget.GetClientSize() dc.DrawLine(0, 0, w, h) dc.DrawLine(w, 0, 0, h) text = 'Custom Widget: %s' tw, th = dc.GetTextExtent(text) x = (w - tw)/2 y = (h - th)/2 dc.SetPen(wx.ThePenList.FindOrCreatePen(wx.BLACK, 0, wx.TRANSPARENT)) dc.DrawRectangle(x-1, y-1, tw+2, th+2) dc.DrawText(text, x, y) dc.EndDrawing() """ % ((widget.name,) * 3) for line in on_paint_code.splitlines(): append(line + '\n') append('wx.EVT_PAINT(self.%s, self_%s_on_paint)\n' % (widget.name, widget.name)) return init, [], [] # end of class PythonCodeGenerator class CppCodeGenerator: def get_code(self, widget): cppgen = common.code_writers['C++'] prop = widget.properties id_name, id = cppgen.generate_code_id(widget) if id_name: ids = [ id_name ] else: ids = [] if not widget.parent.is_toplevel: parent = '%s' % widget.parent.name else: parent = 'this' arguments = _fix_arguments( prop.get('arguments', []), parent, id, prop.get('size', '-1, -1').strip()) init = ['%s = new %s(%s);\n' % (widget.name, widget.klass, ", ".join(arguments)) ] props_buf = cppgen.generate_common_properties(widget) return init, ids, props_buf, [] # end of class CppCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class CustomXrcObject(xrcgen.DefaultXrcObject): from xml.sax.saxutils import escape def write(self, outfile, ntabs): # first, fix the class: self.klass = obj.klass # then, the attributes: if 'arguments' in self.properties: args = self.properties['arguments'] del self.properties['arguments'] for arg in args: try: name, val = [s.strip() for s in arg.split(':', 1)] except Exception, e: print 'Exception:', e continue # silently ignore malformed arguments self.properties[name] = val xrcgen.DefaultXrcObject.write(self, outfile, ntabs) return CustomXrcObject(obj) def initialize(): common.class_names['CustomWidget'] = 'CustomWidget' # python code generation functions pygen = common.code_writers.get('python') if pygen: pygen.add_widget_handler('CustomWidget', PythonCodeGenerator()) pygen.add_property_handler('arguments', ArgumentsCodeHandler, 'CustomWidget') cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('CustomWidget', CppCodeGenerator()) cppgen.add_property_handler('arguments', ArgumentsCodeHandler, 'CustomWidget') xrcgen = common.code_writers.get('XRC') if xrcgen: xrcgen.add_widget_handler('CustomWidget', xrc_code_generator) xrcgen.add_property_handler('arguments', ArgumentsCodeHandler, 'CustomWidget') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/perl_codegen.py0000644000175000017500000000271010743421035025102 0ustar stanistani# perl_codegen.py : perl generator functions for CustomWidget objects # $Id: perl_codegen.py,v 1.4 2004/09/17 13:09:53 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import ArgumentsCodeHandler, _fix_arguments class PerlCodeGenerator: def get_code(self, widget): init = [] plgen = common.code_writers['perl'] prop = widget.properties id_name, id = plgen.generate_code_id(widget) if not widget.parent.is_toplevel: parent = '$self->{%s}' % widget.parent.name else: parent = '$self' if id_name: init.append(id_name) arguments = _fix_arguments(prop.get('arguments', []), parent, id, prop.get('size', "-1, -1")) init.append('use %s;\n' % widget.klass ) # yuck init.append('$self->{%s} = %s->new(%s);\n' % (widget.name, widget.klass, ", ".join(arguments))) props_buf = plgen.generate_common_properties(widget) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['CustomWidget'] = 'CustomWidget' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('CustomWidget', PerlCodeGenerator()) plgen.add_property_handler('arguments', ArgumentsCodeHandler, 'CustomWidget') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/lisp_codegen.py0000644000175000017500000000271410743421035025113 0ustar stanistani# perl_codegen.py : perl generator functions for CustomWidget objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:59:00 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from codegen import ArgumentsCodeHandler, _fix_arguments class PerlCodeGenerator: def get_code(self, widget): init = [] plgen = common.code_writers['perl'] prop = widget.properties id_name, id = plgen.generate_code_id(widget) if not widget.parent.is_toplevel: parent = '(object-%s self)' % widget.parent.name else: parent = 'nil' if id_name: init.append(id_name) arguments = _fix_arguments(prop.get('arguments', []), parent, id, prop.get('size', "-1, -1")) init.append('use %s;\n' % widget.klass ) # yuck init.append('$self->{%s} = %s->new(%s);\n' % (widget.name, widget.klass, ", ".join(arguments))) props_buf = plgen.generate_common_properties(widget) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['CustomWidget'] = 'CustomWidget' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('CustomWidget', PerlCodeGenerator()) plgen.add_property_handler('arguments', ArgumentsCodeHandler, 'CustomWidget') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/__init__.py0000644000175000017500000000066210743421035024217 0ustar stanistani# __init__.py: custom widget module initialization # $Id: __init__.py,v 1.7 2007/03/27 07:02:01 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import custom_widget return custom_widget.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/custom_widget/custom_widget.py0000644000175000017500000001725610743421035025344 0ustar stanistani# custom_widget.py: custom wxWindow objects # $Id: custom_widget.py,v 1.21 2007/08/07 12:13:43 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from tree import Tree from widget_properties import * from edit_windows import ManagedBase class ArgumentsProperty(GridProperty): def write(self, outfile, tabs): from xml.sax.saxutils import escape if self.getter: values = self.getter() else: values = self.owner[self.name][0]() if values: write = outfile.write write(' ' * tabs + '\n') stab = ' ' * (tabs+1) for value in values: write('%s%s\n' % (stab, escape(value[0]))) write(' ' * tabs + '\n') # end of class ArgumentsProperty class ArgumentsHandler: def __init__(self, parent): self.parent = parent self.arguments = [] self.curr_arg = [] def start_elem(self, name, attrs): pass def end_elem(self, name): if name == 'arguments': self.parent.arguments = self.arguments self.parent.properties['arguments'].set_value(self.arguments) return True elif name == 'argument': self.arguments.append(["".join(self.curr_arg)]) self.curr_arg = [] return False def char_data(self, data): self.curr_arg.append(data) # end of class ArgumentsHandler class CustomWidget(ManagedBase): def __init__(self, name, klass, parent, id, sizer, pos, property_window, show=True): ManagedBase.__init__(self, name, klass, parent, id, sizer, pos, property_window, show) self.arguments = [['$parent'], ['$id']] #,['$width'],['$height']] self.access_functions['arguments'] = (self.get_arguments, self.set_arguments) cols = [('Arguments', GridProperty.STRING)] self.properties['arguments'] = ArgumentsProperty(self, 'arguments', None, cols, 2, label=_("arguments")) def set_klass(self, value): ManagedBase.set_klass(self, value) if self.widget: self.widget.Refresh() def create_widget(self): self.widget = wx.Window(self.parent.widget, self.id, style=wx.SUNKEN_BORDER|wx.FULL_REPAINT_ON_RESIZE) wx.EVT_PAINT(self.widget, self.on_paint) def finish_widget_creation(self): ManagedBase.finish_widget_creation(self, sel_marker_parent=self.widget) def on_paint(self, event): dc = wx.PaintDC(self.widget) dc.BeginDrawing() dc.SetBrush(wx.WHITE_BRUSH) dc.SetPen(wx.BLACK_PEN) dc.SetBackground(wx.WHITE_BRUSH) dc.Clear() w, h = self.widget.GetClientSize() dc.DrawLine(0, 0, w, h) dc.DrawLine(w, 0, 0, h) text = _('Custom Widget: %s') % self.klass tw, th = dc.GetTextExtent(text) x = (w - tw)/2 y = (h - th)/2 dc.SetPen(wx.ThePenList.FindOrCreatePen(wx.BLACK, 0, wx.TRANSPARENT)) dc.DrawRectangle(x-1, y-1, tw+2, th+2) dc.DrawText(text, x, y) dc.EndDrawing() def create_properties(self): ManagedBase.create_properties(self) panel = wx.ScrolledWindow(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) args = self.properties['arguments'] args.display(panel) szr.Add(args.panel, 1, wx.ALL|wx.EXPAND, 5) help_btn = wx.Button(panel, -1, _('Help on "Arguments" property')) text = _("""\ The 'Arguments' property behaves differently when generating XRC code wrt C++ or python: you can use it to add custom attributes to the resource object. To do so, arguments must have the following format: ATTRIBUTE_NAME: ATTRIBUTE_VALUE For instance: default_value: 10 is translated to: 10 Invalid entries are silently ignored""") def show_help(event): wx.MessageBox(text, _('Help on "Arguments" property'), wx.OK|wx.CENTRE|wx.ICON_INFORMATION) wx.EVT_BUTTON(help_btn, -1, show_help) szr.Add(help_btn, 0, wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') args.set_col_sizes([-1]) def get_arguments(self): return self.arguments def set_arguments(self, value): self.arguments = [[misc.wxstr(v) for v in val] for val in value] def get_property_handler(self, name): if name == 'arguments': return ArgumentsHandler(self) return ManagedBase.get_property_handler(self, name) # end of class CustomWidget def builder(parent, sizer, pos, number=[1]): """\ factory function for CustomWidget objects. """ class Dialog(wx.Dialog): def __init__(self, number=[0]): title = _('Select widget class') wx.Dialog.__init__(self, None, -1, title) self.klass = 'CustomWidget' if number[0]: self.klass = 'CustomWidget%s' % (number[0]-1) number[0] += 1 klass_prop = TextProperty(self, 'class', self, label=_("class")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(klass_prop.panel, 0, wx.ALL|wx.EXPAND, 5) szr.Add(wx.Button(self, wx.ID_OK, _('OK')), 0, wx.ALL|wx.ALIGN_CENTER, 5) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) w = self.GetTextExtent(title)[0] + 50 if self.GetSize()[0] < w: self.SetSize((w, -1)) self.CenterOnScreen() def __getitem__(self, value): def set_klass(c): self.klass = c return (lambda : self.klass, set_klass) # end of inner class dialog = Dialog() dialog.ShowModal() name = 'window_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'window_%d' % number[0] win = CustomWidget(name, dialog.klass, parent, wx.NewId(), sizer, pos, common.property_panel) node = Tree.Node(win) win.node = node win.set_option(1) win.set_flag("wxEXPAND") win.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) sizer.set_item(win.pos, 1, wx.EXPAND) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build CustomWidget objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if not sizer or not sizeritem: raise XmlParsingError, _("sizer or sizeritem object cannot be None") win = CustomWidget(name, 'CustomWidget', parent, wx.NewId(), sizer, pos, common.property_panel, True) sizer.set_item(win.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(win) win.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return win def initialize(): """\ initialization function for the module: returns a wx.BitmapButton to be added to the main palette. """ common.widgets['CustomWidget'] = builder common.widgets_from_xml['CustomWidget'] = xml_builder return common.make_object_button('CustomWidget', 'icons/custom.xpm', tip='Add a custom widget') spe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/codegen.py0000644000175000017500000001007710743421035023157 0ustar stanistani# codegen.py: code generator functions for wxComboBox objects # $Id: codegen.py,v 1.15 2007/03/27 07:02:02 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PythonCodeGenerator: def get_code(self, obj): pygen = common.code_writers['python'] prop = obj.properties id_name, id = pygen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' style = prop.get("style", None) if not style: style = pygen.cn('wxCB_DROPDOWN') else: style = pygen.cn_f('wxCB_DROPDOWN|' + style) init = [] if id_name: init.append(id_name) choices = ', '.join([pygen.quote_str(c) for c in choices]) klass = obj.klass if klass == obj.base: klass = pygen.cn(klass) init.append('self.%s = %s(%s, %s, choices=[%s], style=%s)\n' % (obj.name, klass, parent, id, choices, style)) props_buf = pygen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and len(prop.get('choices', [])): props_buf.append('self.%s.SetSelection(%s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class PythonCodeGenerator def xrc_code_generator(obj): xrcgen = common.code_writers['XRC'] class ComboBoxXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if name == 'choices': xrc_write_choices_property(self, outfile, tabs) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class ComboBoxXrcObject return ComboBoxXrcObject(obj) class CppCodeGenerator: def get_code(self, obj): """\ generates the C++ code for wxComboBox objects """ cppgen = common.code_writers['C++'] prop = obj.properties id_name, id = cppgen.generate_code_id(obj) if id_name: ids = [ id_name ] else: ids = [] choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' number = len(choices) ch_arr = '{\n %s\n };\n' % \ ',\n '.join([cppgen.quote_str(c) for c in choices]) style = prop.get("style") if not style: style = 'wxCB_DROPDOWN' else: style = 'wxCB_DROPDOWN|' + style init = [] if number: init.append('const wxString %s_choices[] = %s' % (obj.name, ch_arr)) else: init.append('const wxString *%s_choices = NULL;\n' % obj.name) init.append('%s = new %s(%s, %s, wxT(""), wxDefaultPosition, ' 'wxDefaultSize, %s, %s_choices, %s);\n' % \ (obj.name, obj.klass, parent, id, number, obj.name, style)) props_buf = cppgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None and len(prop.get('choices', [])): props_buf.append('%s->SetSelection(%s);\n' % (obj.name, selection)) return init, ids, props_buf, [] # end of class CppCodeGenerator def initialize(): common.class_names['EditComboBox'] = 'wxComboBox' pygen = common.code_writers.get("python") if pygen: pygen.add_widget_handler('wxComboBox', PythonCodeGenerator()) pygen.add_property_handler('choices', ChoicesCodeHandler) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxComboBox', xrc_code_generator) xrcgen.add_property_handler('choices', ChoicesCodeHandler) cppgen = common.code_writers.get('C++') if cppgen: cppgen.add_widget_handler('wxComboBox', CppCodeGenerator()) cppgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/perl_codegen.py0000644000175000017500000000351210743421035024175 0ustar stanistani# perl_codegen.py : perl generator functions for wxComboBox objects # $Id: perl_codegen.py,v 1.4 2005/08/15 07:36:35 crazyinsomniac Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class PerlCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['perl'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' style = prop.get("style", None) if not style: style = 'wxCB_DROPDOWN' else: style = 'wxCB_DROPDOWN|' + style if id_name: init.append(id_name) choices = ', '.join([plgen.quote_str(c) for c in choices]) klass = obj.base; if klass != obj.klass : klass = obj.klass; else: klass = klass.replace('wx','Wx::',1); init.append('$self->{%s} = %s->new(%s, %s, "", wxDefaultPosition, \ wxDefaultSize, [%s], %s);\n' % (obj.name, klass, parent, id, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('$self->{%s}->SetSelection(%s);\n' % (obj.name, selection)) return init, props_buf, [] # end of class PerlCodeGenerator def initialize(): common.class_names['EditComboBox'] = 'wxComboBox' plgen = common.code_writers.get('perl') if plgen: plgen.add_widget_handler('wxComboBox', PerlCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/lisp_codegen.py0000644000175000017500000000353210743421035024204 0ustar stanistani# lisp_codegen.py : lisp generator functions for wxComboBox objects # $Id: lisp_codegen.py,v 1.1 2005/09/22 06:58:36 efuzzyone Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common from ChoicesCodeHandler import * class LispCodeGenerator: def get_code(self, obj): init = [] plgen = common.code_writers['lisp'] prop = obj.properties id_name, id = plgen.generate_code_id(obj) choices = prop.get('choices', []) if not obj.parent.is_toplevel: parent = '(object-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' style = prop.get("style", None) if not style: style = 'wxCB_DROPDOWN' else: style = style.strip().replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if id_name: init.append(id_name) length = len(choices) choices = ', '.join([plgen.quote_str(c) for c in choices]) init.append('(setf (slot-%s obj) (wxComboBox_Create %s %s "" -1 -1 -1 -1 %s (vector %s) %s))\n' % (obj.name, parent, id, length, choices, style)) props_buf = plgen.generate_common_properties(obj) selection = prop.get('selection') if selection is not None: props_buf.append('(wxComboBox_SetSelection (slot-%s obj) %s)\n' % (obj.name, selection)) return init, props_buf, [] # end of class LispCodeGenerator def initialize(): common.class_names['EditComboBox'] = 'wxComboBox' plgen = common.code_writers.get('lisp') if plgen: plgen.add_widget_handler('wxComboBox', LispCodeGenerator()) plgen.add_property_handler('choices', ChoicesCodeHandler) spe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/__init__.py0000644000175000017500000000065510743421035023313 0ustar stanistani# __init__.py: combo box widget module initialization # $Id: __init__.py,v 1.8 2007/03/27 07:02:02 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def initialize(): import common import codegen codegen.initialize() if common.use_gui: import combo_box return combo_box.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/widgets/combo_box/combo_box.py0000644000175000017500000001770510743421035023527 0ustar stanistani# combo_box.py: wxComboBox objects # $Id: combo_box.py,v 1.28 2007/03/27 07:02:02 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx import common, misc from edit_windows import ManagedBase from tree import Tree from widget_properties import * from ChoicesProperty import * if wx.Platform == '__WXMSW__': # why on Windows combo boxes give segfaults? Need to investigate, but # for now replace them with choices # this seems to be because of the style of wxPanel: if there's a # wxTAB_TRAVERSAL, we have troubles -- now it should be fixed... class wxComboBox2(wx.ComboBox): # on windows GetBestSize considers also the drop down menu, while we # don't want it to be included def GetBestSize(self): w, h = wx.ComboBox.GetBestSize(self) n = self.GetCount() return w, h/(n+1) def GetSize(self): return self.GetClientSize() else: wxComboBox2 = wx.ComboBox class EditComboBox(ManagedBase): events = ['EVT_COMBOBOX', 'EVT_TEXT', 'EVT_TEXT_ENTER'] def __init__(self, name, parent, id, choices, sizer, pos, property_window, show=True): """\ Class to handle wxComboBox objects """ import config ManagedBase.__init__(self, name, 'wxComboBox', parent, id, sizer, pos, property_window, show=show) self.choices = choices if len(choices): self.selection = 0 else: self.selection = -1 self.style = 0 # properties self.access_functions['choices'] = (self.get_choices, self.set_choices) self.access_functions['style'] = (self.get_style, self.set_style) style_labels = ('#section#' + _('Style'), 'wxCB_SIMPLE','wxCB_DROPDOWN', 'wxCB_READONLY', 'wxCB_SORT') self.style_pos = [ eval('wx.' + s[2:]) for s in style_labels[1:] ] self.tooltips = (_("Creates a combobox with a permanently displayed list." " Windows only."), _("Creates a combobox with a drop-down list."), _("Same as wxCB_DROPDOWN but only the strings specified " "as the combobox choices can be selected, it is " "impossible to select (even from a program) a string " "which is not in the choices list."), _("Sorts the entries in the list alphabetically.")) self.properties['style'] = CheckListProperty(self, 'style', None, style_labels, tooltips=self.tooltips) self.properties['choices'] = ChoicesProperty(self, 'choices', None, [('Label', GridProperty.STRING)], len(choices), label=_("choices")) self.access_functions['selection'] = (self.get_selection, self.set_selection) self.choices = list(choices) self.properties['selection'] = SpinProperty(self, 'selection', None, r=(0, len(choices)-1), label=_("selection")) # 2003-09-04 added default_border if config.preferences.default_border: self.border = config.preferences.default_border_size self.flag = wx.ALL def create_widget(self): self.widget = wxComboBox2(self.parent.widget, self.id, choices=self.choices) self.set_selection(self.selection) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) def create_properties(self): ManagedBase.create_properties(self) panel = wx.Panel(self.notebook, -1) szr = wx.BoxSizer(wx.VERTICAL) self.properties['choices'].display(panel) self.properties['style'].display(panel) self.properties['selection'].display(panel) szr.Add(self.properties['style'].panel, 0, wx.EXPAND) szr.Add(self.properties['selection'].panel, 0, wx.EXPAND) szr.Add(self.properties['choices'].panel, 1, wx.EXPAND) panel.SetAutoLayout(True) panel.SetSizer(szr) szr.Fit(panel) self.notebook.AddPage(panel, 'Widget') self.properties['choices'].set_col_sizes([-1]) def get_selection(self): return self.selection def set_selection(self, value): value = int(value) if self.selection != value: self.selection = value if self.widget: self.widget.SetSelection(value) def get_choices(self): return zip(self.choices) def set_choices(self, values): self.choices = [ misc.wxstr(v[0]) for v in values ] self.properties['selection'].set_range(0, len(self.choices)-1) if self.widget: self.widget.Clear() for c in self.choices: self.widget.Append(c) if not self.properties['size'].is_active(): self.sizer.set_item(self.pos, size=self.widget.GetBestSize()) def get_style(self): retval = [0] * len(self.style_pos) try: for i in range(len(self.style_pos)): if self.style & self.style_pos[i]: retval[i] = 1 except AttributeError: pass return retval def set_style(self, value): value = self.properties['style'].prepare_value(value) self.style = 0 for v in range(len(value)): if value[v]: self.style |= self.style_pos[v] ## if self.widget: ## self.SetWindowStyleFlag(style) def create_widget(self): self.widget = wxComboBox2(self.parent.widget, self.id, choices=self.choices) wx.EVT_LEFT_DOWN(self.widget, self.on_set_focus) def get_property_handler(self, prop_name): if prop_name == 'choices': return ChoicesHandler(self) return ManagedBase.get_property_handler(self, prop_name) # end of class EditComboBox def builder(parent, sizer, pos, number=[1]): """\ factory function for EditComboBox objects. """ name = 'combo_box_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'combo_box_%d' % number[0] choice = EditComboBox(name, parent, wx.NewId(), #[misc._encode('choice 1')], [], sizer, pos, common.property_panel) node = Tree.Node(choice) # sizer.set_item(pos, size=choice.GetBestSize()) choice.node = node choice.show_widget(True) common.app_tree.insert(node, sizer.node, pos-1) def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory to build EditComboBox objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if sizer is None or sizeritem is None: raise XmlParsingError, _("sizer or sizeritem object cannot be None") choice = EditComboBox(name, parent, wx.NewId(), [], sizer, pos, common.property_panel) sizer.set_item(choice.pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) ## size=choice.GetBestSize()) node = Tree.Node(choice) choice.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) return choice def initialize(): """\ initialization function for the module: returns a wxBitmapButton to be added to the main palette. """ common.widgets['EditComboBox'] = builder common.widgets_from_xml['EditComboBox'] = xml_builder return common.make_object_button('EditComboBox', 'icons/combo_box.xpm') spe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/lisp_sizers_codegen.py0000644000175000017500000001176510743421035024521 0ustar stanistani# lisp_sizers_codegen.py : lisp generator functions for the various wxSizerS # $Id: lisp_sizers_codegen.py,v 1.2 2006/12/02 11:20:29 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # import common class LispBoxSizerBuilder: def get_code(self, obj): orient = obj.properties.get('orient', 'wxHORIZONTAL') init = [ '(setf (slot-%s obj) (wxBoxSizer_Create %s))\n' % (obj.name, orient) ] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-top-window obj)' #layout.append('(wxWindow_SetAutoLayout %s 1)\n' % parent) layout.append('(wxWindow_SetSizer %s (slot-%s obj))\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('(wxSizer_Fit (slot-%s obj) %s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('(wxSizer_SetSizeHints (slot-%s obj) %s)\n' % (obj.name, parent)) return init, [], layout # end of class LispBoxSizerBuilder class LispStaticBoxSizerBuilder: def get_code(self, obj): plgen = common.code_writers['lisp'] orient = obj.properties.get('orient', 'wxHORIZONTAL') label = obj.properties.get('label', '') if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-frame obj)' init = [ '(setf (slot-%s obj) (StaticBoxSizer_Create (wxStaticBox:wxStaticBox_Create %s %s) %s))\n' % (obj.name, parent, plgen.quote_str(label), orient) ] layout = [] if obj.is_toplevel: #layout.append('(wxWindow_SetAutoLayout %s 1)\n' % parent) layout.append('(wxWindow_SetSizer %s (slot-%s obj))\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('(wxSizer_Fit (slot-%s obj) %s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('(wxSizer_SetSizeHints (slot-%s obj) %s)\n' % (obj.name, parent)) return init, [], layout # end of class LispStaticBoxSizerBuilder class LispGridSizerBuilder: klass = 'Wx::GridSizer' def get_code(self, obj): props = obj.properties if not obj.parent.is_toplevel: parent = '(slot-%s obj)' % obj.parent.name else: parent = '(slot-frame obj)' rows = props.get('rows', '0') cols = props.get('cols', '0') vgap = props.get('vgap', '0') hgap = props.get('hgap', '0') init = [ '(setf (slot-%s obj) (wxGridSizer_Create %s %s %s %s))\n' % (obj.name, rows, cols, vgap, hgap) ] layout = [] if obj.is_toplevel: #layout.append('(wxWindow_SetAutoLayout %s 1)\n' % parent) layout.append('(wxWindow_SetSizer %s (slot-%s obj))\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('(wxSizer_Fit (slot-%s obj) %s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('(wxSizer_SetSizeHints (slot-%s obj) %s)\n' % (obj.name, parent)) return init, [], layout # end of class LispGridSizerBuilder class LispFlexGridSizerBuilder(LispGridSizerBuilder): klass = 'Wx::FlexGridSizer' def get_code(self, obj): init, p, layout = LispGridSizerBuilder.get_code(self, obj) props = obj.properties if props.has_key('growable_rows'): for r in props['growable_rows'].split(','): layout.append('(wxFlexGridSizer_AddGrowableRow (slot-%s obj) %s)\n' % (obj.name, r.strip())) if props.has_key('growable_cols'): for r in props['growable_cols'].split(','): layout.append('(wxFlexGridSizer_AddGrowableCol (slot-%s obj) %s)\n' % (obj.name, r.strip())) return init, p, layout # end of class LispFlexGridSizerBuilder def initialize(): cn = common.class_names cn['EditBoxSizer'] = 'wxBoxSizer' cn['EditStaticBoxSizer'] = 'wxStaticBoxSizer' cn['EditGridSizer'] = 'wxGridSizer' cn['EditFlexGridSizer'] = 'wxFlexGridSizer' plgen = common.code_writers.get("lisp") if plgen: awh = plgen.add_widget_handler awh('wxBoxSizer', LispBoxSizerBuilder()) awh('wxStaticBoxSizer', LispStaticBoxSizerBuilder()) awh('wxGridSizer', LispGridSizerBuilder()) awh('wxFlexGridSizer', LispFlexGridSizerBuilder()) spe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/edit_sizers.py0000644000175000017500000025464110743421035023015 0ustar stanistani# edit_sizers.py: hierarchy of Sizers supported by wxGlade # $Id: edit_sizers.py,v 1.80 2007/08/07 12:21:55 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import wx from widget_properties import * from tree import Tree, WidgetTree import common, config, misc import math, sys, re class SizerSlot: "a window to represent a slot in a sizer" def __init__(self, parent, sizer, pos=0): self.widget = None # reference to the widget resembling the slot self.sizer = sizer self.parent = parent self.pos = pos self.menu = None def create_widget(self): if misc.check_wx_version(2, 5, 2): style = wx.FULL_REPAINT_ON_RESIZE else: style = 0 self.widget = wx.Window(self.parent.widget, -1, size=(20, 20), style=style) self.widget.SetBackgroundColour(wx.LIGHT_GREY) self.widget.SetAutoLayout(True) wx.EVT_PAINT(self.widget, self.on_paint) wx.EVT_RIGHT_DOWN(self.widget, self.popup_menu) wx.EVT_LEFT_DOWN(self.widget, self.drop_widget) wx.EVT_MIDDLE_DOWN(self.widget, self.select_and_paste) wx.EVT_ENTER_WINDOW(self.widget, self.on_enter) wx.EVT_LEAVE_WINDOW(self.widget, self.on_leave) def on_key_down(event): evt_flags = 0 if event.ControlDown(): evt_flags = wx.ACCEL_CTRL evt_key = event.GetKeyCode() for flags, key, function in misc.accel_table: if evt_flags == flags and evt_key == key: misc.wxCallAfter(function) break #event.Skip() wx.EVT_KEY_DOWN(self.widget, on_key_down) def show_widget(self, yes): if yes and not self.widget: self.create_widget() if self.widget: self.widget.Show(yes) def on_enter(self, event): # hack. definitely. but... misc._currently_under_mouse = self.widget if common.adding_widget and \ (not common.adding_sizer or not self.sizer.is_virtual()): self.widget.SetCursor(wx.CROSS_CURSOR) else: self.widget.SetCursor(wx.STANDARD_CURSOR) event.Skip() def on_leave(self, event): # _currently_under_mouse is used to restore the normal cursor, if the # user cancelled the addition of a widget and the cursor is over this # slot misc._currently_under_mouse = None event.Skip() def on_paint(self, event): dc = wx.PaintDC(self.widget) dc.BeginDrawing() dc.SetBrush(wx.Brush("black", wx.FDIAGONAL_HATCH)) dc.SetPen(wx.BLACK_PEN) w, h = self.widget.GetClientSize() dc.DrawRectangle(0, 0, w, h) dc.EndDrawing() def on_size(self, event): self.widget.Refresh() def popup_menu(self, event): if not self.menu: self.menu = wx.Menu(_('Options')) REMOVE_ID, PASTE_ID = wx.NewId(), wx.NewId() if not self.sizer.is_virtual(): # we cannot remove items from virtual sizers misc.append_item(self.menu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) misc.append_item(self.menu, PASTE_ID, _('Paste\tCtrl+V'), wx.ART_PASTE) def bind(method): return lambda e: misc.wxCallAfter(method) wx.EVT_MENU(self.widget, REMOVE_ID, bind(self.remove)) wx.EVT_MENU(self.widget, PASTE_ID, bind(self.clipboard_paste)) PREVIEW_ID = wx.NewId() self.menu.AppendSeparator() misc.append_item(self.menu, PREVIEW_ID, _('Preview')) wx.EVT_MENU(self.widget, PREVIEW_ID, bind(self.preview_parent)) self.setup_preview_menu() self.widget.PopupMenu(self.menu, event.GetPosition()) def remove(self, *args): if not self.sizer.is_virtual(): self.sizer.remove_item(self) self.delete() def drop_widget(self, event): """\ replaces self with a widget in self.sizer. This method is called to add every non-toplevel widget or sizer, and in turn calls the appropriate builder function (found in the ``common.widgets'' dict) """ if not common.adding_widget: misc.focused_widget = self self.widget.SetFocus() return if common.adding_sizer and self.sizer.is_virtual(): return common.adding_widget = False common.adding_sizer = False self.widget.SetCursor(wx.NullCursor) # call the appropriate builder common.widgets[common.widget_to_add](self.parent, self.sizer, self.pos) common.widget_to_add = None common.app_tree.app.saved = False # update the status of the app def clipboard_paste(self, *args): import clipboard if clipboard.paste(self.parent, self.sizer, self.pos): common.app_tree.app.saved = False # update the status of the app #print misc.focused_widget def select_and_paste(self, *args): """\ Middle-click event handler: selects the slot and, if the clipboard is not empty, pastes its content here """ misc.focused_widget = self self.widget.SetFocus() self.clipboard_paste() def delete(self, delete_widget=True): if self.menu: self.menu.Destroy() if misc._currently_under_mouse is self.widget: misc._currently_under_mouse = None if delete_widget and self.widget: self.widget.Destroy() if misc.focused_widget is self: misc.focused_widget = None common.app_tree.app.saved = False # update the status of the app def update_pos(self, value): """\ called by self.sizer.change_item_pos to update the item's position when another widget is moved """ self.pos = value def setup_preview_menu(self): p = misc.get_toplevel_widget(self.sizer) if p is not None: item = list(self.menu.GetMenuItems())[-1] if p.preview_is_visible(): item.SetText(_('Close preview') + ' (%s)\tCtrl+P' % p.name) else: item.SetText(_('Preview') + ' (%s)\tCtrl+P' % p.name) def preview_parent(self): p = misc.get_toplevel_widget(self.sizer) if p is not None: p.preview(None) # end of class SizerSlot if 0: #wxPlatform != '__WXMAC__': Button = wx.Button else: #from wxPython.lib.buttons import wxGenButton as Button from wx.lib.buttons import GenButton as Button class SizerHandleButton(Button): """\ Provides a ``handle'' to activate a Sizer and to access its popup menu """ def __init__(self, parent, id, sizer, menu): # menu: list of 2-tuples: (label, function) Button.__init__(self, parent.widget, id, '', size=(5, 5)) self.sizer = sizer self.menu = menu self._rmenu = None try: self.SetUseFocusIndicator(False) except AttributeError: pass ## # provide popup menu for removal ## REMOVE_ID = wxNewId() ## self._rmenu = misc.wxGladePopupMenu(sizer.name) ## #self._rmenu.Append(REMOVE_ID, 'Remove\tDel') ## misc.append_item(self._rmenu, REMOVE_ID, 'Remove\tDel', 'remove.xpm') ## EVT_MENU(self, REMOVE_ID, self._remove) ## for item in menu: ## id = wxNewId() ## #self._rmenu.Append(id, item[0]) ## bmp = None ## if len(item) > 2: bmp = item[2] ## misc.append_item(self._rmenu, id, item[0], bmp) ## EVT_MENU(self, id, item[1]) ## self.sizer._rmenu = self._rmenu wx.EVT_RIGHT_DOWN(self, self.popup_menu) ## def remove(): ## if common.focused_widget is not None: ## common.focused_widget.remove() ## table = [(0, WXK_DELETE, remove)] def on_key_down(event): evt_flags = 0 if event.ControlDown(): evt_flags = wx.ACCEL_CTRL evt_key = event.GetKeyCode() for flags, key, function in misc.accel_table: if evt_flags == flags and evt_key == key: misc.wxCallAfter(function) break #event.Skip() wx.EVT_KEY_DOWN(self, on_key_down) def on_set_focus(event): misc.focused_widget = self event.Skip() wx.EVT_SET_FOCUS(self, on_set_focus) def set_menu_title(self, title): if self._rmenu: self._rmenu.SetTitle(title) def popup_menu(self, event): if not self._rmenu: # provide popup menu for removal REMOVE_ID = wx.NewId() self._rmenu = misc.wxGladePopupMenu(self.sizer.name) def bind(method): return lambda e: misc.wxCallAfter(method) #self._rmenu.Append(REMOVE_ID, 'Remove\tDel') misc.append_item(self._rmenu, REMOVE_ID, _('Remove\tDel'), wx.ART_DELETE) wx.EVT_MENU(self, REMOVE_ID, bind(self._remove)) for item in self.menu: id = wx.NewId() #self._rmenu.Append(id, item[0]) bmp = None if len(item) > 2: bmp = item[2] misc.append_item(self._rmenu, id, item[0], bmp) wx.EVT_MENU(self, id, bind(item[1])) self._rmenu.AppendSeparator() PREVIEW_ID = wx.NewId() misc.append_item(self._rmenu, PREVIEW_ID, _('Preview')) wx.EVT_MENU(self, PREVIEW_ID, bind(self.preview_parent)) self.sizer._rmenu = self._rmenu del self.menu self.setup_preview_menu() self.PopupMenu(self._rmenu, event.GetPosition()) def _remove(self, *args): # removes the sizer from his parent, if it has one if self.sizer.toplevel: window = self.sizer.window common.app_tree.remove(self.sizer.node) window.set_sizer(None) return self.sizer.sizer.free_slot(self.sizer.pos) common.app_tree.remove(self.sizer.node) # needed for consistency (common.focused_widget.remove) remove = _remove def Destroy(self): if self._rmenu: self._rmenu.Destroy() Button.Destroy(self) if misc.focused_widget is self: misc.focused_widget = None def setup_preview_menu(self): p = misc.get_toplevel_widget(self.sizer) if p is not None: item = list(self._rmenu.GetMenuItems())[-1] if p.preview_is_visible(): item.SetText(_('Close preview') + ' (%s)\tCtrl+P' % p.name) else: item.SetText(_('Preview') + ' (%s)\tCtrl+P' % p.name) def preview_parent(self): p = misc.get_toplevel_widget(self.sizer) p.preview(None) # end of class SizerHandleButton class SizerItem: """\ Represents a child of a sizer """ def __init__(self, item, pos, option=0, flag=0, border=0, size=None): self.item = item self.item.pos = pos self.option = option self.flag = flag self.border = border self.size = size # end of class SizerItem #---------- 2002-10-07 -------------------------------------------------------- class SizerClassDialog: choices = [ ('EditBoxSizerV', 'wxBoxSizer (wxVERTICAL)'), ('EditBoxSizerH', 'wxBoxSizer (wxHORIZONTAL)'), ('EditStaticBoxSizerV', 'wxStaticBoxSizer (wxVERTICAL)'), ('EditStaticBoxSizerH', 'wxStaticBoxSizer (wxHORIZONTAL)'), ('EditGridSizer', 'wxGridSizer'), ('EditFlexGridSizer', 'wxFlexGridSizer') ] def __init__(self, owner, parent): self.owner = owner self.parent = parent self.dialog = None def ShowModal(self): name = self.owner.__class__.__name__ if hasattr(self.owner, 'orient'): if self.owner.orient == wx.HORIZONTAL: name += 'H' else: name += 'V' choices = [ b for a, b in self.choices if a != name ] self.dialog = wx.SingleChoiceDialog(self.parent, _("Select sizer type"), _("Select sizer type"), choices) self.dialog.CenterOnScreen() return self.dialog.ShowModal() def get_value(self): return self.dialog.GetStringSelection() # end of class SizerClassDialog def change_sizer(old, new, which_page=0, _hidden=[None]): """\ changes 'old' sizer to 'new' Params: - old: SizerBase instance to replace - new: string selection that identifies the new instance - which_page: index of the notebook page of the property window to display: this is used only by set_growable_(rows|cols) """ constructors = { 'wxBoxSizer (wxVERTICAL)': lambda : EditBoxSizer(old.name, old.window, wx.VERTICAL, 0, old.toplevel), 'wxBoxSizer (wxHORIZONTAL)': lambda : EditBoxSizer(old.name, old.window, wx.HORIZONTAL, 0, old.toplevel), 'wxStaticBoxSizer (wxVERTICAL)': lambda : EditStaticBoxSizer(old.name, old.window, wx.VERTICAL, getattr(old, 'label', old.name), 0, old.toplevel), 'wxStaticBoxSizer (wxHORIZONTAL)': lambda : EditStaticBoxSizer(old.name, old.window, wx.HORIZONTAL, getattr(old, 'label', old.name), 0, old.toplevel), 'wxGridSizer': lambda : EditGridSizer(old.name, old.window, rows=0, cols=0, toplevel=old.toplevel), 'wxFlexGridSizer': lambda : EditFlexGridSizer(old.name, old.window, rows=0, cols=0, toplevel=old.toplevel) } szr = constructors[new]() szr.children.extend(old.children[1:]) szr.node = old.node if isinstance(szr, GridSizerBase): szr.set_rows(getattr(old, 'rows', 1)) szr.set_cols(getattr(old, 'cols', len(szr.children)-1)) szr.set_hgap(getattr(old, 'hgap', 0)) szr.set_vgap(getattr(old, 'vgap', 0)) if isinstance(szr, EditFlexGridSizer): try: grow_r = old.grow_rows grow_c = old.grow_cols if grow_r: szr.grow_rows = grow_r szr.properties['growable_rows'].toggle_active(True) szr.properties['growable_rows'].set_value( szr.get_growable_rows()) if grow_c: szr.grow_cols = grow_c szr.properties['growable_cols'].toggle_active(True) szr.properties['growable_cols'].set_value( szr.get_growable_cols()) except (AttributeError, KeyError): pass szr.show_widget(True, dont_set=True) if _hidden[0] is None: _hidden[0] = wx.Frame(None, -1, _("HIDDEN FRAME FOR CHANGE SIZER")) for c in szr.children[1:]: widget = c.item widget.sizer = szr if not isinstance(widget, SizerSlot): # ALB 2007-09-04. This is necessary as a workaround to a # wx.StaticBoxSizer issue: it seems that the wx.StaticBox needs to # come before any other widget managed by the wx.StaticBoxSizer in # the GetChildren() list. Explicitly reparenting the widgets seems # to solve the problem p = widget.widget.GetParent() widget.widget.Reparent(_hidden[0]) widget.widget.Reparent(p) szr.widget.Insert(widget.pos, widget.widget, int(widget.get_option()), widget.get_int_flag(), int(widget.get_border())) if not szr.toplevel: szr.sizer = old.sizer szr.option = old.option szr.flag = old.flag szr.border = old.border szr.pos = old.pos szr.sizer.children[szr.pos].item = szr if szr.sizer.widget: elem = szr.sizer.widget.GetChildren()[szr.pos] elem.SetSizer(szr.widget) import common common.app_tree.change_node(szr.node, szr) old.toplevel = False szr.show_properties() szr.notebook.SetSelection(which_page) for c in old.widget.GetChildren(): if c and c.IsSizer(): c.SetSizer(None) old.widget.Clear() old.children = old.children[:1] old.delete() if szr.toplevel: szr.window.set_sizer(szr) szr.layout(True) #------------------------------------------------------------------------------ class InsertDialog(wx.Dialog): def __init__(self, max_val): wx.Dialog.__init__(self, None, -1, _("Select a position")) self.pos = 0 pos_prop = SpinProperty(self, 'position', self, r=(0, max_val), label=_("position")) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(pos_prop.panel, 0, wx.ALL|wx.EXPAND, 5) szr2 = wx.BoxSizer(wx.HORIZONTAL) szr2.Add(wx.Button(self, wx.ID_OK, _("OK")), 0, wx.ALL, 5) szr2.Add(wx.Button(self, wx.ID_CANCEL, _("Cancel")), 0, wx.ALL, 5) szr.Add(szr2, 0, wx.ALIGN_CENTER) self.SetAutoLayout(True) self.SetSizer(szr) szr.Fit(self) self.CenterOnScreen() def __getitem__(self, name): def set_pos(v): self.pos = int(v) return (lambda : self.pos, set_pos) # end of class InsertDialog class Sizer: """\ Base class for every Sizer handled by wxGlade """ def __init__(self, window): self.window = window # window this sizer is responsible # for the layout of def set_item(self, pos, option=None, flag=None, border=None, size=None, force_layout=True): """\ Updates the layout of the item at the given pos. """ raise NotImplementedError def add_item(self, item, pos=None, option=0, flag=0, border=0, size=None, force_layout=True): """\ Adds an item to self. """ raise NotImplementedError def remove_item(self, elem, force_layout=True): """\ Removes elem from self. """ pass def free_slot(self, pos, force_layout=True): """\ Replaces the element at pos with an empty slot """ raise NotImplementedError def _fix_notebook(self, pos, notebook_sizer, force_layout=True): """\ Internal method used to replace a notebook widget with its notebook sizer. """ pass def is_virtual(self): """\ Return true if sizer is virtual (f.e. SplitterWindowSizer) """ return False def get_itempos(self, attrs): """\ For virtual sizers only, returns the position of the item in the parent: this is used when loading a wxg file, to build the tree of widgets correctly """ raise NotImplementedError # end of class Sizer class SizerBase(Sizer): """\ Base class for every non-virtual Sizer handled by wxGlade """ def __init__(self, name, klass, window, toplevel=True, show=True, menu=None): Sizer.__init__(self, window) self.id = wx.NewId() self.name = name self.klass = klass self.base = klass self.pos = 0 # for sub-sizers, the position inside the parent self.properties = {} self.property_window = window.property_window self.widget = None # this is the actual wxSizer instance # toplevel: if True, self is not inside another sizer, but it is the # responsible of the layout of self.window self.toplevel = toplevel if not self.toplevel: self.option = 1 self.flag = wx.EXPAND self.border = 0 self.sizer = None self.menu = menu if self.menu is None: self.menu = [(_('Add slot'), self.add_slot), (_('Insert slot...'), self.insert_slot)] #if not self.toplevel: self.menu.extend([(_('Copy\tCtrl+C'), self.clipboard_copy, wx.ART_COPY), (_('Cut\tCtrl+X'), self.clipboard_cut, wx.ART_CUT), ]) self._btn = None # SizerHandleButton self.notebook = None self._property_setup() self.children = [] # list of widgets added to the sizer def create_widget(self): """\ Creates the wxSizer self.widget """ raise NotImplementedError def show_widget(self, yes, dont_set=False): if not yes or self.widget: return # nothing to do if the sizer has already been created self._btn = SizerHandleButton(self.window, self.id, self, self.menu) # ScreenToClient used by WidgetTree for the popup menu wx.EVT_BUTTON(self._btn, self.id, self.show_properties) self.create_widget() self.widget.Refresh = self.refresh self.widget.GetBestSize = self.widget.GetMinSize self.widget.ScreenToClient = self._btn.ScreenToClient if self.toplevel and not dont_set: self.window.set_sizer(self) # ALB 2004-08-11 if not config.preferences.show_sizer_handle: self.widget.Show(self._btn, False) if misc.focused_widget is self: self.update_view(True) def _property_setup(self): """\ Setup of the Properties of self. """ self.flags_pos = [ wx.ALL, wx.LEFT, wx.RIGHT, wx.TOP, wx.BOTTOM, wx.EXPAND, wx.ALIGN_RIGHT, wx.ALIGN_BOTTOM, wx.ALIGN_CENTER_HORIZONTAL, wx.ALIGN_CENTER_VERTICAL, wx.SHAPED, wx.ADJUST_MINSIZE ] self.access_functions = { 'name' : (lambda : self.name, self.set_name), 'class' : (lambda : self.klass, self.change) #lambda v: None) } if not self.toplevel: self.access_functions['option'] = (self.get_option,self.set_option) self.access_functions['flag'] = (self.get_flag, self.set_flag) self.access_functions['border'] = (self.get_border,self.set_border) self.access_functions['pos'] = (self.get_pos, self.set_pos) self.name_prop = TextProperty(self, 'name', None, label=_('name')) #self.klass_prop = TextProperty(self, 'class', None, readonly=True) dialog = SizerClassDialog(self, None) self.klass_prop = DialogProperty(self, 'class', None, dialog, label=_('class')) if not self.toplevel: prop = self.sizer_properties = {} #prop['option'] = SpinProperty(self, 'option', None, 0, (0, 1000)) from layout_option_property import LayoutOptionProperty, \ LayoutPosProperty prop['option'] = LayoutOptionProperty(self, self.sizer) flag_labels = ['#section#' + _('Border'), 'wxALL', 'wxLEFT', 'wxRIGHT', 'wxTOP', 'wxBOTTOM', '#section#' + _('Alignment'), 'wxEXPAND', 'wxALIGN_RIGHT', 'wxALIGN_BOTTOM', 'wxALIGN_CENTER_HORIZONTAL', 'wxALIGN_CENTER_VERTICAL', 'wxSHAPED', 'wxADJUST_MINSIZE' ] prop['flag'] = CheckListProperty(self, 'flag', None, flag_labels) prop['border'] = SpinProperty(self, 'border', None, 0, (0, 1000), label=_('border')) prop['pos'] = LayoutPosProperty(self, self.sizer) def set_containing_sizer(self, sizer): self.sizer = sizer self.sizer_properties['option'].set_sizer(sizer) self.sizer_properties['pos'].set_sizer(sizer) def get_pos(self): return self.pos - 1 def set_pos(self, value): misc.wxCallAfter(self.sizer.change_item_pos, self, min(value + 1, len(self.sizer.children) - 1)) def update_pos(self, value): #print 'update pos', self.name, value self.sizer_properties['pos'].set_value(value-1) self.pos = value def change(self, *args): # if wxPython < 2.3.3, wxCallAfter is defined in misc.py misc.wxCallAfter(change_sizer, self, self.klass_prop.get_value()) def create_properties(self): """\ Displays the Properties of self """ self.notebook = wx.Notebook(common.property_panel, -1) if not misc.check_wx_version(2, 5, 2): nb_sizer = wx.NotebookSizer(self.notebook) self.notebook.sizer = nb_sizer else: self.notebook.sizer = None self.notebook.SetAutoLayout(True) panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) sizer_tmp = wx.BoxSizer(wx.VERTICAL) self.name_prop.display(panel) self.klass_prop.display(panel) self.klass_prop.text.SetEditable(False) sizer_tmp.Add(self.name_prop.panel, 0, wx.EXPAND) sizer_tmp.Add(self.klass_prop.panel, 0, wx.EXPAND) if not self.toplevel: prop = self.sizer_properties prop['pos'].display(panel) prop['option'].display(panel) prop['border'].display(panel) prop['flag'].display(panel) sizer_tmp.Add(prop['pos'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['option'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['border'].panel, 0, wx.EXPAND) sizer_tmp.Add(prop['flag'].panel, 0, wx.EXPAND) else: # button to Fit parent FIT_ID = wx.NewId() self.fit_btn = wx.Button(panel, FIT_ID, _('Fit parent')) wx.EVT_BUTTON(self.fit_btn, FIT_ID, self.fit_parent) sizer_tmp.Add(self.fit_btn, 0, wx.ALL|wx.EXPAND, 5) panel.SetAutoLayout(True) panel.SetSizer(sizer_tmp) sizer_tmp.Fit(panel) w, h = panel.GetClientSizeTuple() self.notebook.AddPage(panel, _("Common")) panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def popup_menu(self, event): """\ pops up a menu to add or remove slots from self, or to remove self from the application. """ if self._btn: self._btn.popup_menu(event) #self._btn.PopupMenu(self._btn._rmenu, event.GetPosition()) def set_name(self, value): value = "%s" % value if not config.preferences.allow_duplicate_names and \ (self.widget and common.app_tree.has_name(value, self.node)): misc.wxCallAfter( wx.MessageBox, _('Name "%s" is already in use.\n' 'Please enter a different one.') % value, _("Error"), wx.OK|wx.ICON_ERROR) self.name_prop.set_value(self.name) return if not re.match(self.set_name_pattern, value): self.name_prop.set_value(self.name) else: oldname = self.name self.name = value self._btn.set_menu_title(value) try: common.app_tree.refresh_name(self.node, oldname) #, self.name) except AttributeError: import traceback; traceback.print_exc() self.property_window.SetTitle(_('Properties - <%s>') % self.name) set_name_pattern = re.compile('^[a-zA-Z_]+[\w0-9]*$') def __getitem__(self, value): return self.access_functions[value] def show_properties(self, *args): """\ Updates common.property_panel to show the notebook with the Properties of self """ if not self.window.is_visible(): return if not self.notebook: self.create_properties() sizer_tmp = self.property_window.GetSizer() #sizer_tmp = wxPyTypeCast(sizer_tmp, "wxBoxSizer") #child = wxPyTypeCast(sizer_tmp.GetChildren()[0], "wxSizerItem") child = sizer_tmp.GetChildren()[0] #w = wxPyTypeCast(child.GetWindow(), "wxWindow") w = child.GetWindow() if w is self.notebook: return try: index = -1 title = w.GetPageText(w.GetSelection()) for i in range(self.notebook.GetPageCount()): if self.notebook.GetPageText(i) == title: index = i break except AttributeError, e: #print e index = -1 w.Hide() if 0 <= index < self.notebook.GetPageCount(): self.notebook.SetSelection(index) self.notebook.Reparent(self.property_window) child.SetWindow(self.notebook) w.Reparent(misc.hidden_property_panel) # ALB moved this before Layout, it seems to be needed for wx2.6... self.notebook.Show() self.notebook.SetSize(self.property_window.GetClientSize()) self.property_window.Layout() self.property_window.SetTitle(_('Properties - <%s>') % self.name) if hasattr(self, 'node'): common.app_tree.select_item(self.node) try: self._btn.SetFocus() except AttributeError: pass def fit_parent(self, *args): """\ Tell the sizer to resize the window to match the sizer's minimal size """ if self.widget and self.window.widget: self.widget.Fit(self.window.widget) #self.widget.SetSizeHints(self.window.widget) self.window.widget.Layout() def add_item(self, item, pos=None, option=0, flag=0, border=0, size=None, force_layout=True): """\ Adds an item to self. """ option = int(option); flag = int(flag); border = int(border) if pos is None: pos = len(self.children) ## self.children.append(SizerItem(item, pos, option, flag, border, ## size)) self.add_slot() try: old_child = self.children[pos] if isinstance(old_child.item, SizerSlot): old_child.item.delete(False) self.children[pos] = SizerItem(item, pos, option, flag, border, size) except IndexError: # this shouldn't happen! import traceback; traceback.print_exc() print self.children, pos raise SystemExit if hasattr(item, 'set_containing_sizer'): item.set_containing_sizer(self) else: item.sizer = self item.pos = pos self._add_item_widget(item, pos, option, flag, border, size, force_layout) def _add_item_widget(self, item, pos, option, flag, border, size, force_layout): if not self.widget: return # nothing more to do if not item.widget: return try: elem = self.widget.GetChildren()[pos] except IndexError: # this happens after loading from xml # I have to set wxADJUST_MINSIZE to handle a bug that I'm not # able to detect (yet): if the width or height of a widget is -1, # the layout is messed up! self.widget.Add(item.widget, option, flag, border) if size: w, h = size else: w, h = item.widget.GetBestSize() if w == -1: w = item.widget.GetBestSize()[0] if h == -1: h = item.widget.GetBestSize()[1] self.widget.SetItemMinSize(item.widget, w, h) return if not misc.check_wx_version(2, 5): if elem.IsWindow(): # remove the previous item at pos w = elem.GetWindow() elem.SetWindow(None) w.Destroy() try: # let's see if the item to add is a window elem.SetWindow(item.widget) except TypeError: # suppose the item to add is a sizer elem.SetSizer(item.widget) elem.SetOption(option) elem.SetFlag(flag) elem.SetBorder(border) else: self.widget.Insert(pos, item.widget, option, flag, border) self.widget.Remove(pos+1) if elem.IsWindow(): w = elem.GetWindow() w.SetContainingSizer(None) w.Destroy() try: # if the item was a window, set its size to a reasonable value ## if elem.IsWindow(): if size: w, h = size else: w, h = item.widget.GetBestSize() if w == -1: w = item.widget.GetBestSize()[0] if h == -1: h = item.widget.GetBestSize()[1] option = 0 if misc.check_wx_version(2, 5): option = elem.GetProportion() else: option = elem.GetOption() flag = elem.GetFlag() if not size or (option == 0 or not (flag & wx.EXPAND)): self.widget.SetItemMinSize(item.widget, w, h) else: w, h = item.widget.GetBestSize() self.widget.SetItemMinSize(item.widget, w, h) #*item.widget.GetBestSize()) #self.widget.SetItemMinSize(item.widget, w, h) except Exception, e: #import traceback; traceback.print_exc() pass if force_layout: self.layout() # update the layout of self def _fix_notebook(self, pos, notebook_sizer, force_layout=True): """\ Replaces the widget at 'pos' with 'notebook_sizer': this is intended to be used by wxNotebook widgets, to add the notebook sizer to this sizer. This is a hack, but it's the best I could find without having to rewrite too much code :-( """ # no error checking at all, this is a "protected" method, so it should # be safe to assume the caller knows how to use it item = self.widget.GetChildren()[pos] if not misc.check_wx_version(2, 5): item.SetWindow(None) else: if item.IsWindow(): w = item.GetWindow() w.SetContainingSizer(None) item.SetSizer(notebook_sizer) if force_layout: self.layout() def set_item(self, pos, option=None, flag=None, border=None, size=None, force_layout=True): """\ Updates the layout of the item at the given pos. """ try: item = self.children[pos] except IndexError: # this shouldn't happen import traceback; traceback.print_exc() raise SystemExit if option is not None: option = int(option) item.option = option if flag is not None: flag = int(flag) item.flag = flag if border is not None: border = int(border) item.border = border if size is not None: item.size = size self._set_item_widget(pos, option, flag, border, size, force_layout) def _set_item_widget(self, pos, option, flag, border, size, force_layout): if not self.widget: return try: elem = self.widget.GetChildren()[pos] except IndexError: return # this may happen during xml loading if option is not None: if not misc.check_wx_version(2, 5): elem.SetOption(option) else: elem.SetProportion(option) if flag is not None: elem.SetFlag(flag) if border is not None: elem.SetBorder(border) if elem.IsWindow(): item = elem.GetWindow() if size is None: size = elem.GetSize() w, h = size if w == -1: w = item.GetBestSize()[0] if h == -1: h = item.GetBestSize()[1] newelem = wx.SizerItem() newelem.SetWindow(item) newelem.SetFlag(elem.GetFlag()) newelem.SetBorder(elem.GetBorder()) if misc.check_wx_version(2, 5): newelem.SetProportion(elem.GetProportion()) else: newelem.SetOption(elem.GetOption()) newelem.SetInitSize(w, h) self.widget.InsertItem(pos, newelem) #self.children[pos] = newelem self.widget.Remove(pos+1) if force_layout: self.layout(True) #try: self.sizer.Layout() #except AttributeError: pass def remove_item(self, elem, force_layout=True): """\ Removes elem from self. """ if elem: for c in self.children[elem.pos+1:]: c.item.pos -= 1 del self.children[elem.pos] if self.widget and elem.widget: self.widget.Remove(elem.widget) if force_layout: self.layout(True) #if not self.toplevel: self.sizer.Layout() Remove = remove_item # maybe this is needed, I have to check... def layout(self, recursive=True): #if not self.widget or not self.window.is_visible(): return if not self.widget: return from edit_windows import TopLevelBase if self.toplevel and not isinstance(self.window, TopLevelBase) and \ hasattr(self.window.sizer, 'widget'): if not self.window.properties['size'].is_active(): szr = self.window.sizer.widget w, h = self.window.widget.GetBestSize() szr.SetItemMinSize(self.window.widget, w, h) if self.window.sizer is not self: self.window.sizer.layout(False) else: szr.Layout() return elif self.toplevel and isinstance(self.window, TopLevelBase): #self.window.widget.Layout() self.widget.Layout() evt = wx.SizeEvent(self.window.widget.GetSize(), self.window.widget.GetId()) wx.PostEvent(self.window.widget, evt) # don't change the size of the window if misc.check_wx_version(2, 4, 1) and \ not misc.check_wx_version(2, 6, 0): # this seems to work bad for 2.4.0 (and 2.6 too... 2005-05-01) self.widget.FitInside(self.window.widget) return self.widget.SetMinSize(self.widget.CalcMin()) self.widget.Layout() for c in self.children: try: c.item.widget.Refresh() except Exception, e: pass if recursive: if getattr(self, 'sizer', None) is not None: self.sizer.layout(recursive) # 2002-10-09 ------------------------------------------------------------- def change_item_pos(self, item, new_pos, force_layout=True): """\ Changes the position of the 'item' so that it is at 'new_pos' 'new_pos' must be a valid position """ if not self.widget: return #print old_pos = item.pos import copy new_item = copy.copy(self.children[old_pos]) if old_pos > new_pos: for c in self.children[new_pos:old_pos]: c.item.update_pos(c.item.pos + 1) self.children.insert(new_pos, new_item) del self.children[old_pos+1] else: for c in self.children[old_pos+1:new_pos+1]: c.item.update_pos(c.item.pos - 1) del self.children[old_pos] #self.children.insert(new_pos+1, new_item) self.children.insert(new_pos, new_item) item.update_pos(new_pos) elem = self.widget.GetChildren()[old_pos] # always set the sizer to None because otherwise it will be Destroy'd elem.SetSizer(None) # this fake_win trick seems necessary because wxSizer::Remove(int pos) # doesn't seem to work with grid sizers :-\ fake_win = wx.Window(self.window.widget, -1) elem.SetWindow(fake_win) self.widget.Remove(fake_win) fake_win.Destroy() self.widget.Insert(new_pos, item.widget, int(item.get_option()), item.get_int_flag(), int(item.get_border())) common.app_tree.change_node_pos(item.node, new_pos-1) common.app_tree.select_item(item.node) if force_layout: self.layout() if wx.Platform == '__WXMSW__': self.window.widget.Refresh() #print [c.item.name for c in self.children] # ------------------------------------------------------------------------ def set_option(self, value): """\ If self is not a toplevel sizer, update the layout to reflect the value of the option property """ self.option = int(value) try: self.sizer.set_item(self.pos, option=self.option) #print self.name, 'set_option', self.option except AttributeError, e: pass self.finish_set() def set_flag(self, value): """\ If self is not a toplevel sizer, update the layout to reflect the value of the flag property """ value = self.sizer_properties['flag'].prepare_value(value) flags = 0 for v in range(len(value)): if value[v]: flags |= self.flags_pos[v] self.flag = flags try: self.sizer.set_item(self.pos, flag=flags) except AttributeError, e: pass self.finish_set() def set_border(self, value): """\ If self is not a toplevel sizer, update the layout to reflect value of the border property """ self.border = int(value) try: self.sizer.set_item(self.pos, border=self.border) except AttributeError, e: print e def get_option(self): if not hasattr(self, 'sizer'): return '1' return str(self.option) def get_flag(self): retval = [0] * len(self.flags_pos) if not hasattr(self, 'sizer'): return retval try: flag = self.flag for i in range(len(self.flags_pos)): if flag & self.flags_pos[i]: retval[i] = 1 # patch to make wxALL work if retval[1:5] == [1, 1, 1, 1]: retval[0] = 1; retval[1:5] = [0, 0, 0, 0] else: retval[0] = 0 except AttributeError: pass return retval def get_int_flag(self): try: return self.flag except AttributeError: return wx.EXPAND def get_border(self): if not hasattr(self, 'sizer'): return '0' return str(self.border) def remove(self): # this function is here for clipboard compatibility if not self._btn: return self._btn._remove() def delete(self): """\ ``Destructor'' """ self._rmenu = None if self._btn: self._btn.Destroy() if self.notebook: ## for p in self.properties.itervalues(): ## if p.panel: p.panel.Destroy() ## if self.name_prop.panel: self.name_prop.panel.Destroy() ## if self.klass_prop.panel: self.klass_prop.panel.Destroy() ## if hasattr(self, 'sizer_properties'): ## for p in self.sizer_properties.itervalues(): ## if p.panel: p.panel.Destroy() nb_szr = self.notebook.sizer self.notebook.DeleteAllPages() self.notebook.Destroy() if nb_szr is not None: nb_szr.Destroy() for c in self.children: if c.item and isinstance(c.item, SizerSlot): c.item.delete() if self.toplevel: self.window.set_sizer(None) if wx.Platform == '__WXMSW__': def finish_set(self): for c in self.children: if c.item.widget: try: c.item.widget.Refresh() except AttributeError: pass # sizers have no Refresh else: def finish_set(self): pass def refresh(self, *args): # this will be self.widget.Refresh for c in self.children: if c.item.widget: try: c.item.widget.Refresh() except AttributeError: pass def update_view(self, selected): if self._btn is not None: color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) if selected: color = wx.RED self._btn.SetBackgroundColour(color) self._btn.Refresh(True) def add_slot(self, *args, **kwds): """\ adds a slot to the sizer, i.e. a fake window that will accept the dropping of widgets """ tmp = SizerSlot(self.window, self, len(self.children)) item = SizerItem(tmp, len(self.children), 1, wx.EXPAND) self.children.append(item) if not self.widget: return tmp.show_widget(True) # create the actual SizerSlot widget self.widget.Add(tmp.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(tmp.widget, 20, 20) force_layout = kwds.get('force_layout', True) if force_layout: self.layout(True) common.app_tree.app.saved = False def insert_slot(self, *args, **kwds): """\ inserts a slot into the sizer: the user will be asked for a position before which to insert the SizerSlot object. This method is meaningful only in an interactive session """ if not self.widget: return dialog = InsertDialog(len(self.children)-1) if dialog.ShowModal() == wx.ID_OK: pos = dialog.pos + 1 tmp = SizerSlot(self.window, self, pos) for c in self.children[pos:]: c.item.pos += 1 self.children.insert(pos, SizerItem(tmp, pos, 1, wx.EXPAND, 0)) tmp.show_widget(True) # create the actual SizerSlot self.widget.Insert(pos, tmp.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(tmp.widget, 20, 20) force_layout = kwds.get('force_layout', True) if force_layout: self.layout(True) common.app_tree.app.saved = False dialog.Destroy() def free_slot(self, pos, force_layout=True): """\ Replaces the element at pos with an empty slot """ tmp = SizerSlot(self.window, self, pos) item = SizerItem(tmp, pos, 1, wx.EXPAND, 0) self.children[pos] = item if self.widget: tmp.show_widget(True) # create the actual SizerSlot if misc.check_wx_version(2, 6): self.widget.Insert(pos+1, tmp.widget, 1, wx.EXPAND) self.widget.Detach(pos) else: elem = self.widget.GetChildren()[pos] elem.SetWindow(tmp.widget) elem.SetSizer(None) if not misc.check_wx_version(2, 5): elem.SetOption(1) else: elem.SetProportion(1) elem.SetBorder(0) elem.SetFlag(wx.EXPAND) if force_layout: self.layout() def is_visible(self): return self.window.is_visible() def clipboard_copy(self, *args): """\ returns a copy of self to be inserted in the clipboard """ #if not self.toplevel: import clipboard clipboard.copy(self) def clipboard_cut(self, *args): #if not self.toplevel: import clipboard clipboard.cut(self) def post_load(self): """\ Called after the loading of an app from an XML file, before showing the hierarchy of widget for the first time. This is used only for container widgets, to adjust their size appropriately. """ if not self.toplevel: return if not self.window.properties['size'].is_active(): self.fit_parent() import config w, h = self.widget.GetSize() prefix = '' if config.preferences.use_dialog_units: w, h = self.window.widget.ConvertPixelSizeToDialog( self.widget.GetSize()) prefix = 'd' self.window.set_size('%s, %s%s' % (w, h, prefix)) # end of class SizerBase class wxGladeBoxSizer(wx.BoxSizer): def SetItemMinSize(self, item, w, h): try: w2, h2 = item.GetBestSize() if w == -1: w = w2 if h == -1: h = h2 except AttributeError: pass wx.BoxSizer.SetItemMinSize(self, item, w, h) # end of class wxGladeBoxSizer class EditBoxSizer(SizerBase): """\ Class to handle wxBoxSizer objects """ def __init__(self, name, window, orient=wx.VERTICAL, elements=3, toplevel=True, show=True): SizerBase.__init__(self, name, 'wxBoxSizer', window, toplevel, show) self.access_functions['orient'] = (self.get_orient, self.set_orient) self.properties = {'orient': HiddenProperty(self, 'orient', (orient==wx.HORIZONTAL and 'wxHORIZONTAL' or 'wxVERTICAL')) } class Dummy: widget = None name = "" # add to self.children the SizerItem for self._btn self.children = [SizerItem(Dummy(), 0, 0, wx.EXPAND)] for i in range(1, elements+1): tmp = SizerSlot(self.window, self, i) self.children.append(SizerItem(tmp, i, 1, wx.EXPAND)) self.orient = orient def create_widget(self): self.widget = wxGladeBoxSizer(self.orient) self.widget.Add(self._btn, 0, wx.EXPAND) to_lay_out = [] for c in self.children[1:]: # we've already added self._btn c.item.show_widget(True) if isinstance(c.item, SizerSlot): self.widget.Add(c.item.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(c.item.widget, 20, 20) else: sp = c.item.properties.get('size') if sp and sp.is_active(): if (c.option != 0 or (c.flag & wx.EXPAND)) and \ (misc.check_wx_version(2, 4) or \ not (c.flag & wx.FIXED_MINSIZE)): c.item.widget.Layout() w, h = c.item.widget.GetBestSize() if misc.check_wx_version(2, 5): #print "HERE:", w, h c.item.widget.SetMinSize((w, h)) else: ## if misc.check_wx_version(2, 4) or \ ## ((c.flag & wxFIXED_MINSIZE) and \ ## (c.option == 0 or not (c.flag & wxEXPAND))): size = sp.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(c.item.widget, (w, h)) ## else: ## w, h = c.item.widget.GetBestSize() # now re-set the item to update the size correctly... to_lay_out.append((c.item.pos, (w, h))) ## else: ## w, h = c.item.widget.GetBestSize() ## self.widget.SetItemMinSize(c.item.widget, w, h) for pos, size in to_lay_out: self.set_item(pos, size=size, force_layout=False) self.layout(True) if not self.toplevel and getattr(self, 'sizer'): # hasattr(self, 'sizer') is False only in case of a 'change_sizer' # call self.sizer.add_item(self, self.pos, self.option, self.flag, self.border, self.widget.GetMinSize()) def get_orient(self): od = { wx.HORIZONTAL: 'wxHORIZONTAL', wx.VERTICAL: 'wxVERTICAL' } return od.get(self.orient) def set_orient(self, value): od = { 'wxHORIZONTAL': wx.HORIZONTAL, 'wxVERTICAL': wx.VERTICAL } self.orient = od.get(value, wx.VERTICAL) # end of class EditBoxSizer class wxGladeStaticBoxSizer(wx.StaticBoxSizer): def SetItemMinSize(self, item, w, h): try: w2, h2 = item.GetBestSize() if w == -1: w = w2 if h == -1: h = h2 except AttributeError: pass wx.StaticBoxSizer.SetItemMinSize(self, item, w, h) # end of class wxGladeStaticBoxSizer class EditStaticBoxSizer(SizerBase): """\ Class to handle wxStaticBoxSizer objects """ def __init__(self, name, window, orient=wx.VERTICAL, label='', elements=3, toplevel=True, show=True): self.label = label self.orient = orient SizerBase.__init__(self, name, 'wxStaticBoxSizer', window, toplevel, show) self.access_functions['orient'] = (self.get_orient, self.set_orient) self.properties['orient'] = HiddenProperty(self, 'orient', (orient==wx.HORIZONTAL and 'wxHORIZONTAL' or 'wxVERTICAL')) class Dummy: widget = None # add to self.children the SizerItem for self._btn self.children = [SizerItem(Dummy(), 0, 0, wx.EXPAND)] for i in range(1, elements+1): tmp = SizerSlot(self.window, self, i) self.children.append(SizerItem(tmp, i, 1, wx.EXPAND)) def create_widget(self): self.widget = wxGladeStaticBoxSizer(wx.StaticBox(self.window.widget, -1, self.label), self.orient) self.widget.Add(self._btn, 0, wx.EXPAND) for c in self.children[1:]: # we've already added self._btn c.item.show_widget(True) if isinstance(c.item, SizerSlot): self.widget.Add(c.item.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(c.item.widget, 20, 20) else: sp = c.item.properties.get('size') if sp and sp.is_active() and \ (c.option == 0 or not (c.flag & wx.EXPAND)): size = sp.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(c.item.widget, (w, h)) else: w, h = c.item.widget.GetBestSize() self.widget.SetItemMinSize(c.item.widget, w, h) self.layout() if not self.toplevel and getattr(self, 'sizer'): # getattr(self, 'sizer') is False only in case of a 'change_sizer' # call self.sizer.add_item(self, self.pos, self.option, self.flag, self.border, self.widget.GetMinSize()) def _property_setup(self): SizerBase._property_setup(self) self.access_functions['label'] = (self.get_label, self.set_label) lbl = self.properties['label'] = TextProperty(self, 'label', None, label=_("label")) def write(outfile, tabs): import widget_properties outfile.write(' ' * tabs + '\n') # we must consider also "" a valid value lbl.write = write def create_properties(self): SizerBase.create_properties(self) panel = self.notebook.GetPage(0) sizer = panel.GetSizer() self.properties['label'].display(panel) sizer.Add(self.properties['label'].panel, 0, wx.EXPAND) sizer.Layout() w, h = sizer.GetMinSize() panel.SetScrollbars(1, 5, 1, int(math.ceil(h/5.0))) def set_label(self, value): """\ Sets the label of the static box """ self.label = misc.wxstr(value) if self.widget: self.widget.GetStaticBox().SetLabel(self.label) self.layout() def get_label(self): return self.label def delete(self): if self.widget: self.widget.GetStaticBox().Destroy() SizerBase.delete(self) def get_orient(self): od = { wx.HORIZONTAL: 'wxHORIZONTAL', wx.VERTICAL: 'wxVERTICAL' } return od.get(self.orient) def set_orient(self, value): od = { 'wxHORIZONTAL': wx.HORIZONTAL, 'wxVERTICAL': wx.VERTICAL } self.orient = od.get(value, wx.VERTICAL) # end of class EditStaticBoxSizer class CustomSizer(wx.BoxSizer): """\ Custom wxSizer class used to implement a GridSizer with an additional handle button """ def __init__(self, parent, factory, rows, cols, vgap, hgap): wx.BoxSizer.__init__(self, wx.VERTICAL) self.parent = parent self._grid = factory(rows, cols, vgap, hgap) wx.BoxSizer.Add(self, self.parent._btn, 0, wx.EXPAND) wx.BoxSizer.Add(self, self._grid, 1, wx.EXPAND) def __getattr__(self, name): return getattr(self._grid, name) def GetBestSize(self): return self._grid.GetMinSize() def Add(self, *args, **kwds): self._grid.Add(*args, **kwds) def Insert(self, pos, *args, **kwds): self._grid.Insert(pos-1, *args, **kwds) def Remove(self, *args, **kwds): try: pos = int(args[0])-1 self._grid.Remove(pos) except TypeError: self._grid.Remove(*args, **kwds) def RemovePos(self, pos): self._grid.Remove(pos-1) def Detach(self, pos_or_obj): try: pos = int(pos_or_obj) - 1 self._grid.Detach(pos) except TypeError: self._grid.Detach(pos_or_obj) def SetItemMinSize(self, item, w, h): #*args, **kwds): try: w2, h2 = item.GetBestSize() if w == -1: w = w2 if h == -1: h = h2 except AttributeError: pass self._grid.SetItemMinSize(item, w, h) def GetChildren(self): return [None] + list(self._grid.GetChildren()) def Layout(self): self._grid.Layout() wx.BoxSizer.Layout(self) # end of class CustomSizer class GridSizerBase(SizerBase): """\ Base class for Grid sizers. Must not be instantiated. """ def __init__(self, name, klass, window, rows=3, cols=3, vgap=0, hgap=0, toplevel=True, show=True): self.rows = rows; self.cols = cols self.vgap = vgap; self.hgap = hgap if self.cols or self.rows: if not self.rows: self.rows = 1 elif not self.cols: self.cols = 1 menu = [(_('Add slot'), self.add_slot), (_('Insert slot...'), self.insert_slot), (_('Add row'), self.add_row), (_('Add column'), self.add_col), (_('Insert row...'), self.insert_row), (_('Insert column...'), self.insert_col)] SizerBase.__init__(self, name, klass, window, toplevel, show, menu) class Dummy: widget = None # add to self.children the SizerItem for self._btn self.children = [SizerItem(Dummy(), 0, 0, wx.EXPAND)] for i in range(1, self.rows*self.cols+1): tmp = SizerSlot(self.window, self, i) self.children.append(SizerItem(tmp, i, 1, wx.EXPAND)) def create_widget(self): """\ This must be overriden and called at the end of the overriden version """ to_lay_out = [] for c in self.children[1:]: # we've already added self._btn c.item.show_widget(True) if isinstance(c.item, SizerSlot): self.widget.Add(c.item.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(c.item.widget, 20, 20) else: sp = c.item.properties.get('size') if sp and sp.is_active(): if (c.option != 0 or (c.flag & wx.EXPAND)) and \ (misc.check_wx_version(2, 4) or \ not (c.flag & wx.FIXED_MINSIZE)): c.item.widget.Layout() w, h = c.item.widget.GetBestSize() if misc.check_wx_version(2, 5): c.item.widget.SetMinSize((w, h)) else: size = sp.get_value().strip() if size[-1] == 'd': size = size[:-1] use_dialog_units = True else: use_dialog_units = False w, h = [ int(v) for v in size.split(',') ] if use_dialog_units: w, h = wx.DLG_SZE(c.item.widget, (w, h)) # now re-set the item to update the size correctly... to_lay_out.append((c.item.pos, (w, h))) ## sp = c.item.properties.get('size') ## if sp and sp.is_active() and \ ## (c.option == 0 or not (c.flag & wxEXPAND)): ## size = sp.get_value().strip() ## if size[-1] == 'd': ## size = size[:-1] ## use_dialog_units = True ## else: use_dialog_units = False ## w, h = [ int(v) for v in size.split(',') ] ## if use_dialog_units: ## w, h = wxDLG_SZE(c.item.widget, (w, h)) ## else: ## w, h = c.item.widget.GetBestSize() ## self.widget.SetItemMinSize(c.item.widget, w, h) for pos, size in to_lay_out: #print 'set_item:', pos, size self.set_item(pos, size=size, force_layout=False) self.layout(True) def _property_setup(self): SizerBase._property_setup(self) self.access_functions['rows'] = (self.get_rows, self.set_rows) self.access_functions['cols'] = (self.get_cols, self.set_cols) self.access_functions['hgap'] = (self.get_hgap, self.set_hgap) self.access_functions['vgap'] = (self.get_vgap, self.set_vgap) props = { 'rows': SpinProperty(self, 'rows', None, label=_("rows")), 'cols': SpinProperty(self, 'cols', None, label=_("cols")), 'hgap': SpinProperty(self, 'hgap', None, label=_("hgap")), 'vgap': SpinProperty(self, 'vgap', None, label=_("vgap")) } self.properties = props def create_properties(self): SizerBase.create_properties(self) page = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL) sizer = wx.BoxSizer(wx.VERTICAL) props = self.properties props['rows'].display(page) props['cols'].display(page) props['vgap'].display(page) props['hgap'].display(page) sizer.Add(props['rows'].panel, 0, wx.EXPAND) sizer.Add(props['cols'].panel, 0, wx.EXPAND) sizer.Add(props['vgap'].panel, 0, wx.EXPAND) sizer.Add(props['hgap'].panel, 0, wx.EXPAND) page.SetAutoLayout(True) page.SetSizer(sizer) sizer.Fit(page) self.notebook.AddPage(page, _("Grid")) def get_rows(self): return self.rows def get_cols(self): return self.cols def get_vgap(self): return self.vgap def get_hgap(self): return self.hgap def _set_rows_cols(self, rows, cols): self.rows = rows self.cols = cols self.properties['rows'].set_value(rows) self.properties['cols'].set_value(cols) if self.widget: self.widget.SetRows(self.rows) self.widget.SetCols(self.cols) self.layout(True) def set_rows(self, rows): self.rows = int(rows) if self.widget: self.widget.SetRows(self.rows) self.layout(True) def set_cols(self, cols): self.cols = int(cols) if self.widget: self.widget.SetCols(self.rows) self.layout(True) def set_hgap(self, hgap): self.hgap = int(hgap) if self.widget: self.widget.SetHGap(self.hgap) self.layout() def set_vgap(self, vgap): self.vgap = int(vgap) if self.widget: self.widget.SetVGap(self.vgap) self.layout() def fit_parent(self, *args): """\ Tell the sizer to resize the window to match the sizer's minimal size """ if self.widget and self.window.widget: self.widget.Fit(self.window.widget) self.widget.SetSizeHints(self.window.widget) def insert_slot(self, *args, **kwds): """\ inserts a slot into the sizer: the user will be asked for a position before which to insert the SizerSlot object """ if not self.widget: return if kwds.get('interactive', True): dialog = InsertDialog(len(self.children)) ok = dialog.ShowModal() == wx.ID_OK pos = dialog.pos+1 dialog.Destroy() else: pos = kwds['pos'] ok = True if ok: tmp = SizerSlot(self.window, self, pos) for c in self.children[pos:]: c.item.pos += 1 self.children.insert(pos, SizerItem(tmp, pos, 1, wx.EXPAND, 0)) tmp.show_widget(True) # create the actual SizerSlot self.widget.Insert(pos, tmp.widget, 1, wx.EXPAND) self.widget.SetItemMinSize(tmp.widget, 20, 20) force_layout = kwds.get('force_layout', True) if force_layout: self.layout(True) common.app_tree.app.saved = False def add_row(self, *args, **kwds): if not self.widget: return self._insert_row(self.widget.GetRows()+1) def insert_row(self, *args): if not self.widget: return dialog = InsertDialog(self.widget.GetRows()) if dialog.ShowModal() == wx.ID_OK: self._insert_row(dialog.pos + 1) dialog.Destroy() def _insert_row(self, pos): rows = self.widget.GetRows() cols = self.widget.GetCols() pos = (pos-1) * cols + 1 if pos >= len(self.children): # fix the out of bounds index... tot = len(self.children) - 1 rows = tot / cols if tot % cols: rows += 1 # print 'fixed rows:', rows if rows * cols > tot: for i in range(rows * cols - tot): self.insert_slot(interactive=False, pos=tot+i+1, force_layout=False) pos = rows * cols + 1 self.set_rows(rows+1) for i in range(cols): self.insert_slot(interactive=False, pos=pos+i, force_layout=False) self.properties['rows'].set_value(self.rows) self.layout(True) common.app_tree.app.saved = False def add_col(self, *args, **kwds): if not self.widget: return self._insert_col(self.widget.GetCols()+1) def insert_col(self, *args): if not self.widget: return dialog = InsertDialog(self.widget.GetCols()) if dialog.ShowModal() == wx.ID_OK: self._insert_col(dialog.pos + 1) dialog.Destroy() def _insert_col(self, pos): rows = self.widget.GetRows() cols = self.widget.GetCols() if pos >= len(self.children): # fix the out of bounds index... tot = len(self.children) - 1 cols = tot / rows if tot % rows: cols += 1 # print 'fixed cols:', cols if rows * cols > tot: for i in range(rows * cols - tot): self.insert_slot(interactive=False, pos=tot+i+1, force_layout=False) pos = rows * cols + 1 self.set_cols(cols+1) for i in range(rows): self.insert_slot(interactive=False, pos=pos + self.cols * i, #pos=cols + self.cols * i, force_layout=False) self.properties['cols'].set_value(self.cols) self.layout(True) common.app_tree.app.saved = False def _set_item_widget(self, pos, option, flag, border, size, force_layout): if not self.widget: return try: elem = self.widget.GetChildren()[pos] except IndexError: return # this may happen during xml loading if option is not None: if not misc.check_wx_version(2, 5): elem.SetOption(option) else: elem.SetProportion(option) if flag is not None: elem.SetFlag(flag) if border is not None: elem.SetBorder(border) if elem.IsWindow(): if size is None: size = elem.GetSize() item = elem.GetWindow() w, h = size if w == -1: w = item.GetBestSize()[0] if h == -1: h = item.GetBestSize()[1] self.widget.SetItemMinSize(item, w, h) if force_layout: self.layout(True) #try: self.sizer.Layout() #except AttributeError: pass # end of class GridSizerBase class EditGridSizer(GridSizerBase): """\ Class to handle wxGridSizer objects """ def __init__(self, name, window, rows=3, cols=3, vgap=0, hgap=0, toplevel=True, show=True): GridSizerBase.__init__(self, name, 'wxGridSizer', window, rows, cols, vgap, hgap, toplevel, show) def create_widget(self): self.widget = CustomSizer(self, wx.GridSizer, self.rows, self.cols, self.vgap, self.hgap) if not self.toplevel and getattr(self, 'sizer', None): # getattr(self, 'sizer') is False only in case of a 'change_sizer' # call self.sizer.add_item(self, self.pos, self.option, self.flag, self.border) #, self.widget.GetMinSize()) GridSizerBase.create_widget(self) # end of class EditGridSizer class CheckListDialogProperty(DialogProperty): dialog = [None] def __init__(self, owner, name, parent, title, message, callback, can_disable=True): self.title = title self.message = message if not self.dialog[0]: class Dialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, parent, -1, title) sizer = wx.BoxSizer(wx.VERTICAL) self.message = wx.StaticText(self, -1, "") sizer.Add(self.message, 0, wx.TOP|wx.LEFT|wx.RIGHT|wx.EXPAND, 10) self.choices = wx.CheckListBox(self, -1, choices=['dummy']) sizer.Add(self.choices, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 10) sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 10) sz2 = wx.BoxSizer(wx.HORIZONTAL) sz2.Add(wx.Button(self, wx.ID_OK, ""), 0, wx.ALL, 10) sz2.Add(wx.Button(self, wx.ID_CANCEL, ""), 0, wx.ALL, 10) sizer.Add(sz2, 0, wx.ALIGN_CENTER) self.SetAutoLayout(True) self.SetSizer(sizer) sizer.Fit(self) self.CenterOnScreen() def get_value(self): ret = [] for c in range(self.choices.GetCount()): if self.choices.IsChecked(c): ret.append(str(c)) return ",".join(ret) def set_choices(self, values): if wx.Platform != '__WXGTK__': self.choices.Set(values) else: self.choices.Clear() for v in values: self.choices.Append(v) def set_descriptions(self, title, message): self.SetTitle(title) self.message.SetLabel(message) # end of class Dialog self.dialog[0] = Dialog() DialogProperty.__init__(self, owner, name, parent, self.dialog[0], can_disable, label=title) self.choices_setter = callback def display_dialog(self, event): self.set_choices(self.choices_setter()) self.dialog.set_descriptions(self.title, self.message) DialogProperty.display_dialog(self, event) def set_choices(self, values): self.dialog.set_choices(values) # end of class CheckListDialogProperty class EditFlexGridSizer(GridSizerBase): """\ Class to handle wxFlexGridSizer objects """ def __init__(self, name, window, rows=3, cols=3, vgap=0, hgap=0, toplevel=True, show=True): GridSizerBase.__init__(self, name, 'wxFlexGridSizer', window, rows, cols, vgap, hgap, toplevel, show) def create_widget(self): self.widget = CustomSizer(self, wx.FlexGridSizer, self.rows, self.cols, self.vgap, self.hgap) GridSizerBase.create_widget(self) for r in self.grow_rows: self.widget.AddGrowableRow(r) for c in self.grow_cols: self.widget.AddGrowableCol(c) if not self.toplevel and getattr(self, 'sizer', None) is not None: # hasattr(self, 'sizer') is False only in case of a 'change_sizer' # call self.sizer.add_item(self, self.pos, self.option, self.flag, self.border) def _property_setup(self): GridSizerBase._property_setup(self) self.grow_rows = [] self.access_functions['growable_rows'] = (self.get_growable_rows, self.set_growable_rows) self.grow_cols = [] self.access_functions['growable_cols'] = (self.get_growable_cols, self.set_growable_cols) def rows_setter(): return map(str, range(self.get_rows())) pr = CheckListDialogProperty(self, 'growable_rows', None, _('Growable Rows'), _('Select growable rows'), rows_setter) self.properties['growable_rows'] = pr def cols_setter(): return map(str, range(self.get_cols())) pr = CheckListDialogProperty(self, 'growable_cols', None, _('Growable Columns'), _('Select growable columns'), cols_setter) self.properties['growable_cols'] = pr def create_properties(self): GridSizerBase.create_properties(self) page = self.notebook.GetPage(1) sizer = page.GetSizer() props = self.properties props['growable_rows'].display(page) props['growable_cols'].display(page) sizer.Add(props['growable_rows'].panel, 0, wx.EXPAND) sizer.Add(props['growable_cols'].panel, 0, wx.EXPAND) sizer.Layout() sizer.Fit(page) def set_growable_rows(self, value): try: self.grow_rows = [int(i) for i in value.split(',')] except: if not value.strip(): self.grow_rows = [] else: self.properties['growable_rows'].set_value( self.get_growable_rows()) return if self.widget: if self.notebook: page = self.notebook.GetSelection() else: page = 0 misc.wxCallAfter(change_sizer, self, self.klass_prop.get_value(), page) def set_growable_cols(self, value): try: self.grow_cols = [int(i) for i in value.split(',')] except: if not value.strip(): self.grow_cols = [] else: self.properties['growable_cols'].set_value( self.get_growable_cols()) return if self.widget: if self.notebook: page = self.notebook.GetSelection() else: page = 0 misc.wxCallAfter(change_sizer, self, self.klass_prop.get_value(), page) def get_growable_rows(self): return ','.join(map(str, self.grow_rows)) def get_growable_cols(self): return ','.join(map(str, self.grow_cols)) def _insert_row(self, pos): for i in range(len(self.grow_rows)): if self.grow_rows[i] >= pos-1: self.grow_rows[i] += 1 GridSizerBase._insert_row(self, pos) self.set_growable_rows(self.get_growable_rows()) def _insert_col(self, pos): for i in range(len(self.grow_cols)): if self.grow_cols[i] >= pos-1: self.grow_cols[i] += 1 GridSizerBase._insert_col(self, pos) self.set_growable_cols(self.get_growable_cols()) # end of class EditFlexGridSizer def _builder(parent, sizer, pos, orientation=wx.VERTICAL, slots=1, is_static=False, label="", number=[1], show=True): num = slots name = 'sizer_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'sizer_%d' % number[0] if sizer is not None: topl = 0 else: topl = 1 if is_static: sz = EditStaticBoxSizer(name, parent, orientation, label, num, topl) else: sz = EditBoxSizer(name, parent, orientation, num, topl) if sizer is not None: sizer.add_item(sz, pos, 1, wx.EXPAND) node = Tree.Node(sz) sz.node = node common.app_tree.insert(node, sizer.node, pos-1) common.adding_sizer = False else: parent.set_sizer(sz) node = Tree.Node(sz) sz.node = node if pos is None: common.app_tree.add(node, parent.node) else: common.app_tree.insert(node, parent.node, pos-1) sz.pos = pos sz.show_widget(show) if sizer is not None: sz.sizer_properties['flag'].set_value('wxEXPAND') sz.sizer_properties['pos'].set_value(pos-1) def builder(parent, sizer, pos, number=[1], show=True): """\ factory function for box sizers. """ class SizerDialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, misc.get_toplevel_parent(parent), -1, _('Select sizer type')) self.orientation = wx.RadioBox(self, -1, _('Orientation'), choices=[_('Horizontal'), _('Vertical')]) self.orientation.SetSelection(0) tmp = wx.BoxSizer(wx.HORIZONTAL) tmp.Add(wx.StaticText(self, -1, _('Slots: ')), 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 3) self.num = wx.SpinCtrl(self, -1) self.num.SetRange(1, 100) self.num.SetValue(1) tmp.Add(self.num, 1, wx.ALL, 3) szr = wx.BoxSizer(wx.VERTICAL) szr.Add(self.orientation, 0, wx.ALL|wx.EXPAND, 4) szr.Add(tmp, 0, wx.EXPAND) CHECK_ID = wx.NewId() self.check = wx.CheckBox(self, CHECK_ID, _('Has a Static Box')) self.label = wx.TextCtrl(self, -1, "") self.label.Enable(False) wx.EVT_CHECKBOX(self, CHECK_ID, self.on_check_statbox) szr.Add(self.check, 0, wx.ALL|wx.EXPAND, 4) tmp = wx.BoxSizer(wx.HORIZONTAL) tmp.Add(wx.StaticText(self, -1, _("Label: ")), 0, wx.ALIGN_CENTER) tmp.Add(self.label, 1) szr.Add(tmp, 0, wx.ALL|wx.EXPAND, 4) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn, 0, wx.ALL|wx.ALIGN_CENTER, 10) self.SetAutoLayout(1) self.SetSizer(szr) szr.Fit(self) self.Layout() self.CenterOnScreen() def reset(self): self.orientation.SetSelection(0) self.num.SetValue(1) self.check.SetValue(0) self.label.SetValue("") self.label.Enable(False) def on_check_statbox(self, event): self.label.Enable(event.IsChecked()) # end of class SizerDialog dialog = SizerDialog(parent) dialog.ShowModal() if dialog.orientation.GetStringSelection() == _('Horizontal'): orientation = wx.HORIZONTAL else: orientation = wx.VERTICAL num = dialog.num.GetValue() _builder(parent, sizer, pos, orientation, num, dialog.check.GetValue(), dialog.label.GetValue()) dialog.Destroy() def xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditBoxSizer objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") orientation = wx.VERTICAL # default value if sizer is not None: topl = False else: topl = True if attrs['base'] == 'EditStaticBoxSizer': sz = EditStaticBoxSizer(name, parent, orientation, '', 0, topl) else: sz = EditBoxSizer(name, parent, orientation, 0, topl) if sizer is not None: if sizeritem is None: raise XmlParsingError, _("'sizeritem' object not found") sizer.add_item(sz, pos=pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(sz) sz.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) else: parent.set_sizer(sz) node = Tree.Node(sz) sz.node = node common.app_tree.add(node, parent.node) return sz def grid_builder(parent, sizer, pos, number=[1], show=True): """\ factory function for grid sizers """ class Dialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, misc.get_toplevel_parent(parent), -1, _('Select sizer attributes')) self.rows = SpinProperty(self, 'rows', self, label=_("rows")) self.cols = SpinProperty(self, 'cols', self, label=_("cols")) self.vgap = SpinProperty(self, 'vgap', self, label=_("vgap")) self.hgap = SpinProperty(self, 'hgap', self, label=_("hgap")) self.flex = wx.CheckBox(self, -1, '') self.rows.set_value(3) self.cols.set_value(3) self.vgap.set_value(0) self.hgap.set_value(0) szr = wx.BoxSizer(wx.HORIZONTAL) szr.Add(wx.StaticText(self, -1, _('Flexible')), 2, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) szr.Add(self.flex, 5, wx.ALL, 4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.rows.panel, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, 10) sizer.Add(self.cols.panel, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) sizer.Add(self.vgap.panel, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) sizer.Add(self.hgap.panel, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) sizer.Add(szr, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10) szr = wx.BoxSizer(wx.HORIZONTAL) btn = wx.Button(self, wx.ID_OK, _('OK')) btn.SetDefault() szr.Add(btn) sizer.Add(szr, 0, wx.ALL|wx.ALIGN_CENTER, 10) self.SetAutoLayout(True) self.SetSizer(sizer) sizer.Fit(self) self.Layout() self.CentreOnParent() def __getitem__(self, name): return (lambda : 0, lambda v: None) # end of inner class dialog = Dialog(parent) dialog.ShowModal() rows = int(dialog.rows.get_value()) cols = int(dialog.cols.get_value()) vgap = int(dialog.vgap.get_value()) hgap = int(dialog.hgap.get_value()) name = 'grid_sizer_%d' % number[0] while common.app_tree.has_name(name): number[0] += 1 name = 'grid_sizer_%d' % number[0] topl = True if dialog.flex.GetValue(): constructor = EditFlexGridSizer else: constructor = EditGridSizer if sizer is not None: topl = False sz = constructor(name, parent, rows, cols, vgap, hgap, topl) if sizer is not None: sizer.add_item(sz, pos, 1, wx.EXPAND) node = Tree.Node(sz) sz.node = node common.app_tree.insert(node, sizer.node, pos-1) common.adding_sizer = False else: parent.set_sizer(sz) node = Tree.Node(sz) sz.node = node if pos is None: common.app_tree.add(node, parent.node) else: common.app_tree.insert(node, parent.node, pos-1) sz.pos = pos sz.show_widget(show) #True) if sizer is not None: sz.sizer_properties['flag'].set_value('wxEXPAND') sz.sizer_properties['pos'].set_value(pos-1) dialog.Destroy() def grid_xml_builder(attrs, parent, sizer, sizeritem, pos=None): """\ factory function to build EditGridSizer objects from an xml file """ from xml_parse import XmlParsingError try: name = attrs['name'] except KeyError: raise XmlParsingError, _("'name' attribute missing") if attrs['base'] == 'EditGridSizer': constructor = EditGridSizer else: constructor = EditFlexGridSizer if sizer is not None: sz = constructor(name, parent, rows=0, cols=0, toplevel=False) if sizeritem is None: raise XmlParsingError, _("'sizeritem' object not found") sizer.add_item(sz, pos=pos, option=sizeritem.option, flag=sizeritem.flag, border=sizeritem.border) node = Tree.Node(sz) sz.node = node if pos is None: common.app_tree.add(node, sizer.node) else: common.app_tree.insert(node, sizer.node, pos-1) else: sz = constructor(name, parent, rows=0, cols=0, toplevel=True) parent.set_sizer(sz) node = Tree.Node(sz) sz.node = node common.app_tree.add(node, parent.node) return sz def init_all(): """\ module initialization function: returns a list of buttons (to add to the main palette) to add the various sizers """ cw = common.widgets cw['EditBoxSizer'] = builder cw['EditGridSizer'] = grid_builder cwx = common.widgets_from_xml cwx['EditBoxSizer'] = xml_builder cwx['EditStaticBoxSizer'] = xml_builder cwx['EditGridSizer'] = grid_xml_builder cwx['EditFlexGridSizer'] = grid_xml_builder from tree import WidgetTree import os.path WidgetTree.images['EditStaticBoxSizer'] = os.path.join(common.wxglade_path, 'icons/sizer.xpm') WidgetTree.images['EditFlexGridSizer'] = os.path.join( common.wxglade_path, 'icons/grid_sizer.xpm') return [common.make_object_button('EditBoxSizer', 'icons/sizer.xpm'), common.make_object_button('EditGridSizer', 'icons/grid_sizer.xpm')] spe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/sizers_codegen.py0000644000175000017500000002461610743421035023471 0ustar stanistani# sizers_codegen.py: code generation functions for the various wxSizerS # $Id: sizers_codegen.py,v 1.16 2007/03/27 07:02:06 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import common class PythonBoxSizerBuilder: def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn orient = obj.properties.get('orient', 'wxHORIZONTAL') init = [('%s = ' + cn('wxBoxSizer') + '(%s)\n') % \ (obj.name, cn(orient))] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' #layout.append('%s.SetAutoLayout(True)\n' % parent) layout.append('%s.SetSizer(%s)\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('%s.Fit(%s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s.SetSizeHints(%s)\n' % (obj.name, parent)) return init, [], layout # end of class PythonBoxSizerBuilder class PythonStaticBoxSizerBuilder: def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn orient = obj.properties.get('orient', 'wxHORIZONTAL') label = obj.properties.get('label', '') if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' init = [ ('self.%s_staticbox = ' + cn('wxStaticBox') + '(%s, -1, %s)\n') % (obj.name, parent, pygen.quote_str(label)), ('%s = ' + cn('wxStaticBoxSizer') + '(self.%s_staticbox, %s)\n') % (obj.name, obj.name, cn(orient)) ] layout = [] if obj.is_toplevel: #layout.append('%s.SetAutoLayout(True)\n' % parent) layout.append('%s.SetSizer(%s)\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('%s.Fit(%s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s.SetSizeHints(%s)\n' % (obj.name, parent)) return init, [], layout # end of class PythonStaticBoxSizerBuilder class PythonGridSizerBuilder: klass = 'wxGridSizer' def get_code(self, obj): pygen = common.code_writers['python'] cn = pygen.cn props = obj.properties if not obj.parent.is_toplevel: parent = 'self.%s' % obj.parent.name else: parent = 'self' rows = props.get('rows', '0') cols = props.get('cols', '0') vgap = props.get('vgap', '0') hgap = props.get('hgap', '0') init = [ '%s = %s(%s, %s, %s, %s)\n' % (obj.name, cn(self.klass), rows, cols, vgap, hgap) ] layout = [] if obj.is_toplevel: #layout.append('%s.SetAutoLayout(True)\n' % parent) layout.append('%s.SetSizer(%s)\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('%s.Fit(%s)\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s.SetSizeHints(%s)\n' % (obj.name, parent)) return init, [], layout # end of class PythonGridSizerBuilder class PythonFlexGridSizerBuilder(PythonGridSizerBuilder): klass = 'wxFlexGridSizer' def get_code(self, obj): init, p, layout = PythonGridSizerBuilder.get_code(self, obj) props = obj.properties if props.has_key('growable_rows'): for r in props['growable_rows'].split(','): layout.append('%s.AddGrowableRow(%s)\n' % (obj.name, r.strip())) if props.has_key('growable_cols'): for r in props['growable_cols'].split(','): layout.append('%s.AddGrowableCol(%s)\n' % (obj.name, r.strip())) return init, p, layout # end of class PythonFlexGridSizerBuilder class CppBoxSizerBuilder: def get_code(self, obj): """\ generates the C++ code for wxBoxSizer objects. """ orient = obj.properties.get('orient', 'wxHORIZONTAL') init = ['wxBoxSizer* %s = new wxBoxSizer(%s);\n' % (obj.name, orient)] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = '%s->' % obj.parent.name else: parent = '' #layout.append('%sSetAutoLayout(true);\n' % parent) layout.append('%sSetSizer(%s);\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size'): if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' if obj.parent.is_toplevel: layout.append('%s->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], [], layout # end of class CppBoxSizerBuilder class CppStaticBoxSizerBuilder: def get_code(self, obj): """\ generates the C++ code for wxStaticBoxSizer objects. """ cppgen = common.code_writers['C++'] orient = obj.properties.get('orient', 'wxHORIZONTAL') label = obj.properties.get('label', '') if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' init = [ '%s_staticbox = new wxStaticBox(%s, -1, %s);\n' % (obj.name, parent, cppgen.quote_str(label)), 'wxStaticBoxSizer* %s = new wxStaticBoxSizer(%s_staticbox, %s);\n' % (obj.name, obj.name, orient)] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = '%s->' % obj.parent.name else: parent = '' #layout.append('%sSetAutoLayout(true);\n' % parent) layout.append('%sSetSizer(%s);\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size'): if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' if obj.parent.is_toplevel: layout.append('%s->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], [], layout # end of class CppStaticBoxSizerBuilder class CppGridSizerBuilder: klass = 'wxGridSizer' def get_code(self, obj): props = obj.properties rows = props.get('rows', '0') cols = props.get('cols', '0') vgap = props.get('vgap', '0') hgap = props.get('hgap', '0') init = [ '%s* %s = new %s(%s, %s, %s, %s);\n' % \ (self.klass, obj.name, self.klass, rows, cols, vgap, hgap) ] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = '%s->' % obj.parent.name else: parent = '' #layout.append('%sSetAutoLayout(true);\n' % parent) layout.append('%sSetSizer(%s);\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size'): if not obj.parent.is_toplevel: parent = '%s' % obj.parent.name else: parent = 'this' if obj.parent.is_toplevel: layout.append('%s->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('%s->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], [], layout # end of class CppGridSizerBuilder class CppFlexGridSizerBuilder(CppGridSizerBuilder): klass = 'wxFlexGridSizer' def get_code(self, obj): """\ function used to generate the C++ code for wxFlexGridSizer objects. """ init, ids, p, layout = CppGridSizerBuilder.get_code(self, obj) props = obj.properties if props.has_key('growable_rows'): for r in props['growable_rows'].split(','): layout.append('%s->AddGrowableRow(%s);\n' % (obj.name, r.strip())) if props.has_key('growable_cols'): for r in props['growable_cols'].split(','): layout.append('%s->AddGrowableCol(%s);\n' % (obj.name, r.strip())) return init, ids, p, layout # end of class CppFlexGridSizerBuilder def xrc_wxFlexGridSizer_builder(obj): xrcgen = common.code_writers['XRC'] class FlexGridSizerXrcObject(xrcgen.DefaultXrcObject): def write_property(self, name, val, outfile, tabs): if val and name in ('growable_rows', 'growable_cols'): if name == 'growable_rows': name2 = 'growablerows' else: name2 = 'growablecols' outfile.write(' '*tabs + '<%s>%s\n' % (name2, val, name2)) else: xrcgen.DefaultXrcObject.write_property(self, name, val, outfile, tabs) # end of class FlexGridSizerXrcObject return FlexGridSizerXrcObject(obj) def initialize(): cn = common.class_names cn['EditBoxSizer'] = 'wxBoxSizer' cn['EditStaticBoxSizer'] = 'wxStaticBoxSizer' cn['EditGridSizer'] = 'wxGridSizer' cn['EditFlexGridSizer'] = 'wxFlexGridSizer' pygen = common.code_writers.get("python") if pygen: awh = pygen.add_widget_handler awh('wxBoxSizer', PythonBoxSizerBuilder()) awh('wxStaticBoxSizer', PythonStaticBoxSizerBuilder()) awh('wxGridSizer', PythonGridSizerBuilder()) awh('wxFlexGridSizer', PythonFlexGridSizerBuilder()) cppgen = common.code_writers.get("C++") if cppgen: awh = cppgen.add_widget_handler awh('wxBoxSizer', CppBoxSizerBuilder()) awh('wxStaticBoxSizer', CppStaticBoxSizerBuilder()) awh('wxGridSizer', CppGridSizerBuilder()) awh('wxFlexGridSizer', CppFlexGridSizerBuilder()) xrcgen = common.code_writers.get("XRC") if xrcgen: xrcgen.add_widget_handler('wxFlexGridSizer', xrc_wxFlexGridSizer_builder) spe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/perl_sizers_codegen.py0000644000175000017500000001170410743421035024505 0ustar stanistani# perl_sizers_codegen.py : perl generator functions for the various wxSizerS # $Id: perl_sizers_codegen.py,v 1.7 2006/12/02 11:20:29 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # import common class PerlBoxSizerBuilder: def get_code(self, obj): orient = obj.properties.get('orient', 'wxHORIZONTAL') init = [ '$self->{%s} = Wx::BoxSizer->new(%s);\n' % (obj.name, orient) ] layout = [] if obj.is_toplevel: if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' #layout.append('%s->SetAutoLayout(1);\n' % parent) layout.append('%s->SetSizer($self->{%s});\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('$self->{%s}->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('$self->{%s}->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], layout # end of class PerlBoxSizerBuilder class PerlStaticBoxSizerBuilder: def get_code(self, obj): plgen = common.code_writers['perl'] orient = obj.properties.get('orient', 'wxHORIZONTAL') label = obj.properties.get('label', '') if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' init = [ '$self->{%s_staticbox} = Wx::StaticBox->new(%s, -1, %s );\n' % (obj.name, parent, plgen.quote_str(label)), # this get '$self->{%s}= Wx::StaticBoxSizer->new($self->{%s_staticbox}, %s);\n' % (obj.name,obj.name, orient) ] layout = [] if obj.is_toplevel: #layout.append('%s->SetAutoLayout(1);\n' % parent) layout.append('%s->SetSizer($self->{%s});\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('$self->{%s}->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('$self->{%s}->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], layout # end of class PerlStaticBoxSizerBuilder class PerlGridSizerBuilder: klass = 'Wx::GridSizer' def get_code(self, obj): props = obj.properties if not obj.parent.is_toplevel: parent = '$self->{%s}' % obj.parent.name else: parent = '$self' rows = props.get('rows', '0') cols = props.get('cols', '0') vgap = props.get('vgap', '0') hgap = props.get('hgap', '0') init = [ '$self->{%s} = %s->new(%s, %s, %s, %s);\n' % (obj.name, self.klass.replace('wx','Wx::',1), rows, cols, vgap, hgap) ] layout = [] if obj.is_toplevel: #layout.append('%s->SetAutoLayout(1);\n' % parent) layout.append('%s->SetSizer($self->{%s});\n' % (parent, obj.name)) if not obj.parent.properties.has_key('size') and \ obj.parent.is_toplevel: layout.append('$self->{%s}->Fit(%s);\n' % (obj.name, parent)) if obj.parent.properties.get('sizehints', False): layout.append('$self->{%s}->SetSizeHints(%s);\n' % (obj.name, parent)) return init, [], layout # end of class PerlGridSizerBuilder class PerlFlexGridSizerBuilder(PerlGridSizerBuilder): klass = 'Wx::FlexGridSizer' def get_code(self, obj): init, p, layout = PerlGridSizerBuilder.get_code(self, obj) props = obj.properties if props.has_key('growable_rows'): for r in props['growable_rows'].split(','): layout.append('$self->{%s}->AddGrowableRow(%s);\n' % (obj.name, r.strip())) if props.has_key('growable_cols'): for r in props['growable_cols'].split(','): layout.append('$self->{%s}->AddGrowableCol(%s);\n' % (obj.name, r.strip())) return init, p, layout # end of class PerlFlexGridSizerBuilder def initialize(): cn = common.class_names cn['EditBoxSizer'] = 'wxBoxSizer' cn['EditStaticBoxSizer'] = 'wxStaticBoxSizer' cn['EditGridSizer'] = 'wxGridSizer' cn['EditFlexGridSizer'] = 'wxFlexGridSizer' plgen = common.code_writers.get("perl") if plgen: awh = plgen.add_widget_handler awh('wxBoxSizer', PerlBoxSizerBuilder()) awh('wxStaticBoxSizer', PerlStaticBoxSizerBuilder()) awh('wxGridSizer', PerlGridSizerBuilder()) awh('wxFlexGridSizer', PerlFlexGridSizerBuilder()) spe-0.8.4.h/_spe/plugins/wxGlade/edit_sizers/__init__.py0000644000175000017500000000120510743421035022212 0ustar stanistani# __init__.py: sizers module initialization # $Id: __init__.py,v 1.10 2007/03/27 07:02:06 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY def init_all(): import sizers_codegen sizers_codegen.initialize() import common if common.use_gui: import edit_sizers global Sizer, SizerSlot, SizerBase, _builder Sizer = edit_sizers.Sizer SizerSlot = edit_sizers.SizerSlot SizerBase = edit_sizers.SizerBase _builder = edit_sizers._builder return edit_sizers.init_all() spe-0.8.4.h/_spe/plugins/wxGlade/res/messagedialog.wxg0000644000175000017500000000605510743421035021711 0ustar stanistani wxGlade message 1 250, 112d wxVERTICAL wxALL|wxALIGN_CENTER_HORIZONTAL 5 1 -1 default bold 0 wxLEFT|wxRIGHT|wxEXPAND 5 wxHORIZONTAL wxALIGN_CENTER_HORIZONTAL 0 1 code:wx.ArtProvider_GetBitmap(wx.ART_TIP, wx.ART_MESSAGE_BOX, (48, 48)) 48, 48 wxLEFT|wxEXPAND 10 wxALL|wxALIGN_RIGHT 10 OK spe-0.8.4.h/_spe/plugins/wxGlade/res/preferences.wxg0000644000175000017500000005230110743421035021401 0ustar stanistani import common\nimport os\n\n_icon_path = os.path.join(common.wxglade_path, 'icons', 'icon.xpm')\n var:_icon_path wxGlade: preferences 1 wxVERTICAL wxALL|wxEXPAND 5 Interface Other wxVERTICAL wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxEXPAND 3 0 4 1 2 0 wxALL|wxALIGN_CENTER_VERTICAL 5 0 wxALL|wxALIGN_CENTER_VERTICAL 5 196, -1 wxALL|wxALIGN_CENTER_VERTICAL 5 0 wxALL|wxALIGN_CENTER_VERTICAL 5 196, -1 wxALL|wxALIGN_CENTER_VERTICAL 5 0 wxALL|wxALIGN_CENTER_VERTICAL 5 0, 100 4 196, -1 wxALL|wxALIGN_CENTER_VERTICAL 5 0 wxALL|wxALIGN_CENTER_VERTICAL 5 1, 100 5 196, -1 wxVERTICAL wxALL|wxEXPAND 5 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 5 wxALL 5 0, 20 45, 22 wxEXPAND 0 wxHORIZONTAL wxLEFT|wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL 5 wxTOP|wxBOTTOM 5 30, 300 120 45, 22 wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE 5 0 wxALL|wxEXPAND 5 1 wxALL|wxEXPAND 5 wxALL|wxEXPAND 5 0 2 append ~ to filename append .bak to filename wxALL|wxEXPAND 5 wxHORIZONTAL wxALL 3 wxALL|wxALIGN_CENTER_VERTICAL 3 wxALL|wxALIGN_RIGHT 10 wxHORIZONTAL 0 OK 1 wxLEFT 10 CANCEL spe-0.8.4.h/_spe/plugins/wxGlade/res/templates_ui.wxg0000644000175000017500000003504210743421035021576 0ustar stanistani wxGlade template information 1 250, 265d wxVERTICAL wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 10 0 -1 default bold 0 wxALL|wxALIGN_CENTER_VERTICAL 10 wxALL|wxEXPAND 5 wxHORIZONTAL 0 wxALL|wxEXPAND 5 wxHORIZONTAL wxEXPAND 0 wxALL|wxEXPAND 5 wxHORIZONTAL wxEXPAND 0 wxALL|wxALIGN_RIGHT 10 wxHORIZONTAL 0 OK wxLEFT 10 CANCEL wxGlade template list 1 300, 200d wxVERTICAL wxEXPAND 0 wxHORIZONTAL wxALL|wxEXPAND 5 wxVERTICAL wxALL|wxEXPAND 3 0 on_select_template on_open wxEXPAND 0 wxVERTICAL wxALL|wxALIGN_CENTER_VERTICAL 7 1 -1 default bold 0 wxALL|wxEXPAND 5 wxHORIZONTAL 0 wxALL|wxEXPAND 5 wxHORIZONTAL wxEXPAND 0 wxALL|wxEXPAND 5 wxHORIZONTAL wxEXPAND 0 wxALL|wxALIGN_RIGHT 10 wxHORIZONTAL 0 OPEN on_open wxLEFT 10 try:\n ID_EDIT = wx.ID_EDIT\nexcept AttributeError:\n ID_EDIT = wx.NewId()\n ID_EDIT on_edit wxLEFT 10 DELETE on_delete wxLEFT 10 CANCEL spe-0.8.4.h/_spe/plugins/wxGlade/icons/radio_button.xpm0000644000175000017500000000122210743421035022106 0ustar stanistani/* XPM */ static char * radio_button_xpm[] = { "21 21 5 1", " c None", ". c #848284", "+ c #000000", "@ c #FFFFFF", "# c #C6C3C6", " ", " ", " ", " ", " .... ", " ..++++.. ", " .++@@@@++@ ", " .+@@@@@@#@ ", " .+@@@++@@@#@ ", " .+@@++++@@#@ ", " .+@@++++@@#@ ", " .+@@@++@@@#@ ", " .+@@@@@@#@ ", " .##@@@@##@ ", " @@####@@ ", " @@@@ ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/combo_box.xpm0000644000175000017500000000121710743421035021370 0ustar stanistani/* XPM */ static char * combo_box_xpm[] = { "21 21 5 1", " c None", ". c #848284", "+ c #000000", "@ c #C6C3C6", "# c #FFFFFF", " ", " ", ".....................", ".+++++++++++++++++++@", ".+#####@@@@@@@@@@@@+@", ".+#####@##########.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@#@++++++.@.+@", ".+#####@#@@++++.@@.+@", ".+#####@#@@@++.@@@.+@", ".+#####@#@@@@.@@@@.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@#@@@@@@@@@.+@", ".+#####@...........+@", ".+#####+++++++++++++@", ".@@@@@@@@@@@@@@@@@@@@", "#####################", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/tree_ctrl.xpm0000644000175000017500000000123610743421035021405 0ustar stanistani/* XPM */ static char * tree_ctrl_xpm[] = { "21 21 6 1", " c None", ". c #000000", "+ c #00FFFF", "@ c #7B797B", "# c #FFFF00", "$ c #00FF00", " ... ", " .+. @@@@@@ ", " ... ", " . ", " . ... ", " ....#. @@@@@@ ", " . ... ", " . . ", " . . ... ", " . ....$. @@@@@@ ", " . . ... ", " . . ", " . . ... ", " . ....$. @@@@@@ ", " . ... ", " . ", " . ... ", " ....#. @@@@@@ ", " ... ", " . ", " . "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/sizer.xpm0000644000175000017500000000161310743421035020555 0ustar stanistani/* XPM */ static char * sizer_xpm[] = { "21 21 22 1", " c None", ". c #FFFFFF", "+ c #F0F0F0", "@ c #0F0F0F", "# c #D8D8D8", "$ c #D9D9D9", "% c #7A7A7A", "& c #030303", "* c #D7D7D7", "= c #010101", "- c #0C0C0C", "; c #000000", "> c #020202", ", c #0A0A0A", "' c #060606", ") c #050505", "! c #040404", "~ c #0B0B0B", "{ c #070707", "] c #DADADA", "^ c #D6D6D6", "/ c #0D0D0D", "...................+@", ".###$$$$$$$$#######%&", ".#############*####%=", ".##################%-", ".##################%;", ".%%%%%%%%%%%%%%%%%%%;", ">;,;========',;;;;>>'", "...................+;", ".##################%)", ".##################%)", ".##################%;", ".##################%;", ".%%%%%%%%%%%%%%%%%%%!", ");~;;;;;;;;;&;{&;>;=;", "...................+!", ".##################%;", ".##############]###%>", ".###^^^^^##########%>", ".##################%;", ".%%%%%%%%%%%%%%%%%%%!", ";;/;;;;;;;;;>;'>;=;;;"}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/panel.xpm0000644000175000017500000000213510743421035020520 0ustar stanistani/* XPM */ static char * panel_xpm[] = { "21 21 36 1", " c None", ". c #FFFFFF", "+ c #FBFBFB", "@ c #F8F8F8", "# c #000000", "$ c #F5F5F5", "% c #D7D7D7", "& c #D1D1D1", "* c #777777", "= c #0C0C0C", "- c #FDFDFD", "; c #D2D2D2", "> c #CECECE", ", c #181818", "' c #D6D6D6", ") c #D8D8D8", "! c #FCFCFC", "~ c #DBDBDB", "{ c #D0D0D0", "] c #0B0B0B", "^ c #090909", "/ c #DADADA", "( c #080808", "_ c #191919", ": c #D9D9D9", "< c #D4D4D4", "[ c #0A0A0A", "} c #F1F1F1", "| c #F3F3F3", "1 c #D5D5D5", "2 c #0D0D0D", "3 c #0F0F0F", "4 c #060606", "5 c #020202", "6 c #101010", "7 c #040404", ".+........@.........#", "$%%%%%%%%%%%%%%%%%&*=", "-%%%%%%%%%%%%%%%%%;*#", ".%%%%%%%%%%%%%%%%%>*,", ".%'%%%%%%%%%%%%%%);*#", "!%)%%%%%%%%%%%%%%~{*]", ".%%%%%%%%%%%%%)%%~%*^", "-%'%%%%%%%%%%%%%%%/*#", "+%%%%%%%%%%%%%%%%'&*#", ".%%%%%%%%%%%%%%%%%%*(", ".%%%%%%%%%%%%%%%%%%*#", "+%%%%%%%%%%%%%%%%%{*_", ".%%%%%%%%%%:%%%%%%<*#", "@%%%%%%%%%%%%%%%%%'*[", ".%%%%%%%%%%%%%%%%%'*#", "}%%%%%%%%%%%%%%%%%~*#", ".%%%%%%%%%%%%%%%%%~*#", ".%%%%%%%%%%%%%%%%%%*#", "|%%%%%%%%%%%%%%%1%%*2", ".*******************3", "##[^#45#6#4###5#7#4=#"}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/static_line.xpm0000644000175000017500000000160210743421035021715 0ustar stanistani/* XPM */ static char * static_line_xpm[] = { "21 21 21 1", " c None", ". c #D5D5D5", "+ c #BFBFBF", "@ c #939393", "# c #787878", "$ c #747474", "% c #7A7A7A", "& c #777777", "* c #7C7C7C", "= c #757575", "- c #818181", "; c #737373", "> c #919191", ", c #CACACA", "' c #E8E8E8", ") c #F5F5F5", "! c #FEFEFE", "~ c #FFFFFF", "{ c #FDFDFD", "] c #FAFAFA", "^ c #F3F3F3", " ", " ", " ", " ", " ", " ", " ", " ", " ", ".....................", "+@#$%%&********=-*;>,", "')!~~!{~~~~~~~~{!!]^'", ".....................", " ", " ", " ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/spin_ctrl.xpm0000644000175000017500000000217710743421035021424 0ustar stanistani/* XPM */ static char * spin_ctrl_xpm[] = { "21 21 38 1", " c None", ". c #000000", "+ c #060608", "@ c #000002", "# c #020202", "$ c #010101", "% c #080808", "& c #131313", "* c #FFFFFF", "= c #F7F7F7", "- c #FDFDFD", "; c #EBEBEB", "> c #FCFCFC", ", c #D4D4D4", "' c #070707", ") c #CFCFCF", "! c #8F8F8F", "~ c #FBFBFB", "{ c #040404", "] c #050505", "^ c #7C7C7C", "/ c #0C0C0C", "( c #090909", "_ c #111111", ": c #6B6B6B", "< c #0B0B0B", "[ c #0A0A0A", "} c #F6F6F6", "| c #FEFEFE", "1 c #030303", "2 c #CDCDCD", "3 c #BFBFBF", "4 c #737373", "5 c #787878", "6 c #838383", "7 c #797979", "8 c #828282", "9 c #888888", " ", " ", " ", " ", " ", " ", " .+.@.@.@.@.#$.#%... ", " &**********=.-*;>*# ", " .**--------*#>,')!. ", " .**********~.*.{]^$ ", " $**********-/**=**. ", " %**---------.*.(_:< ", " [}|*********1*2.34[ ", " .*|*********.56789. ", " {<.$$$$$$$$$$$$$$$$ ", " ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/splitter_window.xpm0000644000175000017500000000177610743421035022670 0ustar stanistani/* XPM */ static char * splitter_window_xpm[] = { "21 21 29 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #FEFEFE", "# c #FBFBFB", "$ c #FCFCFC", "% c #0D0D0D", "& c #D6D6D6", "* c #7A7A7A", "= c #7C7C7C", "- c #D7D7D7", "; c #D5D5D5", "> c #020202", ", c #7D7D7D", "' c #DADADA", ") c #D3D3D3", "! c #7E7E7E", "~ c #161616", "{ c #F2F2F2", "] c #D9D9D9", "^ c #787878", "/ c #797979", "( c #D8D8D8", "_ c #F8F8F8", ": c #121212", "< c #050505", "[ c #111111", "} c #090909", "| c #080808", "..........+......@#$%", "$&&&&&&&&*+.&&&&&&&*+", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;-&--&*>", "@&&&&&&&&=+@-;&&--&*>", "@&&&&&&&-,+.&&&&'-&*>", "@&&&&&&&)!~{&&&&&-&*>", "@&&&&&&=====&&&&&-&*>", "@&&&&&&=...==&&&;-&*>", "@&&&&&&=$..==&'&&-&*>", "@&&&&&&=...==&;&&-&*>", "@&&&&&&======&&&&-&*>", "@]&&&&&&^====&&&&&&*>", ".&&&&&&&&/>.&&&&&&(*+", ".=========+_========:", "++++++++++<+[++}|%++>"}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/icon.xpm0000644000175000017500000000250010743421035020345 0ustar stanistani/* XPM */ static char *mondrian_xpm[] = { /* columns rows colors chars-per-pixel */ "32 32 6 1", " c Black", ". c Blue", "X c #00bf00", "o c Red", "O c Yellow", "+ c Gray100", /* pixels */ " ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " oooooo +++++++++++++++++++++++ ", " ", " ++++++ ++++++++++++++++++ .... ", " ++++++ ++++++++++++++++++ .... ", " ++++++ ++++++++++++++++++ .... ", " ++++++ ++++++++++++++++++ .... ", " ++++++ ++++++++++++++++++ .... ", " ++++++ ++++++++++++++++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++++++++++++++++ ++++ ", " ++++++ ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " ++++++ OOOOOOOOOOOO XXXXX ++++ ", " " }; spe-0.8.4.h/_spe/plugins/wxGlade/icons/bitmap_button.xpm0000644000175000017500000000237310743421035022274 0ustar stanistani/* XPM */ static char * bitmap_button_xpm[] = { "21 21 46 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #D6D6D6", "# c #7B7B7B", "$ c #40FFFF", "% c #7FFFFF", "& c #60FFFF", "* c #38F7F7", "= c #C2E2E2", "- c #C6E6E6", "; c #00FFFF", "> c #2ECECE", ", c #20FFFF", "' c #30FFFF", ") c #2AF9F9", "! c #A6E6E6", "~ c #BECD3E", "{ c #8FFFFF", "] c #1FAEAE", "^ c #36C5C5", "/ c #2ECDCD", "( c #BECE3E", "_ c #4D4D4D", ": c #8ECECE", "< c #4ECDCD", "[ c #009F9F", "} c #172727", "| c #1F1F1F", "1 c #10FFFF", "2 c #008080", "3 c #A0A0A0", "4 c #AEAEDE", "5 c #00BD80", "6 c #005F40", "7 c #8686E5", "8 c #00DE00", "9 c #006F00", "0 c #3636F5", "a c #00FF00", "b c #008000", "c c #787878", "d c #7878A8", "e c #0000BF", "f c #00BF00", "g c #007F00", " ", " ", " ", " ..................+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@$%&*=-$&;;>>;@@#+ ", " .@,$';)!;';>~~>@@#+ ", " .@;{{;;]#^'/((/@@#+ ", " .@$;;;>_##:;/<$@@#+ ", " .@,;;[}|||}[;1,@@#+ ", " .@;;;234@432;;;@@#+ ", " .@555637@736555@@#+ ", " .@8889340439888@@#+ ", " .@aaabcdedcbaaa@@#+ ", " .@aaafgggggfaaa@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .#################+ ", " +++++++++++++++++++ ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/calendar_ctrl.xpm0000644000175000017500000000130010743421035022207 0ustar stanistani/* XPM */ static char * calendar_ctrl_xpm[] = { "21 21 8 1", " c None", ". c #000000", "+ c #BFBFBF", "@ c #FEFEFE", "# c #8E8ED1", "$ c #FFFFFF", "% c #FF8080", "& c #FFF1F1", " ", " ", ".....................", ".+++++++++++++++++++.", ".+@@++@@+++++@@@@@@+.", ".+++++++++++++++++++.", ".....................", ".###################.", ".$$$$$$$$$$$$$$$$$$$.", ".$$$$$##$$##$$##$%%$.", ".$$$$$##$$##$$##$%%$.", ".$$$$$$$$$$$$$$$$$&$.", ".$##$$##$$##$$##$%%$.", ".$##$$##$$##$$##$%%$.", ".$$$$$$$$$$$$$$$$$$$.", ".$##$$##$$##$$##$$$$.", ".$##$$##$$##$$##$$$$.", ".$$$$$$$$$$$$$$$$$$$.", ".....................", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/static_text.xpm0000644000175000017500000000137310743421035021757 0ustar stanistani/* XPM */ static char * static_text_xpm[] = { "21 21 12 1", " c None", ". c #040603", "+ c #010002", "@ c #040005", "# c #0A050C", "$ c #060005", "% c #000000", "& c #020202", "* c #0E0E0E", "= c #030303", "- c #010101", "; c #050505", " ", " ", " ", " . ", " .+. ", " .@# ", " $.@.. ", " ..... ", " .%%... ", " %. &... ", " .* &%%.= ", " %. ..... ", " .........- ", " ..=........ ", " .. ...%. ", " ... ..... ", " %..% %..... ", " ;=.%% ....... ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/grid_sizer.xpm0000644000175000017500000000154310743421035021564 0ustar stanistani/* XPM */ static char * grid_sizer_xpm[] = { "21 21 19 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #D8D8D8", "# c #7B7B7B", "$ c #060606", "% c #0A0A0A", "& c #141414", "* c #FBFBFB", "= c #7A7A7A", "- c #0E0E0E", "; c #040404", "> c #010101", ", c #0B0B0B", "' c #101010", ") c #050505", "! c #030303", "~ c #080808", "{ c #020202", "..........+.........+", ".@@@@@@@@#$.@@@@@@@#%", ".@@@@@@@@#+.@@@@@@@#+", ".@@@@@@@@#&.@@@@@@@#%", ".@@@@@@@@#+.@@@@@@@#+", "*==#######+.########-", ";>>>>>>>>+,+;$$>++;+,", "..........+.........+", ".@@@@@@@@#'.@@@@@@@#)", ".@@@@@@@@#+.@@@@@@@#+", ".@@@@@@@@#!.@@@@@@@#+", ".@@@@@@@@#+.@@@@@@@#~", ".#########+.########+", ";++++++++-+{~++;+!!++", "..........+.........'", ".@@@@@@@@#;.@@@@@@@#;", ".@@@@@@@@#{.@@@@@@@#+", ".@@@@@@@@#$.@@@@@@@#+", ".@@@@@@@@#%.@@@@@@@#%", ".#########+.########+", ";+++++++++;!+{+++{)++"}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/toolbar.xpm0000644000175000017500000000123410743421035021062 0ustar stanistani/* XPM */ static char * toolbar_xpm[] = { "21 21 6 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #DEDEDE", "# c #7B7B7B", "$ c #D6D6D6", " ", " ", " ", " ", " ..................+ ", " .@@@@#$$$$$$$$$$$#+ ", " ..@@@#$$$$$$$$$$$#+ ", " .@#.@#$$$$$$$$$$$#+ ", " .@@@##$$$$$$$$$$$#+ ", " ..@@@#$$$$$$$$$$$#+ ", " .@#.@#$$$$$$$$$$$#+ ", " .@@@##$$$$$$$$$$$#+ ", " ..@@@#$$$$$$$$$$$#+ ", " .@#.@#$$$$$$$$$$$#+ ", " .@@@##$$$$$$$$$$$#+ ", " .#################+ ", " +++++++++++++++++++ ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/spacer.xpm0000644000175000017500000000115610743421035020700 0ustar stanistani/* XPM */ static char * spacer_xpm[] = { "21 21 3 1", " c None", ". c #000000", "+ c #929292", " ", " ", " ", " ", " ", " ", " . . ", " .+ .+ ", " .+ . . .+ ", " .+ .. .. .+ ", " .+.............. .+ ", " .+ ..++++++++..++.+ ", " .+ .+ .++ .+ ", " .+ + + .+ ", " .+ .+ ", " + + ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/list_box.xpm0000644000175000017500000000123510743421035021244 0ustar stanistani/* XPM */ static char * list_box_xpm[] = { "21 21 6 1", " c None", ". c #848284", "+ c #000000", "@ c #FFFFFF", "# c #C6C3C6", "$ c #000084", " ", "...............++++++", ".@@@@@@@@@@@@@@+@@@#+", ".@@@$$$$$$$$$@@+@..#+", ".@@@@@@@@@@@@@@+@++#+", ".@@@$$$$$$$$@@@+####+", ".@@@@@@@@@@@@@@++++++", ".@@@$$$$$$$$$@@+@#@#+", ".@@@@@@@@@@@@@@+#@#@+", ".@@@$$$$$$$$@@@+@#@#+", ".$$$$$$$$$$$$$$+#@#@+", ".$$$@@@@@@@@@$$+@#@#+", ".$$$$$$$$$$$$$$+#@#@+", ".@@@$$$$$$$$@@@+@#@#+", ".@@@@@@@@@@@@@@++++++", ".@@@$$$$$$$$$@@+@@@#+", ".@@@@@@@@@@@@@@+@++#+", ".@@@$$$$$$$$@@@+@..#+", ".@@@@@@@@@@@@@@+####+", ".++++++++++++++++++++", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/text_ctrl.xpm0000644000175000017500000000121710743421035021431 0ustar stanistani/* XPM */ static char * text_ctrl_xpm[] = { "21 21 5 1", " c None", ". c #7B7B7B", "+ c #FFFFFF", "@ c #000000", "# c #D6D6D6", " ", " ", "....................+", ".@@@@@@@@@@@@@@@@@@#+", ".@+++++++++++++++++#+", ".@+++++++++++++++@+#+", ".@++++++++@++++++@+#+", ".@++++++++@++++++@+#+", ".@+++@@@++@#@@+++@+#+", ".@++@#+#@+@@+.@++@+#+", ".@++++++@+@+++@++@+#+", ".@+++@@@@+@+++@++@+#+", ".@++@#++@+@+++@++@+#+", ".@++@#++@+@++.@++@+#+", ".@+++@@@@+@@@@+++@+#+", ".@+++++++++++++++@+#+", ".@+++++++++++++++++#+", ".###################+", "+++++++++++++++++++++", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/grid.xpm0000644000175000017500000000127610743421035020353 0ustar stanistani/* XPM */ static char * C:\devel\wxGlade\icons\grid_xpm[] = { "21 21 5 1", " c None", ". c #000000", "+ c #6C77B5", "@ c #C9C7C7", "# c #FFFFFF", ".....................", ".++++@++++@++++@++++.", ".++++@++++@++++@++++.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", ".++++@####@####@####.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", ".++++@####@####@####.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", ".++++@####@####@####.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", ".++++@####@####@####.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", ".++++@####@####@####.", ".@@@@@@@@@@@@@@@@@@@.", ".++++@####@####@####.", "....................."}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gauge.xpm0000644000175000017500000000123210743421035020506 0ustar stanistani/* XPM */ static char * gauge_xpm[] = { "21 21 6 1", " c None", ". c #7B7B7B", "+ c #FFFFFF", "@ c #000000", "# c #D6D6D6", "$ c #DEDEDE", " ", " ", " ", " ", " ", " .................. ", " .++++++.@########+ ", " .+$$$$$.@########+ ", " .+$$$$$.@########+ ", " .+$$$$$.@########+ ", " .+$$$$$.@########+ ", " .+$$$$$.@########+ ", " ........@########+ ", " .@@@@@@@@########+ ", " ++++++++++++++++++ ", " ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/icon16.xpm0000644000175000017500000000403310743421035020517 0ustar stanistani/* XPM */ static char *icon16[] = { /* columns rows colors chars-per-pixel */ "16 16 80 1", " c #0FA60FA65779", ". c #000000007D41", "X c #29D529D569D5", "o c #0FA645720000", "O c #00005D210000", "+ c #00006D620000", "@ c #13F6696413F6", "# c #1BE37CC30000", "$ c #1B267D901C18", "% c #29D559C51BE3", "& c #509B00000000", "* c #57790FA60FA6", "= c #7D4100000000", "- c #7D427D420000", "; c #80007DF20000", ": c #47D347D35779", "> c #47D3538C47D3", ", c #577947D347D3", "< c #5779577947D3", "1 c #509B509B509B", "2 c #5EED50FC50FC", "3 c #5BE35BE369D5", "4 c #7D4280008000", "5 c #800080007D41", "6 c #000000008FA6", "7 c #1BE31BE38B7F", "8 c #1BE31BE39BE3", "9 c #1B461B469F30", "0 c #00000000E42C", "q c blue", "w c #0000A78C0000", "e c #0000A7F50000", "r c #0000C4C10000", "t c #0000C5390000", "y c #8000951B8000", "u c #8FA600000000", "i c #87ED18511851", "p c #915400000000", "a c #9BE31BE31BE3", "s c #E1D400000000", "d c red", "f c #8FA68FA60000", "g c #8604860413F6", "h c #8DF18C1D1BE3", "j c #90B590B50000", "k c #9BE39BE31BE3", "l c #9CEF9CEF1BFE", "z c #9BE39BE38000", "x c #DF38DF380000", "c c #E41CE0680000", "v c yellow", "b c #87ED88768876", "n c #83098D7B8309", "m c #8DF18DF18B7F", "M c #8FA68FA68FA6", "N c #820A820A9EC8", "B c #9DB581648164", "V c #90FB90FB8309", "C c #911E911E911E", "Z c #915591559264", "A c #940B9341940B", "S c #9851985198D9", "D c #98D9987398D9", "F c #9BE39BE39BE3", "G c #9CEF9CEF9CEF", "H c #C203C203C65F", "J c #C2A3C6E7C6E7", "K c #C65FC31BC65F", "L c #DF40DF40DF41", "P c #E0DEE0DEE0DE", "I c #DF58DF5CE41C", "U c #E0DEE0DEE5CB", "Y c #DF38E41CE41C", "T c #E41CE41CDF88", "R c #E1AAE1AAE121", "E c #E394E1BFE41C", "W c #E394E394E122", "Q c #E5D4E211E5CB", "! c #E6CCE6CCE1C2", "~ c gray100", /* pixels */ "&pp*4CMMMMMMMMC1", "uddaY~~~~~~~~~~M", "uddaY~~~~~~~~~~M", "=ssiJPLLLLLLLTT4", ",BB2bGFFFFFGmX9 ", "M~~FL~~~~~~~T8q6", "M~~FL~~~~~~~T70.", "M~~FL~~~~~~~P3N:", "M~~GL~~~~~~~LF~M", "M~~DL~~~~~~~LF~M", "M~~DL~~~~~~~LF~M", "M~~SHIIIIIEQKF~M", "M~~Vgkkklh%w@n~M", "M~~zxvvvvc#twy~M", "M~~zcvvvvc#een~M", "1ZZ<-ffjg;o++>C1" }; spe-0.8.4.h/_spe/plugins/wxGlade/icons/closed_folder.xpm0000644000175000017500000000072510743421035022230 0ustar stanistani/* XPM */ static char * closed_folder_xpm[] = { "16 16 6 1", " c None", ". c #808080", "+ c #FFFF00", "@ c #C0C0C0", "# c #FFFFFF", "$ c #000000", " ", " ", " ..... ", " .+@+@+. ", " .+@+@+@+...... ", " .############.$", " .#+@+@+@+@+@+.$", " .#@+@+@+@+@+@.$", " .#+@+@+@+@+@+.$", " .#@+@+@+@+@+@.$", " .#+@+@+@+@+@+.$", " .#@+@+@+@+@+@.$", " .#+@+@+@+@+@+.$", " ..............$", " $$$$$$$$$$$$$$", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/application.xpm0000644000175000017500000000124010743421035021720 0ustar stanistani/* XPM */ static char * application_xpm[] = { "21 21 6 1", " c None", ". c #848284", "+ c #000084", "@ c #C6C3C6", "# c #000000", "$ c #FFFFFF", " ", " ", " ............. ", " .+++++++++++@# ", " .+++++++++++@# ", " .$$$$$$$$$$$@# ", " .............$$@# ", " .+++++++++++@#$@# ", " .+++++++++++@#$@# ", " .$$$$$$$$$$$@#$@# ", " .$$$$$$$$$$$@#$@# ", " .$$$$$$$$$$$@#$@# ", " .$$$$$$$$$$$@#@@# ", " .$$$$$$$$$$$@#### ", " .$$$$$$$$$$$@# ", " .$$$$$$$$$$$@# ", " .@@@@@@@@@@@@# ", " ############# ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/checkbox.xpm0000644000175000017500000000121610743421035021206 0ustar stanistani/* XPM */ static char * checkbox_xpm[] = { "21 21 5 1", " c None", ". c #848284", "+ c #FFFFFF", "@ c #000000", "# c #C6C3C6", " ", " ", " ", " ", " ............+ ", " .@@@@@@@@@@#+ ", " .@+++++++++#+ ", " .@+++++++@+#+ ", " .@++++++@@+#+ ", " .@+@+++@@@+#+ ", " .@+@@+@@@++#+ ", " .@+@@@@@+++#+ ", " .@++@@@++++#+ ", " .@+++@+++++#+ ", " .@+++++++++#+ ", " .###########+ ", " +++++++++++++ ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/datepicker_ctrl.xpm0000644000175000017500000000166310743421035022565 0ustar stanistani/* XPM */ static char * datepicker_ctrl_xpm[] = { "21 21 24 1", " c None", ". c #000000", "+ c #060608", "@ c #000002", "# c #020202", "$ c #010101", "% c #080808", "& c #131313", "* c #FFFFFF", "= c #F7F7F7", "- c #FDFDFD", "; c #FCFCFC", "> c #787878", ", c #C6C3C6", "' c #FBFBFB", ") c #0C0C0C", "! c #090909", "~ c #BFBFBF", "{ c #0B0B0B", "] c #0A0A0A", "^ c #F6F6F6", "/ c #030303", "( c #FEFEFE", "_ c #040404", " ", " ", " ", " ", " ", " ", ".+.@..@.@.@#$$.#%....", "&**********=.--**;;>#", ".**----.---*#-,,,,,>.", ".******.***'.-,...,>$", "$******.***-)-,,!,,>.", "%**---.-----.-,,,~,>{", "]^...*.*...*/-,,,,,>]", ".*(*********.>>>>>>>.", "_{.$$$$$$$$$$$$$$$$$$", " ", " ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/wxglade.ico0000644000175000017500000000137610743421035021030 0ustar stanistani ( @𻻻""𻻻""𻻻""𻻻""𻻻""𻻻""     spe-0.8.4.h/_spe/plugins/wxGlade/icons/spinbtn.xpm0000644000175000017500000000131210743421035021072 0ustar stanistani/* XPM */ static char * spinbtn_xpm[] = { "21 21 7 1", " c None", ". c #141414", "+ c #D6D6D6", "@ c #D4D4D4", "# c #000000", "$ c #0A0A0A", "% c #0D0D0D", " ", " ", " ", " ........... ", " .+++@+@+++. ", " .++++#++++. ", " .+++...+++. ", " .++.....++. ", " .+.......+. ", " .+++++++++. ", " ........... ", " $+++++++++$ ", " .+.......+. ", " .++.....++. ", " .+++...+++. ", " .++++.++++. ", " .+++++++++. ", " #%%%%%%%%%# ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/statusbar.xpm0000644000175000017500000000302410743421035021427 0ustar stanistani/* XPM */ static char * statusbar_xpm[] = { "21 21 65 1", " c None", ". c #F7F7F7", "+ c #DBDBDB", "@ c #D6D6D6", "# c #8D8D8D", "$ c #FDFDFD", "% c #DADADA", "& c #D4D4D4", "* c #737373", "= c #FEFEFE", "- c #808080", "; c #7A7A7A", "> c #FFFFFF", ", c #FAFAFA", "' c #F2F2F2", ") c #F9F9F9", "! c #F5F5F5", "~ c #D5D5D5", "{ c #DEDEDE", "] c #D8D8D8", "^ c #D9D9D9", "/ c #D2D2D2", "( c #DCDCDC", "_ c #C9C9C9", ": c #D1D1D1", "< c #D0D0D0", "[ c #D7D7D7", "} c #CFCFCF", "| c #E0E0E0", "1 c #888888", "2 c #727272", "3 c #7E7E7E", "4 c #838383", "5 c #797979", "6 c #6D6D6D", "7 c #777777", "8 c #8A8A8A", "9 c #787878", "0 c #CECECE", "a c #E2E2E2", "b c #E1E1E1", "c c #DDDDDD", "d c #E4E4E4", "e c #E3E3E3", "f c #E5E5E5", "g c #818181", "h c #8B8B8B", "i c #C6C6C6", "j c #EEEEEE", "k c #E6E6E6", "l c #DFDFDF", "m c #F0F0F0", "n c #FBFBFB", "o c #F1F1F1", "p c #E9E9E9", "q c #CDCDCD", "r c #B9B9B9", "s c #CCCCCC", "t c #080808", "u c #010101", "v c #000000", "w c #020202", "x c #070707", "y c #060606", "z c #0A0A0A", " ", " ", " ", " .+@# ", " $%&* ", " =@@- ", " =@@; ", " =@@>>,'=>=)!>>> ", " =@@~&{%]^/%(~_] ", " =@@:<+[&~}[^^|@ ", " =@@-1;23435-678 ", " =@@90ab|:+cdef| ", " =@@g|([d%f%+|]e ", " >}]hije~{k{l^f~ ", " ,&/m=>=n>=.>>$> ", " ob+p%:~%][%q+@r ", " >(s&q0@[:~l~ c #040404", ", c #070707", "' c #0E0E0E", ") c #111111", "! c #080808", "~ c #030303", "{ c #020202", "] c #BCBCBC", "^ c #0D0D0D", "/ c #1D1D1D", " ", " ", " ", " ..................+ ", " .@@@@@@@@@@@@@@#@@+ ", " .@$$$$$$$$$$$$$$$$+ ", " .@$$$%$$$&&$$$$$$$+ ", " .@$$$$$$$$$$$$$$$$+ ", " .@$$$$#@$$*$$@$$$$+ ", " .@$=$@$$-$@$$;$$$$+ ", " .@$$$>$$@$,@$@$$$$+ ", " .@$$$'$$)$!$~@$$$$+ ", " .@$%$@$${${$$@$$$$+ ", " .@$]$$@@$$^=$/$$$$+ ", " .@$$$$$$$$$$$$$$$$+ ", " .@$$$$$$$$$$$$$$$$+ ", " .@$$$$$$$$$$$$$$$$+ ", " +++++++++++++++++++ ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/static_bitmap.xpm0000644000175000017500000000130010743421035022235 0ustar stanistani/* XPM */ static char * static_bitmap_xpm[] = { "21 21 8 1", " c None", ". c #001815", "+ c #F20000", "@ c #FBE800", "# c #110C00", "$ c #110095", "% c #060400", "& c #060D00", " ", " ", " .......... ", " .++++++++. ", " .++++++++..... ", " .+++++++.@@@@@. ", " .++++++.@@@@@@@. ", " .+++++.@@@@@@@@@. ", " .+++++.@@@@@@@@@. ", " .+++++.@@@@@@@@@. ", " .+++++.@@@@@@@@@. ", " ........@@@@@@@# ", " .$$$$$%@@@@@& ", " .$$$$$$..... ", " .$$$$$$$$$. ", " .$$$$$$$$$. ", " .$$$$$$$$$. ", " ........... ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/notebook.xpm0000644000175000017500000000154110743421035021241 0ustar stanistani/* XPM */ static char * notebook_xpm[] = { "21 21 19 1", " c None", ". c #FFFFFF", "+ c #6C6C6C", "@ c #D9D9D9", "# c #989898", "$ c #020202", "% c #D8D8D8", "& c #7C7C7C", "* c #000000", "= c #050505", "- c #010101", "; c #101010", "> c #060606", ", c #7E7E7E", "' c #0F0F0F", ") c #0C0C0C", "! c #0E0E0E", "~ c #0B0B0B", "{ c #030303", " ", " ", " ", " ......+....+....+ ", " .@@@@@+####+####+ ", " .@@@@@+####+####+ ", " .@@@@@+####+####+ ", " .@@@@@+...........$ ", " .%@@@@@@@@@@@@@@@&* ", " .@@@@@@@@@@@@@@@@&= ", " .@@@@@@@@@@@@@@@@&* ", " .@@@@@@@@@@@@@@@@&- ", " .@@@@@@@@@@@@@@@@&; ", " .@@@@@@@@@@@@@@@@&> ", " .@@@@@@@@@@@@@@@@&* ", " .@@@@@@@@@@@@@@@@&* ", " .&&&&&&&&&&&&&&,&&' ", " *)*!~*********=-*~{ ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/frame.xpm0000644000175000017500000000134610743421035020516 0ustar stanistani/* XPM */ static char * frame_xpm[] = { "21 21 11 1", " c None", ". c #7B7B7B", "+ c #F2F2F2", "@ c #00007B", "# c #FF0000", "$ c #FFFF00", "% c #000000", "& c #00FFFF", "* c #00FF00", "= c #FFFFFF", "- c #D6D6D6", " ", " ", "....................+", ".@#$@@@@@@@@@@@@@@@.%", ".@&*@===@==@@@@@-%-.%", "....................%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", ".-=================.%", "....................%", "+%%%%%%%%%%%%%%%%%%%%", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/menubar.xpm0000644000175000017500000000755510743421035021065 0ustar stanistani/* XPM */ static char * menubar_xpm[] = { "21 21 183 2", " c None", ". c #F8F6F7", "+ c #FFFBFC", "@ c #FFFEFC", "# c #FCFCFA", "$ c #FEFFFD", "% c #EBEDEC", "& c #FFFFFF", "* c #F7F2F6", "= c #FFFDFF", "- c #FFFEFF", "; c #EEEEEE", "> c #F7F7F7", ", c #F6F6F6", "' c #000000", ") c #FDF9FA", "! c #DED8DA", "~ c #DAD6D5", "{ c #D7D7D5", "] c #CFD4D0", "^ c #DFE4E0", "/ c #E2E7E3", "( c #D1D2D4", "_ c #D8D6D9", ": c #DFD8DF", "< c #D5CFD3", "[ c #D6D4D7", "} c #D7D7D7", "| c #E2E2E2", "1 c #D2D2D2", "2 c #DBDBDB", "3 c #C1C1C1", "4 c #898989", "5 c #D7D1D3", "6 c #D9D5D4", "7 c #E4E4E2", "8 c #D2D7D3", "9 c #707571", "0 c #E1E2E4", "a c #D3D1D4", "b c #E9E2E9", "c c #E5DFE3", "d c #737174", "e c #E3E3E3", "f c #DADADA", "g c #757575", "h c #D8D8D8", "i c #747474", "j c #DDD7D9", "k c #E0DCDB", "l c #C3C3C1", "m c #EAEFEB", "n c #DFE0E2", "o c #E6E4E7", "p c #CFC8CF", "q c #E3DDE1", "r c #848285", "s c #D6D6D6", "t c #737373", "u c #D5D5D5", "v c #838383", "w c #DBD5D7", "x c #DCD8D7", "y c #DFDFDD", "z c #BEC3BF", "A c #DEE3DF", "B c #757A76", "C c #DDDBDE", "D c #DBD4DB", "E c #D0CACE", "F c #757376", "G c #E1E1E1", "H c #C7C7C7", "I c #CACACA", "J c #8B8B8B", "K c #E2DCDE", "L c #FEFAF9", "M c #FFFFFD", "N c #FAFFFB", "O c #F3F8F4", "P c #FCFFFD", "Q c #F4F5F7", "R c #716A71", "S c #8D878B", "T c #79777A", "U c #DCDCDC", "V c #868686", "W c #777777", "X c #6D6D6D", "Y c #787878", "Z c #CDC7C9", "` c #FFFEFD", " . c #E0E0DE", ".. c #D4D9D5", "+. c #DCE1DD", "@. c #D8D9DB", "#. c #E7E5E8", "$. c #837C83", "%. c #D2CCD0", "&. c #C9C9C9", "*. c #ECECEC", "=. c #CCCCCC", "-. c #878787", ";. c #FAF6F7", ">. c #969092", ",. c #EEEAE9", "'. c #DEDEDC", "). c #777C78", "!. c #787D79", "~. c #747975", "{. c #7F8082", "]. c #D7D5D8", "^. c #878087", "/. c #7D777B", "(. c #7E7C7F", "_. c #7D7D7D", ":. c #7F7F7F", "<. c #818181", "[. c #7E7E7E", "}. c #707070", "|. c #030000", "1. c #0C0608", "2. c #E7E7E5", "3. c #CED3CF", "4. c #DDE2DE", "5. c #D5DAD6", "6. c #DBDCDE", "7. c #E1DFE2", "8. c #827B82", "9. c #040002", "0. c #020003", "a. c #010101", "b. c #020202", "c. c #F6F2F1", "d. c #7C817D", "e. c #858A86", "f. c #898A8C", "g. c #7F787F", "h. c #090307", "i. c #FDF9F8", "j. c #EAEAE8", "k. c #D1D6D2", "l. c #D5D6D8", "m. c #EAE8EB", "n. c #756E75", "o. c #FFFCFB", "p. c #DADAD8", "q. c #6E736F", "r. c #888D89", "s. c #808581", "t. c #797A7C", "u. c #ECEAED", "v. c #0C060A", "w. c #DCDCDA", "x. c #E1E6E2", "y. c #D0D5D1", "z. c #D6D7D9", "A. c #E9E7EA", "B. c #766F76", "C. c #0B0509", "D. c #DBDBD9", "E. c #767B77", "F. c #7C7D7F", "G. c #DAD8DB", "H. c #7E777E", "I. c #050003", "J. c #F4F0EF", "K. c #E5EAE6", "L. c #D3D8D4", "M. c #DEDFE1", "N. c #D5D3D6", "O. c #8B848B", "P. c #070105", "Q. c #7A7A78", "R. c #717370", "S. c #7D7F7E", "T. c #7A7A7A", "U. c #8C8A8D", "V. c #716B6F", "W. c #000201", "X. c #020001", "Y. c #040001", "Z. c #050001", " ", " ", " . + @ # $ $ % & * = = - & ; & > & & , ' ", " ) ! ~ { ] ^ / ( _ : < [ } | 1 2 2 3 4 ' ", " - 5 6 7 8 ] 9 0 a b c d | 1 e f g h i ' ", " - j k l m ^ 9 n o p q r e s 2 1 t u v ' ", " + w x y z A B n C D E F G H h I J } t ' ", " - K L M N O P Q - R S T U v V W X f Y ' ", " - Z ` .../ +.@.#.$.%.[ U U &.u *.=.-.' ", " ;.>.,.'.).!.~.{.].^./.(.W _.:.<.X [.}.' ", " |.1.` 2.3.4.5.6.7.8.9.0.a.a.a.a.a.a.a.b.", " c.{ d.e.).f.].g.h. ", " i.j.4.3.k.l.m.n.9. ", " o.p.q.r.s.t.u.n.v. ", " ` w.x.y.+.z.A.B.C. ", " ` D.!.!.E.F.G.H.I. ", " J.'.K.L.A M.N.O.P. ", " M Q.R.).S.T.U.V.9. ", " W.W.a.a.X.Y.Z.Y. ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/wxg_file.ico0000644000175000017500000000427610743421035021203 0ustar stanistani @( @HHdZdZdtZZeZdeeiZZdddZZZdediZdZddZZdZd dZZd Zd!dZZd Zd"dZ Zd Zd# dZ Zd Zd$ dZ! Zd Zd% dZ" Zd Zd& dZ# Zd Zd' dZ$Zd Zd(dZ%Zd Zd)dZ&ZdZd*dZ'ZdZd+dZ(ZdZd,dZ)ZdZd-dZ*ZdZe.deZ+dZZ/ddZ,eZZe0de-eZZd1dZ.ZZe2de/Z?spe-0.8.4.h/_spe/plugins/wxGlade/icons/custom.xpm0000644000175000017500000000144310743421035020734 0ustar stanistani/* XPM */ static char * custom_xpm[] = { "21 21 15 1", " c None", ". c #7B7B7B", "+ c #000000", "@ c #FFFFFF", "# c #DEDEDE", "$ c #D6D6D6", "% c #E38E8E", "& c #DFA7A7", "* c #FF0000", "= c #F52F2F", "- c #DABEBE", "; c #F14747", "> c #FA1818", ", c #EC5F5F", "' c #E87777", " ", " ................... ", " .++++++++++++++++@# ", " .+$$$$$$$$$$$$$$$@# ", " .+$$$$$$$$$$$$$$$@# ", " .+$$$$$$%%&$$$$$$@# ", " .+$$$$%****=-$$$$@# ", " .+$$$-**&$%*=$$$$@# ", " .+$$$-%&$$$**$$$$@# ", " .+$$$$$$$$;*=$$$$@# ", " .+$$$$$$$;*>-$$$$@# ", " .+$$$$$$,*=$$$$$$@# ", " .+$$$$$$;*%$$$$$$@# ", " .+$$$$$$&%-$$$$$$@# ", " .+$$$$$$;*%$$$$$$@# ", " .+$$$$$$';&$$$$$$@# ", " .+$$$$$$$$$$$$$$$@# ", " .+$$$$$$$$$$$$$$$@# ", " .@@@@@@@@@@@@@@@@@# ", " .################## ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/wxglade_small.png0000644000175000017500000011136610743421035022233 0ustar stanistaniPNG  IHDRs[2e}bKGDtn^ pHYs  ~tIME%RO^ IDATxyu_oˬHw&Jv9#yǕĎRUJUc%T\eĒ(%ˊKEI$HX3}omw9 1 oUt~{={\%"!qCM F_!qCqhqC-Cc~CoCx ~/o x[!v>dq(Q(JWx(mї{Cphq[o0g'v7} |w9އ8@TqxEuA5G{Q@]Ci!^ ;<յߣ=8'JH TS1Qkh7g:fR C͉Cc~W _C˿OcMEY e)JMpQyR= ((i(_/r277F!!r[`0s›1eiNWM\1fR[<P.R%L[)L~pIu"Q{ݙCx84懸%x[Rm)g14nj1K)Bd , PZybl#h\ljy!"-G@) ^r{eW!^*atg1g(VL+P1PC T P <`”U;;Y9·@LJ*owLyig՘E5T#!Is"Ʋ{Yw{ǡ1?7w٥g|63q%q4W g"8PFe#LqV$f8eUe֒$rO"%H_#i2g򙇸3\x 9|(n"MԌ~Wn0*ZP޺wvۆ㌞yFG0)al]h( ׯbxfy9\9Zl<`6<\1*cbakϳ#oi/ / ʱ$yJ)*PԳ).5ӋB̐} g!^?_٦ &Bc'Б _r5JA=I#i=5g߁_itSbm*ɫ.` #O| @)NBD(GE:|V,a8Ռ-0N!s%յ/0ubTAllEQ8p^#(-x06"MO4X16X*"R6[bZv7Bb?2¸ Q)UA=FL}STl42ѼT!nxKlM9+8)2 |))yc Q[7ۊs[$WL.C܋"cF*amX\AE(DLSu$F,A 7 {! ;;pd8d~~-#w1~^\R "6RИ;ftəߢ٢*ڌT#&Fń$ʑW p ƞ뻊DS$hjK52Qe fUns5zcdrKq,7o'XTr`AhXߌt N~3G=}b/`6d-aCcz]4h04ES>UbS J0*"vk\dc!Ӝ' :iv좔pUPRH hy[}vfS?ÌU|]zSsX-%^dqʲ|q;ؕxPN"  8Q8p( ޿r84 h_cĐW `۠J+xAB[ϰ\O(;N?NoG&Nsk),ϩʊ<sXͱHӹ킝^ 3'<C$A{֍b'T"!OLSUF=kq xYB4kJH(O+uNJѾqh̿Qgatd&{T;`SŊi H: 5{f{9[ҘbҧP ^ j|ڰjt!yQ 03.bLQI偀SH 7;aTn,[?2OSsĉoϡn{h-xb4#;`Ф"Zx4'/KʺrN fҭyhE:2@L/&noL>A&"0{z_#+(oPI5Ldl@ui_#ٯⷞC "Vb/,D6Mڈ2;A]M~M-eC&Os ~NfFڞ}a79fr,*jnOP|xQm=E FWIfģO)r\0bh[]c~q'Orq=c^ֵ+O8H^xMB/|[ih\S֘䙋s<2}wHCԝqHNkZ0ëL|4v{F KiI/t]SD"8]hOWbxxB%`Ơ#p*)桑@e,j e3_G|_e٣(-i'>Ju}C ~a?Jkn8~e#R^TO&σo"qy?=NXWR^z=b mztn';W=L^PBe=jk<xQ8̡_h<*NQ5wX[#~_cPYĿUٽK90 <'Se)掲sw̼4%N7Le3W)* U DQ<֦7G}!h `jy%"XC5VyM8%4J %wȿ;?@oyʫ2";KIg5s3nTҡ͐M3a?=cf~eۊ;2`lI}SYm xsfz}'5Y~VLfrqJp%x+7du>*GUIffgY[_gqiezׅDQDo8Qg 5pC7O-eP~]o\(J)u7yb5 %:ڗa4D|Up"#DV{4A?OdπzCcm"[:'?F<F+X)TJHPx-%%xgi}N{H;u򹘢;h ^>g.7hWDlZܤ} 00zIĎ10r g4YՁ=^A>&M$|{T1|fHYgiW#_d;wr#f1fz|Ki>s*_~a2kPb5$kDbb)6_a?]^2_ksr3+Lγ+6{16T*M[f܃H!(20uؐ Zp- -h$fg.>Iп5w r½#'/I%Zʌ/0=x QC)#$2%R }IOϬ3{|7sg?Kx4:JHӔ8N^urQ8O7;ӟ 0.#IUGơdcq[ ?G X A T&!F_>E~}Bc?w333|_ +05:> &1&-%}33;mᑉp.xJТhUJe!ϟe$*:轄gYC)zUBa&IRs/_zwn_gb&܂FhA댿̼*/}z4oP8B𐫈8qDaRjӈi:2 xh${OPRzsz94g_V8+Ǚgݙ:΋cR+1f7PiX3>;ϐ}?b$2Mva*OY EC;$O)}3G,|&08󻔣(('7jP_Y"+\:K{nE01?j2^~n%+V3g?Nrߏ?S4_e[Z4 #P;QʃՠPy &{P^yŧ(đBtV8Pݨ8GC)!R {ηZAGr(71>Y(E/ qm1DOdab NՉf(V^DB;M<C,cr6ϵO3|_艓HIy[䗩R]>w.h:cs?TjZnj\L{/.2 d4Ny:yFFA$B郱TOQhd$艳aIywzev{둴Oyh948 Qōn:^LOs?_:P"+ᐎ1oxPSfhmܢJ%2(RL@3g@Ey"wAo.)G( {FgAB^g`)nW4"AԴSz0n(NrL_ L~})0ND0Nn.Q Kh$AG)4JitӪ,0zVLxTFѠiHxC%kN}3/XqB㮿{nxZQ 9QqUߊiYFǎQι7\=EL+Lއ#!ATabhdBQY"/9=&UXtX5z:?stw!w9z7F=)t6&349T!B W4,Tg?G a _Kv/24`Lg` kaTa G뱸Don^ &8(X0FZS# xZc;!+a?xOܒ!BT'e 5i@ݑD~1}c &[ӝaa~!Jffn9͟D/d(H1@y0F#ɚ]ҴA$_BQGiL&qxR$~C/^`?ɩw KK7ˌFץ¶ھB y:$TldFUi Z4{=:Fn^nL]y@GXQhHPn+J}YDs|+{r #!zRRq(lkG.0Fa~q~3*=T*+NQ,+[%\(v+^\`QMwv,tZ}=f=a&/aK)Up,DО I0;QDȮ>>} ET d+\#.fS1"k,,/n {.+++7*@gX;v~g6#Z9@d(,vwl l1atsd'CMcQ*sѤj|vi0?ޏCsSl{7`4!kz65<( 3Hb2eBoPl}h’PU=Hm[PVٰXF1WG]i\^e;^^>=8>R/h" -a"Bͦ)nvC|;<ƌބbMωIW5i .IOn1"pkTm74IoT BX^M7! 3*u( .O4ˈc, r#+tǞbHYo]FU8x<,\gQB=Nd/vLP %\4E{g*G:yi6$qxte"l GU.-Mm"ՙ _WݾN3)sP&Քh+a%Ҵ5;M,AL \ؒ٣VzzJ:GQ 걍jLDn`  C cfqq??(e1E]cqQzyS9[z[]2BA;&S!ye#J됺dU]PugyZ6ݙ.NV]n3뱶R6֏s>5P9tS#>Xij"&jDi3vBi<6{\+ZiB3C ~ %xq%X0@G\r5X8vz'YY]c3nBP!O=y.N iD|N\X"rG?QL,l1Sg9aV(.g7̞xaymu=C}R^ilh[$>iTaªs&B} ’(Gd2cw1*a#FT-_|hX9vi(B<4[ 47!|}G]" W|(+: ,%$˽)Kh UU᝻a̕R̰~ջW#7VRA'Al'sW0䗾@~aDk$ H~^9艏 /Y(`7 i/Нj'&^ KK4 ^U֏q).}s^x SLp2o<ݶ:ia7t ^ &R 29<1/5u^+ƆZXŸKEi~kw];]tGq=-9¸ptnTj!\>q -=ˌУݠ5aˣO'E!*E4[ZMZ-WO.>^  Da]Hy2zAѤ(X\UG^7F$H*1<>$wr<[;)?ɓ'9u~nQL[ 8 TNB{3\?Gy3No;baN?׿N:rrciJqT&cwƉ'9ykuͥiAӡja֚\](NPXSkqatI&wUZYSrDR!r%PX=I{ӊBD tN-~BE0#cU[{ss?Γ/v2h"h''RD@#ɲd^ko1>_$~t"ȩ"C{hnMJU7~7SG.ܸ޶[5T$ifUn5/78N癝evn Q]t(XTw NU^pFmu2nOX; cnSGB "cny=z'Op ;vqgJy|(߷UQi4ЌҠEq+^xl1'pz9TnG'Տ&U Aqx~4MIZ>wtHs:I6fk l`lgq0CaBk>a)z;+kk:u{5֏jݴy|+tSt_Qh{$h<RMlN:n1Iz+"? @G &y'4N}<_;%wM%ĎKa_!cܺ] \! ifLHJa.Mjjeh 3+AnNJ mK,W*tz$ )9Y\s|xfWEF x/| 9dٜ(5/l]b|j=(UYKkϑ]i2E 2j*HR) :BJBHOӡV1(TUj?pGO 8R3b>lbœ6Ti.Sؚ:o$t(646hLֳ [#"ra8z ^VRSfib<;oRk84o!d()Ж@'8-L3ABйU ޿C%J)5LxA K1fdjS8 9ɘ([.ï%1c3%1ONQ>W]~Won]bGS\/RHg(2ާR1}ߧn֫ ^/\}Ϙd{SÏ< ]Xp4hL 8;SɅ\xiju:z>kkllv@Z#?{hr 3Aj>'?x<&n:K}Ϙ<;q! H8ƣwe4NQ}C Th7 -'Q&8SDV8׌$&F(#8ȰW*z>A^کQ? ]Z5Z6F\JI٢s_ɜLc2Z xvJgsM-GO>=8&5Gf"c^ SmO1sO}7f>)E$2/hrI #fBO'8P.Q*(ʄ^n<ʪ*.8o*eqĉNWf=>g3(IIJBӣؠ?iz凞"v*8z|4ᘱd<% r%; Yl ost4'MbbksoVmdV,{s# Q_\*Q,׹5V9iH4ƑffO/$,StY&Lg`YD~~hMr"pZ}*.nږqyh/?Evx,I^Yn`P0c m*{ʊ9if W, 5f2=J6Ճg/IAх*±$vBS%d|1Y^DAC\7䋠t$8 |,] JB٠nS,n̅4uw}x IDATs&Wuq2Sd| f>I&Lt?e"?<$5fnyjws/(JtmP^~YԚ<F~5tel20LTýInT7Fv-C/#'vR[R[/pW{*iʹަuN-%L[{ҨyQ30^sO"9fW~NR|\iL ̌_ɕ@v =5pw6*!+2XA ydZp4Ts$# kUJU\? 5)ʄ2QC?/M#? y|"[Y]˓6]D 満SlS)W(nzѯQrȁ QjA 9I<PrG첺O&+)ˬ'7]ax&4\irq,:#7z`"%qEPdY#eO:^k+Xg sC*Ju)Mp}YD<5/ 0 tN!)oT*5;8_j^6Pক 4Z YўGn G{Kg)MąpSQMc\uAu2߉K S_aˍi4J׿ifN\.^?yw%yL8x֏#Ԙ mJ1̋Hh iM 2%)i:}6/F$ĉ0 ~GX,M}\.ɿFCKBg_:ɐCk <17~a$ .OTk56ﻟy6TA&BqlvuW3oaE,A^(}" Bby-b,.qx3|(NQY)j}7xsOTi^i_#TZmVJ6*ǿoo?Bf9[8xE48# !2r8$G3Ӑ$5PA t%YYyfHZ-rı 1IDr* 6NƠߧVF}8Fz$QQ8HQ*YQSƞ2wa dyjHvӵ9?5L}\yAhb+MƑ`/lGc'6Ek3v$ڑr8[@SwK1=TB}Bnt_ Ed:W._ kK3H#7Sxi HN#jlk0SbEa7QGvC]PurZXwr M3ɥAڴ<@kAkSn]`*\zp"\ט-fbwV`0MP7aej1|2~O?/HF$ Mٟ9D&LJq̘ȁ6_Sj$f0ZQJ =յ#rOZ-eք2:y<,3r #3J4S7`"<&cCR("+u ZwK=7~:+k VXX?Žx`nɅʍ( g6~-,?׌^| Ũ%V;]}93^oB7̀r7x?J:4d͹$8 9R<e,g/3>a +^4nWDGx` FSφW&sNT6Lhf*u;̓XGbɱAZؒ3p\*`$#c bϲF;Y(ۼKƘ~RF<@}v/l21tZe6^_) y3:y3;J(DdwZ !(JVNѸƿ`yX44na+lE3IRݼfonOđws9P4m]XJK5Ĕkr&.h#8I*էR.ɷ:x]zψX1"CSy/G`3?XpkM$L&D0RtM3cո9G!j|:yϳݻrpNzv]8ztVVغv?38~KR%Dklb ?B+T*ec/'fS\|K0LoeB Sd /38q` 6^` 2~jړAHJBXk|11Gb&5̬D 5{_^"2V 9nlߦ.5)(kc,*/DG (^&2;d2jnx~ p Gۗ`wҐ("m4vv)ԳO qJizOzqv 8,lMNּ6]laQ;2qU>e_&7ɂ%,x˩G4L0N͕dh:;NvZ+O|aQ]hjoXB`@OmS F:3<5ކO`iXa@BHXq]R08^2F\ VQ.NLaj7 ")PFF1 >UTV*l?b%_ˍi<-0Ќ#y(Y@ef5JءTq-kӪ8CsnvM¹}wA \R2| $8C_!~ ? >a*wf zYC:ќ)悖++q = 81p<Lf}8PC x.nъYL#) nk:*L?JCGg3&ϒ}w_$".&S"!HTCI(azd3m)0mflP@-ߨ6 D(P3tj7T?LHo,6:4O2|Q\mSUH(cX;NKSX:GgmU3riڝrttD) .?qJ s5E{զ :xcF'lOa'v>Z-lnoY.3g/ϵB0XpaGځz{K>+3)fL/h<}29H!bOp{ Ax!N(gqjр)3jbrC;( ''J#z|{T[ܬRF"-KP$3M euzM*\70^w[1 8z'yᏯw0a3@DD?_4sL%l)TkBwh;2XYިHk;_7Y`܈ f ifG:7w^֏?ǜϽE>%aԅ(Ku:k\82W^z$a+&] 6Q!V f;ՌU-Rw)qW^`{oFH%REbM@L hm(o0롕~YlßekgH+Wd@@1H|nR_k\;'2B![8!z b{g I9Rm9Zӯ#4w~A`U/>IDhw%ma`o;3ɮ)h 6tz*na'E)CsE;07 &( ",~/, D0J%P^;K\hZ--"&W/%4:ʉ^E` .ǧq)>fNGR}$ax9vVn3 1-8f*Qʨ D//p1j'\n!KP.C4%Ib%ҼȎ81cǥrhK6r Q4LaH'R(d* ٹ j2m|Ns@'fI9'R\8>Bhb [Ya@G~ ;l=,1KqaKWVNV 5le&Qмn+4`e^jgџ7^Axf9bZΌ3RM9LBSr6 ) y ʊ? & 7_z7RS^fHk?&  ]Nƙ;)5;ugI|.&|ѥ+ $i:x1xB\a }Ę > !7yNe$R◿ D@C" #K4.f[bH<7onj2``_ `[a=wego8sKO,% EV/.L3( ,z2{WE֕mh:G?Fs{u~̎.5R}!Σ<b(h-_V;u*45|Xz=Nz~M=p7q]Xlewǂa.؞K.G6hnAߧ?Xac}O\<iFQ`^BDUIي mPq"/(c,شoweZi.0FH;rk+씞w{pNby{9zy_zTiRP¼>NPXK2!86&9 IDATJk&0`Тu}:}++c9.KS(}-PxT[8r񞌐lp%QL ٟͨt1/V}*k]o4u Nckk 0r>8D 4NjjpVi(jZmz(%鄭rkg\ 5XdQ1*d#?hsN8v{>~ͅ,{8˙-($%@&HTIg+Yx- o>63|ii85H݇3dz C*sjJBW?Egƅ rQ{3V4tOo: suW`q•Ko*T%sQq`3=\ R9Z~o9unX/W_(j5M^cf^̃TF#ǣt.+X;u5VWWY[[Q<,MF^Qkwx'=$U-'ǗL=lN?m Zp&zn670E|lD$4}ë(*W75$a73EVZFgZt=*o=3!}8f_.[/(N9PE®i8`'O5C Rq,t.5jzl^!fx4B㧦QYhHs^rl:#w~-H:ZZFa0M&Lp4],E a_,Qn6[Ԫ5 jj:ahE'~{Fw8L$X ̨j Ҧ %>ٳ4w<731]&1Bz|]M%iedkҘ ]qx>zQR fd]SBG+85 ڧqzwfp]]]lަaW9\8RLYCBI(3 ZVbqBHhncy]FARh8ިnᐕ,l|io6:)u&m.6jJeLcӏ6o?‰3J2%rOUơh"hBt?t;ƻ>ORJ+,KrKLG1#e  jCO~)FlL C$%47hh54-EKo !˴O}OpE<4c vgF@]4m ؠxZARaee!iD_7^Q譸oK\4s~6;hڶ4l6oJ{[b::irWHMa&2U q-gkgN:jmbk`}I_kvx +Dh-K#5+$> |Tmn ^RJddM fK :&L],#{WPzuiTh{H E_+Ksu]:6I~8[\7?"3[0s $BRi:CFӥ0 ,Bۥݔawt{}6{}VT ikv5I9u:FFMx/KXvCV#2'&1}󯲟*f泣pB` &OmôR=AmmrMf͍Mnw!ms0NݣGya&$6.ǂ38s73&mlqʸ/w[ji <ϣ\, GO=A*tH$1+wR$Ѹ~.uVWW&s$y.TP_( e-4MwuMΜ9égX__W>xVT.04:|ӌ^},C˗"(9:W!g. 2j,cx 8J,O"W)=``n8K/kor%vhp{}rMVtm_w<:³'94Pif, -xt]6Om hͷ b8&M$zl;VInzn֠\4'5S_u1ؓ Okc2M\I M.4n*pix V(JTfޝy']!Nn}ϱBm,!F[ E*ffMզ*?:YZι O 5#7~YzVVV8uq¹r i)%f{ >?ht:]^=IƂڝ ?OVKF9Y H dAm:oǡj!8D*~k}4+HSVxsĩ3Fc9T:J;3:$Œ3m4x " ոij,"S?cL7OEM_ހ9LVVӄ(Ix>ex_h6Cc^4}ߧ?XVCTn3:<$RRs %F<ִ2Yح'1nxO=pJi5*I] V nKJIVCkM\ŵUg魮a(nL%T. mQJ+=UyF:=ӲmPvz`@?l'QqeVWWyGSyW MN>eDz=jm 6^ Ņ7/W(V?Er8c(@!DN٧a-)D>{ëD341)ZT*E"bv_z■ W,iZh) gs,#3$%IsnS*WߣbA@PPz2H41VM0;(ުڻ] Ull:;!>&69v2'Ofc;lv,L@֭nZ]r.n N?s|>o*"LL&OJ{#@21R9KؽmÇD2?h:Kl{;]̞=l2fjym;^g'eg! fDSa6d`8L""J(LK (xd2E+جGG&hV Lj2t@&hX^CN$5o˘H["IY 3 ?FU ϛKvvzzf4l'#fQFc싵j6uŋId;hoof-ӧ%kkCAEvΡw䀹GOȓh5s&=r9ҩ[0H|w2R,á O0UFMˣSMk 3:6F"H#Ӊ}+$.:¬^=L\Ai5+gm:`Μ4 ?^\.gy8etݦ\j(-S|>t`0Hd2IV/3L|><[xX, $IUD(n)JhWD"%tw첼\m{xnzKt/9Bazn% )D"j<'S֗#n?J8RrDH\ZPm6i4hf4O8& hňD.1"i# cyUL5>{mvkߍdYd{g:Ѩx,oN $ @l6k +a% b2^/m8hJwTF[ ';-\x$%ގ,j1Y&L7 Qd2xՑL"ͮoQT2E8NGJe2,jEU$x>_rHsPUg4[30"f~/yqh?*>T î{3|?Ы2rL37 xG8k ~~wؽ{7eVk2MMW_7(w46r r2IO8-!4Bhtw=:x?1Mfi"g'MNz/ضl?&}:ʊh Z(xzWsC,1 qǏ[:#ۅ䱱1&G`xdb0v6;5?=::J1BeLtig'yt]炿;2rR䞯.$mL羭AZ|72 X&P ؖ-Xt˗ѣr9SSUSSϩ֦>nfƬYx旄Xg~V޽l/Y|%tuuݶܬYTMk|>FFFF<;UU@Evt\?&_5`5r%CCV|fH5tD*0 +pS>|0+$rE{Xk_ʏ1T,h44$!\{*\ [lP(Jĉ FGFV伜!4MݻJ/gu#rHī6><A@8{Iu6e8Z D/F7nSOr UiQ.'a ܰ;C̾*/YA09:Jki1W nSv.Gwrle6~egi{P!x)~oCɫO>ə^V1~;x3F b'BE&x/\D9kȞq^C7sXtqlݴ+FAml#{k=Q+;vO.9#ql^^xl5wfѲ׻O\f}gV",[K "}ӻgL˯眃iZ>j"K/V(ҿ;G{{Yyu,:lz% qɩCQf&^}Z0s&fIep.Ċc^gwowyTTUKY2y1/w@u i1'W=\JG],%+h-p[[k'VQ߿׋1#÷hs} Qlccni`Mdf!Ͼʁ^`WR^>Vq;g\| Nn*ry]FXʹ_7da6>ލ ٴ9Dٿm>˅j|yh:߸ ٷ uF_jʂ.h}z*3glYf ]]ڴr tΚŁ]wс]wqt`SUaTE} 2wRS,ItP1(Ac1E1 UUiM0mɟ5MKXI|5d;0(JD]rjR*hjh: {%tt3ZF:[!̯-ߏR%x~8b(t,?נ:',JۋqSIDAT ##۸S/_7Ɇ߁i]k?ގ  Yŋ9calF8gO3 >YۯũKT J%X_lO(D[W>A18H=g303gVW4Ul\}'l6|Xr՟`߾}o הU^z)ۿqw/|wd 0r<,~!z{{ a5aRd64Mr]pG^|‘#4óu 188iBi@ӦY1ʛ7S޵UULi|Pڳ=~0a@< b\T(PVQrLkS;z sb6OLVcllv+Zj*>fCQ9_>zE= B}~bَ^f]l7(Ţ hSZBRAQ ]Rb9\00MjVF3yѨ*u E T0 &XJ/y^wv Ȳ'ihl H&IZ&zziTU<HW=g +q}Quj\'rOv\k P$' xuzj˖+ \EQ]}͛Gu|LwU 0U4j5PR@<'ck1AZfiD;]-4Riw;RUk(^H$B*[ok+[D7&s |9Vtj{:[ʸj] <_P7,hl)?0ư: lb012B̰gg a,\zQ3ҋgJaޝ7bZ%&H o:CTUBUUT]GV:`}hfM ND6R*E8Fuh6(51G-W$BCo0$ }hȍ*|qŁ@R*5 DApeX )F($N-S)I) 4~ àsb 9$ziXL+OU *`]x@ @٤ZQd ]x￟$ O$ib1ξJ^X>jtEQM}ax<0RFB4nX:&$C0`Q3fD(ZVJ*#ͣ31 h4 (^ _"8@_o/O= O>g,ZD#qJGET7a2*ƞltAs !4w<:JRKLjVhJ1qz{߻wImAb;!ldB멵x*<#?1Cc=}2B_V`vEv_EY?ggTXC1뾃AKܱ~k"S{ ƿDup8.9R쨕:spQ8n{}/~ͭ$IA{\Qwt0{ٙ= o$*xYJ>TUtEaCRಯʜ.gdVGZ:M>3gVn9(s2,U{W-"s/aQ2a0t|q f9cHDSt}L]ʁ~Y&:{6 :<6mdO"QCʞBQkmc1~xowp D4ڗ-×QQU  w(l>e8/<l;$ IP81݃iK/r|9'idz2s .lH$?i=MH#Hxj*=3PQnT˖q۟w[GX9crEQ\|5QD>ϢE5kDAh6paF_~e`^YFwjx^:::, NlH}xif0`&!>D9@:;;1cDJrpTkl 3ىna8Lh9s1FG{} DI0R)LUE\糸{v* shTl H @y>CCr \GEe<̜9t:vq;d#QwZ*MΘfo~EA/uu 顧5Eath͏?bIGL85K\3::J\11V,1YNyx۶Q yL&14Wlrqi6dY:;; tqbbbjꦺ< ~mXa~%]GYfuݥg::%I\.366 y<岛RqjZo3NLA$=9(j .m;/c0^-d;/X TD<' :$9h1XndYjk(r)RɒXsoܢ$c"Az d[^! IjFÚjD"&)2,cљ 4 kܵD"Nqմg> @47OxNa1NTEQPbvtes:ND4F8ykm6y;sιt]w7 grNT0m̧XJ:ԿlpM\{=]̰y#Q;s2kx;xއk9yzS=Ts=OǛ,|5Uk깜{rRk`mLz'N000`P(DGGs縓['5uގ4ɴ1417ݔe =J#9MQ.{ ;m̧1iL09]ޜ{%7m̧1iLz)Kѽ6Ә4p1X.IENDB`spe-0.8.4.h/_spe/plugins/wxGlade/icons/list_ctrl.xpm0000644000175000017500000000120010743421035021410 0ustar stanistani/* XPM */ static char * list_ctrl_xpm[] = { "21 21 4 1", " c None", ". c #000000", "+ c #DEDEDE", "@ c #FFFFFF", ".....................", ".++++++++++.++++++++.", ".++++++++++.++++++++.", ".++++++++++.++++++++.", ".....................", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", ".@.........@.......@.", ".@@@@@@@@@@@@@@@@@@@.", "....................."}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/button.xpm0000644000175000017500000000121410743421035020731 0ustar stanistani/* XPM */ static char * button_xpm[] = { "21 21 5 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #D6D6D6", "# c #7B7B7B", " ", " ", " ", " ..................+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@@@@++@@+@@+@@@@#+ ", " .@@@+@@+@+@+@@@@@#+ ", " .@@@+@@+@++@@@@@@#+ ", " .@@@+@@+@+@+@@@@@#+ ", " .@@@+@@+@+@@+@@@@#+ ", " .@@@@++@@+@@+@@@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .@@@@@@@@@@@@@@@@#+ ", " .#################+ ", " +++++++++++++++++++ ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/dialog.xpm0000644000175000017500000000731410743421035020664 0ustar stanistani/* XPM */ static char * dialog_xpm[] = { "21 21 173 2", " c None", ". c #7D7F7E", "+ c #666A69", "@ c #747877", "# c #696F6D", "$ c #7F838C", "% c #7A7796", "& c #706B93", "* c #7A759D", "= c #928EB3", "- c #79759A", "; c #716D8E", "> c #928FAE", ", c #686580", "' c #817F94", ") c #737282", "! c #6F6F79", "~ c #787E7C", "{ c #191F1D", "] c #4C5552", "^ c #E7F0ED", "/ c #00050D", "( c #0E0D2F", "_ c #090331", ": c #120C38", "< c #06002C", "[ c #07022B", "} c #050126", "| c #120E2F", "1 c #14112E", "2 c #000013", "3 c #100F21", "4 c #191925", "5 c #000005", "6 c #7D8884", "7 c #000400", "8 c #AFBAB6", "9 c #8D9894", "0 c #040B13", "a c #FBFAFF", "b c #FEF9FF", "c c #F6F1FF", "d c #1A153D", "e c #0A062B", "f c #181437", "g c #00001B", "h c #E3E0FB", "i c #121026", "j c #CBCADC", "k c #00000B", "l c #07080D", "m c #75807C", "n c #788480", "o c #6A7672", "p c #798581", "q c #737C81", "r c #78798E", "s c #797695", "t c #747190", "u c #7B7897", "v c #827F9E", "w c #6B6885", "x c #8D8AA5", "y c #6E6C82", "z c #78768B", "A c #7A7989", "B c #80808C", "C c #06060E", "D c #67726E", "E c #F7FFFF", "F c #F3FFFB", "G c #F8FFFF", "H c #F4F7FF", "I c #FAF9FF", "J c #FEFDFF", "K c #F9F8FF", "L c #FDFCFF", "M c #FAFAFF", "N c #7D7D89", "O c #000007", "P c #828D89", "Q c #F3FEFA", "R c #E3EEEA", "S c #F9FFFF", "T c #FCFFFF", "U c #FCFDFF", "V c #F4F5F7", "W c #FEFFFF", "X c #F7F7FF", "Y c #FEFEFF", "Z c #7D7D87", "` c #707674", " . c #FBFFFF", ".. c #F5FEFB", "+. c #89928F", "@. c #F0F9F4", "#. c #787E74", "$. c #686B60", "%. c #FEFFF8", "&. c #7A7D76", "*. c #767875", "=. c #727375", "-. c #77787C", ";. c #FAFBFF", ">. c #7D7E83", ",. c #8D8F8E", "'. c #F9FDFC", "). c #F2F6F5", "!. c #F6FCFA", "~. c #F6FDF6", "{. c #FBFFF1", "]. c #FEFFF3", "^. c #FEFFF4", "/. c #FEFFF6", "(. c #F4F7F0", "_. c #F9FBF6", ":. c #FEFFFD", "<. c #7D7E82", "[. c #000004", "}. c #6B6B6B", "|. c #FFFFFF", "1. c #FEFFFB", "2. c #FDFFF3", "3. c #EDF0E5", "4. c #FEFFFA", "5. c #F0F2ED", "6. c #F4F6F5", "7. c #FAFBFD", "8. c #7D7E80", "9. c #000002", "0. c #858384", "a. c #FDF9FA", "b. c #E5E3E4", "c. c #FFFEFF", "d. c #6D6D6B", "e. c #6D7069", "f. c #84877E", "g. c #E4E6E1", "h. c #8A8C89", "i. c #7E807F", "j. c #000100", "k. c #7B7778", "l. c #FFFDFF", "m. c #E8E4E5", "n. c #8D8B8C", "o. c #090909", "p. c #010302", "q. c #F1F2F4", "r. c #747579", "s. c #010206", "t. c #FAFCFB", "u. c #7D7F7C", "v. c #858182", "w. c #F7F3F4", "x. c #FBF7F8", "y. c #EDEEF2", "z. c #F8F9FD", "A. c #7D7B7C", "B. c #848283", "C. c #6A6869", "D. c #878586", "E. c #727272", "F. c #797979", "G. c #79797B", "H. c #777777", "I. c #898989", "J. c #000000", "K. c #080808", "L. c #0F0F0F", "M. c #070707", "N. c #010101", "O. c #060606", "P. c #020202", " ", " ", " ", " . + @ # $ % & * = - ; > , ' ) ! ", " ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 ", " 6 7 8 9 0 a b c d e f g h i j k l ", " m n o p q r s t u v w x y z A B C ", " D E E F G H I J J a K L a J M N O ", " P G Q R S T U V W W X Y Y Y M Z O ", " ` ...+.@.#.$.%.&.*.W =.-.W ;.>.5 ", " ,.'.).!.~.{.].^./.(._.:.W W ;.<.[. ", " }.|.|.W 1./.2.3.%.4.5.:.6.W 7.8.9. ", " 0.a.b.c.d.e.f.4.g.h.. i.W W 7.. j. ", " k.l.c.m.n.o.p.q.W r.s.[.W W t.u.j. ", " v.w.x.c.c.|.y.W W z.W z.W W t.u.j. ", " A.B.C.D.E.F.G.G.G.G.G.G.G.H.I.}.J. ", " J.K.L.M.N.N.N.N.N.N.N.N.J.N.O.P. ", " ", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/radio_box.xpm0000644000175000017500000000327110743421035021371 0ustar stanistani/* XPM */ static char * radio_box_xpm[] = { "21 21 76 1", " c None", ". c #D4D4D4", "+ c #DEDEDE", "@ c #DCDCDC", "# c #DADADA", "$ c #000000", "% c #0F0F0F", "& c #E4E4E4", "* c #E2E2E2", "= c #CACACA", "- c #D2D2D2", "; c #CCCCCC", "> c #EEEEEE", ", c #D8D8D8", "' c #DDDDDD", ") c #7A7A7A", "! c #8C8C8C", "~ c #7F7F7F", "{ c #C9C9C9", "] c #0B0B0B", "^ c #D7D7D7", "/ c #080808", "( c #E0E0E0", "_ c #8F8F8F", ": c #727272", "< c #828282", "[ c #7B7B7B", "} c #6B6B6B", "| c #FFFFFF", "1 c #7C7C7C", "2 c #F8F8F8", "3 c #F7F7F7", "4 c #030303", "5 c #191919", "6 c #C4C4C4", "7 c #090909", "8 c #C1C1C1", "9 c #F4F4F4", "0 c #F5F5F5", "a c #898989", "b c #797979", "c c #CDCDCD", "d c #0C0C0C", "e c #E5E5E5", "f c #C2C2C2", "g c #EAEAEA", "h c #D6D6D6", "i c #CBCBCB", "j c #CFCFCF", "k c #686868", "l c #6C6C6C", "m c #D5D5D5", "n c #D1D1D1", "o c #D9D9D9", "p c #E3E3E3", "q c #C8C8C8", "r c #757575", "s c #FCFCFC", "t c #777777", "u c #DBDBDB", "v c #DFDFDF", "w c #848284", "x c #D3D3D3", "y c #FDFDFD", "z c #787878", "A c #C6C3C6", "B c #717171", "C c #808080", "D c #D0D0D0", "E c #7D7D7D", "F c #F9F9F9", "G c #868686", "H c #747474", "I c #848484", "J c #888888", "K c #FBFBFB", " ", " .+@#$$%&$*=-.*+;>,' ", " )!~{]@$^$$/(_:<~[}| ", " 123+$$4+56789|0||a> ", " b|@cde$f$/$,ghi+jk| ", " l|;mnco'pq+f@m^+@rs ", " t|uo.vjwwww+h=@nx c #D8D8D8", ", c #131313", "' c #D7D7D7", ") c #D2D2D2", "! c #FBFBFB", "~ c #070707", "{ c #111111", "] c #010101", "^ c #1B1B1B", "/ c #090909", "( c #0F0F0F", "_ c #0A0A0A", " ", " ", " ", " ", "....................+", ".@@@@@@@@@@@@@@@@@@#$", ".@@@@@@@@@@@@@@@@@@#$", ".%@@@@@@@@@@@@@@@@@#+", ".%@@@@@@@@@@@@@@@@@#&", ".%@@@@@@@@*@@...@@@#+", ".%@@@@@@@@@@@.==-@@#+", ".%@@@@@@@@@@@@+++@@#;", ".%@@@@@@@@@@@@@@@@@#+", ".%@@@@@@@@@@>%@@@@@#,", ".%@'%@@@@@@@@@@*')@#+", "!@@@@@@@%%%%%@@@@@@#+", ".###################~", "++{]^+]++++++++/+++(_", " ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/0000755000175000017500000000000011004131465017453 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/0000755000175000017500000000000011004131466017475 5ustar stanistanispe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/generate.xpm0000644000175000017500000000272410743421035022004 0ustar stanistani/* XPM */ static char * generate_xpm[] = { "14 14 79 1", " c None", ". c #A6A6A6", "+ c #27251C", "@ c #28261C", "# c #4A4942", "$ c #BEBEBE", "% c #66624E", "& c #A19972", "* c #A49C74", "= c #928B67", "- c #56544A", "; c #8E8E8E", "> c #26241B", ", c #B1A87D", "' c #9C946E", ") c #8C8563", "! c #14130E", "~ c #ADA57A", "{ c #B6AD80", "] c #938C68", "^ c #65614E", "/ c #756F52", "( c #56544B", "_ c #767676", ": c #4E4A3E", "< c #6A6652", "[ c #4B4735", "} c #423E2E", "| c #958D69", "1 c #BFB687", "2 c #6C674C", "3 c #69644A", "4 c #676148", "5 c #74736E", "6 c #99926C", "7 c #CBC18F", "8 c #CDC391", "9 c #CFC592", "0 c #CEC492", "a c #C8BF8E", "b c #6B654B", "c c #C7BE8D", "d c #D2C895", "e c #D1C793", "f c #C3BA8A", "g c #D4CA96", "h c #D1C794", "i c #716B4F", "j c #5A584D", "k c #474747", "l c #BCB385", "m c #AAA278", "n c #A39C73", "o c #C2B989", "p c #D2C894", "q c #CAC08E", "r c #7F7959", "s c #7E7859", "t c #D0C693", "u c #D1C894", "v c #A9A177", "w c #D0C692", "x c #CEC592", "y c #9A926D", "z c #5F5F5F", "A c #847D5D", "B c #CCC290", "C c #CEC491", "D c #413E2D", "E c #59574D", "F c #ABA278", "G c #847E5D", "H c #B0A87D", "I c #C5BC8B", "J c #99916C", "K c #8C8562", "L c #BBB284", "M c #3D3A2B", "N c #73726D", " .+@#$ ", ".%&*=- ", ";>,')! .;$ ", ";>~{]!.^/(.. ", " _:<[]}|1234. ", " ..567890ab. ", " .3cdefghij$", " klcdmnopqr;", " _s,tuvwxy<.", " zABt9CcD. ", " EFGHIJ=K_ ", " $EzsLMNN ", " _k. ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/exit.xpm0000644000175000017500000000151310743421035021156 0ustar stanistani/* XPM */ static char * exit_xpm[] = { "14 14 36 1", " c None", ". c #888888", "+ c #555555", "@ c #91918C", "# c #B6B6B0", "$ c #000000", "% c #CDCDCD", "& c #ABABAB", "* c #444444", "= c #E4E4DC", "- c #1E1213", "; c #BCBCBC", "> c #4C2E30", ", c #935B5E", "' c #605755", ") c #B8B8B2", "! c #666662", "~ c #C8C8C1", "{ c #2C1819", "] c #784244", "^ c #844A4B", "/ c #8D5254", "( c #A36366", "_ c #C2797D", ": c #AA6E71", "< c #52524F", "[ c #8C8C87", "} c #191919", "| c #BDBDB7", "1 c #767672", "2 c #2D2D2C", "3 c #92928D", "4 c #010101", "5 c #565656", "6 c #5A5A5A", "7 c #8B8B8B", " ", " ", " .++++++.", " +@####$+", " %&*#====$+", " &--#====$+", ";+++*>,'=)!~$+", "&{]^/(_:<[}|$+", "&{]^/(_:<===$+", ";+++*>,'====$+", " &--#====$+", " %&*#==12$+", " +@344445", " .+566667"}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/paste.xpm0000644000175000017500000000320510743421035021321 0ustar stanistani/* XPM */ static char * paste_xpm[] = { "14 14 91 1", " c None", ". c #BEBEBE", "+ c #8E8E8E", "@ c #45443F", "# c #45433E", "$ c #A6A6A6", "% c #767676", "& c #5D5D59", "* c #8A897E", "= c #CFCCBD", "- c #CECABB", "; c #474747", "> c #2F2F2F", ", c #45453F", "' c #A2A193", ") c #A4A499", "! c #6F6F69", "~ c #6E6C68", "{ c #B3B0A5", "] c #88867C", "^ c #D1CFBE", "/ c #D0CFBE", "( c #747471", "_ c #9D9B94", ": c #6C6962", "< c #BCB9AC", "[ c #B4B2A5", "} c #5C5C58", "| c #D6D6D6", "1 c #CFCEBD", "2 c #89877F", "3 c #9E9B90", "4 c #CCC9BA", "5 c #CBC9BA", "6 c #C9C7B8", "7 c #43423D", "8 c #767674", "9 c #373731", "0 c #A19F93", "a c #CECBBB", "b c #CDCABB", "c c #CAC8B8", "d c #4B4B46", "e c #6C6C67", "f c #979788", "g c #C6C6B2", "h c #73726B", "i c #CDC9BB", "j c #CAC8B9", "k c #4C4C4A", "l c #8D8D89", "m c #BCBCAE", "n c #DADAC3", "o c #7E7E71", "p c #CAC9B9", "q c #C9C5B7", "r c #2E2E2B", "s c #868679", "t c #CECEB9", "u c #DEDEC7", "v c #BFBFAB", "w c #575753", "x c #42423C", "y c #C7C4B5", "z c #C4C1B1", "A c #BFBDAB", "B c #393933", "C c #CACAB5", "D c #E2E2CB", "E c #E9E9D1", "F c #CCCCB7", "G c #747472", "H c #969285", "I c #BDB9A7", "J c #B9B5A2", "K c #10100E", "L c #A3A392", "M c #E2E2CA", "N c #E6E6CF", "O c #EDEDD5", "P c #F2F2D9", "Q c #62625A", "R c #6A685F", "S c #69675E", "T c #65655D", "U c #E6E6CE", "V c #DADAC4", "W c #8F8F80", "X c #545450", "Y c #949485", "Z c #3E3E37", " ", " .+@#$ .. ", " %&*=-; $;>> ", "$,')!~{]+$;>> ", ";^/(_:<[}||.. ", " @123456789$ ", " 80ab5cdefg; ", " $hi4j6klmno+ ", " ;4p6qrstuvw ", " xyzABCuDEF;", " GHIJKLMNOPQ", " $RS;$TUVWX%", " $$ ;YZ+. ", " % "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/copy.xpm0000644000175000017500000000253010743421035021157 0ustar stanistani/* XPM */ static char * copy_xpm[] = { "14 14 71 1", " c None", ". c #767676", "+ c #BEBEBE", "@ c #979797", "# c #3B3B37", "$ c #A0A090", "% c #707064", "& c #8E8E8E", "* c #70706D", "= c #94948F", "- c #CACAB8", "; c #B7B7A4", "> c #555552", ", c #A6A6A6", "' c #474747", ") c #7D7D70", "! c #4F4F4C", "~ c #777773", "{ c #7E7E71", "] c #CECEB9", "^ c #E0E0C8", "/ c #4B4B43", "( c #787875", "_ c #ACACA1", ": c #D6D6C0", "< c #6E6E63", "[ c #68685D", "} c #CDCDB8", "| c #DDDDC6", "1 c #E3E3CC", "2 c #4C4C44", "3 c #B1B1AC", "4 c #8C8C81", "5 c #DADAC3", "6 c #D4D4BE", "7 c #585852", "8 c #E2E2CA", "9 c #E8E8D0", "0 c #4E4E46", "a c #919181", "b c #CECEB8", "c c #DFDFC8", "d c #969686", "e c #71716F", "f c #CACAB5", "g c #E5E5CE", "h c #ECECD4", "i c #4F4F47", "j c #B3B3A0", "k c #DCDCC5", "l c #E2E2CB", "m c #E7E7D0", "n c #E5E5CD", "o c #474740", "p c #45453D", "q c #ADAD9B", "r c #606058", "s c #44443D", "t c #DBDBC4", "u c #E7E7CF", "v c #C6C6B2", "w c #808073", "x c #70706F", "y c #D6D6D6", "z c #727270", "A c #ACAC9A", "B c #737367", "C c #545450", "D c #5F5F5F", "E c #5E5E57", "F c #000000", " ", " ", " .. ", "+@#$%& &+ ", "&*=-;>,')! ", "&~{]^/(_:<, ", "&[}|123456' ", ",7|890abc1de ", " 'fghijklmno ", " pqr'stuhvw. ", " xx,yzA5BC& ", " +&DD,E', ", " &FFF , ", " ,, "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/open.xpm0000644000175000017500000000136110743421035021147 0ustar stanistani/* XPM */ static char * open_xpm[] = { "14 14 30 1", " c None", ". c #767676", "+ c #BEBEBE", "@ c #8E8E8E", "# c #A6A6A6", "$ c #514F4A", "% c #333029", "& c #77705F", "* c #999489", "= c #B4B4B3", "- c #666052", "; c #474747", "> c #5B574E", ", c #88806D", "' c #DDD9CD", ") c #C6C5C0", "! c #555454", "~ c #22201B", "{ c #A49C88", "] c #BBB4A4", "^ c #FFFEF7", "/ c #AAA9A4", "( c #5A5852", "_ c #555044", ": c #99907B", "< c #555452", "[ c #AFA896", "} c #F3F1E9", "| c #11100D", "1 c #706F6C", " ", " ", " .. ", " +@ #@$%&*=@@ ", " $-;>-,'')!-~ ", " $,{]^^/(_::% ", " @-]^)<-,:::% ", " ;[}%::::::% ", " #_'%::::::% ", " $,%:::,-;# ", " @-%:::$@ ", " ;%&>; ", " #|1# ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/prefs.xpm0000644000175000017500000000272110743421035021326 0ustar stanistani/* XPM */ static char * prefs_xpm[] = { "14 14 79 1", " c None", ". c #A6A6A6", "+ c #787878", "@ c #474747", "# c #727272", "$ c #B2B2B2", "% c #DFDFDF", "& c #767676", "* c #797259", "= c #BEBEBE", "- c #8E8E8E", "; c #4C4C4C", "> c #E1E1E1", ", c #E0E0E0", "' c #8B8B8B", ") c #77756F", "! c #998C61", "~ c #564F36", "{ c #606060", "] c #969696", "^ c #E5E5E5", "/ c #CBA6A6", "( c #DADADA", "_ c #DCDCDC", ": c #C9C9C9", "< c #574E2F", "[ c #5E5E5E", "} c #C7C7C7", "| c #E6E6E6", "1 c #E9E9E9", "2 c #AE7575", "3 c #BCBCBC", "4 c #AFAFAF", "5 c #D0D0D0", "6 c #7E7C76", "7 c #949494", "8 c #D5BBBB", "9 c #CEA2A2", "0 c #BC8F8F", "a c #CACACA", "b c #7F7F7F", "c c #E2DFDF", "d c #C9A2A2", "e c #C9A5A5", "f c #7D7B75", "g c #988B60", "h c #574F36", "i c #D6D6D4", "j c #5E5E5B", "k c #7B7B7B", "l c #E8E8E8", "m c #CFC198", "n c #4B401D", "o c #37311F", "p c #94948F", "q c #BABAB1", "r c #B4B4A9", "s c #909085", "t c #C7CAC5", "u c #5D605B", "v c #636560", "w c #B5B5A9", "x c #B9B9AF", "y c #B9B9B0", "z c #767670", "A c #5C5C5C", "B c #919191", "C c #CDCDC8", "D c #C4C4BF", "E c #D8D9D8", "F c #E1E1DE", "G c #DCDCDA", "H c #E3E3E3", "I c #AEAEAE", "J c #7D7D7D", "K c #494949", "L c #757575", "M c #909082", "N c #545450", " .+@. . ", " @#$%@ &*.", "=-@;>,>>'-)!~.", "{]%^/(_$:{!<. ", "[}|123456!~. ", "-7890a^b!<+. ", " @cde^fgh.ij. ", " .k^lmnopqrs@ ", " {:tuvwxyzA ", " -BCDEFG&-= ", " @H^>I@. ", " .J,KL ", " .@ ", " &MN "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/save_as.xpm0000644000175000017500000000376610743421035021642 0ustar stanistani/* XPM */ static char * save_as_xpm[] = { "14 14 96 2", " c None", ". c #A6A6A6", "+ c #BEBEBE", "@ c #8E8E8E", "# c #6F6236", "$ c #3F381F", "% c #767676", "& c #455254", "* c #293E42", "= c #474747", "- c #776C46", "; c #7E6F3D", "> c #6E6D66", ", c #3E4647", "' c #96A6A9", ") c #D0DFE1", "! c #7A959A", "~ c #5B5F60", "{ c #76888B", "] c #CDDDE0", "^ c #E4ECED", "/ c #C0C0C1", "( c #7A6F4A", "_ c #333E41", ": c #79949A", "< c #CDDCE0", "[ c #D8DADA", "} c #F9F9F9", "| c #C1C1C1", "1 c #465053", "2 c #121B1D", "3 c #7E9FA5", "4 c #CBDCDF", "5 c #E3E1E0", "6 c #CECAC8", "7 c #7B704A", "8 c #7E7C76", "9 c #BCD3D8", "0 c #344F55", "a c #2D3739", "b c #ADC6CB", "c c #E1E0DF", "d c #73653B", "e c #4F4B3D", "f c #6F7878", "g c #B8CFD2", "h c #53858F", "i c #5D959F", "j c #393D3E", "k c #666A6B", "l c #69878D", "m c #EDF1F2", "n c #B9B3AF", "o c #9FA1A2", "p c #94B0B5", "q c #729AA2", "r c #3E5D63", "s c #406871", "t c #49767F", "u c #355359", "v c #364548", "w c #94BBC3", "x c #BAD2D6", "y c #64939C", "z c #748D93", "A c #CDD1D2", "B c #E9E9E9", "C c #5F7377", "D c #48747D", "E c #41666E", "F c #0C1213", "G c #6E9BA5", "H c #67A0AB", "I c #AFB9BC", "J c #9DA6A9", "K c #E2E6E7", "L c #E5E5E5", "M c #AAB2B3", "N c #638F97", "O c #1A282B", "P c #020405", "Q c #253235", "R c #669BA5", "S c #7B979D", "T c #8F9596", "U c #9EBBC0", "V c #CACECF", "W c #6C6F70", "X c #404445", "Y c #65696A", "Z c #2F4C52", "` c #65949D", " . c #BCC4C6", ".. c #788284", "+. c #333737", "@. c #989898", " . . ", " + @ . # $ ", " % & * = - ; > ", " + @ , ' ) ! # ; % ", " % ~ { ] ^ / ( ; > ", ". _ : < [ } | # ; 1 2 ", "= 3 4 5 6 | 7 ; 8 9 0 % ", " a b c 6 d e f g h i j + ", " k l m n o p q r s t u @ ", " . v w x y z A B C D E F ", " = G H I J K L M N O P ", " Q R S T U V W X % ", " Y Z ` ...+.@.+ ", " % = = % "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/save.xpm0000644000175000017500000000311010743421035021136 0ustar stanistani/* XPM */ static char * save_xpm[] = { "14 14 87 1", " c None", ". c #8E8E8E", "+ c #4A5254", "@ c #3F4344", "# c #BEBEBE", "$ c #A6A6A6", "% c #474747", "& c #7A878A", "* c #A5B7BA", "= c #455A5F", "- c #5A5E5E", "; c #657072", "> c #C3D4D7", ", c #E2EAEC", "' c #F7F9FA", ") c #84A0A6", "! c #1D2527", "~ c #62777B", "{ c #A6B6BA", "] c #E4ECED", "^ c #FFFFFF", "/ c #CADADD", "( c #475A5E", "_ c #767676", ": c #2E3638", "< c #9CB5BB", "[ c #E5ECED", "} c #F6F9F9", "| c #9BB9BF", "1 c #6C6E6E", "2 c #788C90", "3 c #ECF2F3", "4 c #F9FBFB", "5 c #D0DEE1", "6 c #83A7B0", "7 c #424E50", "8 c #ACC4C9", "9 c #F7F9F9", "0 c #FDFDFD", "a c #F6F8F9", "b c #C4D5D9", "c c #83A1A7", "d c #617F86", "e c #5B7980", "f c #64848C", "g c #859FA5", "h c #D6E2E5", "i c #D1DEE1", "j c #9BB8BF", "k c #6B848A", "l c #A9B4B7", "m c #949B9C", "n c #6E8C93", "o c #5F7E86", "p c #485D61", "q c #2D3739", "r c #80A4AC", "s c #76989F", "t c #B6BEC1", "u c #CBD0D2", "v c #E5E6E7", "w c #D2D4D5", "x c #7C8B8E", "y c #65878E", "z c #2D3C3F", "A c #6B6F6F", "B c #6C848A", "C c #C9D0D1", "D c #607377", "E c #C4D0D2", "F c #D4D4D4", "G c #8C9395", "H c #212B2E", "I c #666768", "J c #3D4A4D", "K c #6C9199", "L c #96ACB1", "M c #CDD0D1", "N c #929697", "O c #646869", "P c #575757", "Q c #1D2729", "R c #1F2A2C", "S c #414242", "T c #6F7070", "U c #909082", "V c #545450", " ", " .+@# ", " $%&*=. ", " .-;>,')! ", " $%~{]'^^/(_ ", " :<[^^^^^}|@# ", " 123^^^^456=. ", " $7890abcdef! ", " %ghijklmnop_", " qrstuvwxyz%", " ABsCDEFGHI$", " $JKLMNOP ", " $QRST$ ", " _UV "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/remove.xpm0000644000175000017500000000272210743421035021505 0ustar stanistani/* XPM */ static char * remove_xpm[] = { "14 14 79 1", " c None", ". c #BEBEBE", "+ c #8E8E8E", "@ c #878787", "# c #545852", "$ c #757F6F", "% c #81857E", "& c #5D6557", "* c #43493E", "= c #697261", "- c #474747", "; c #A6A6A6", "> c #727B6C", ", c #BECAB6", "' c #B3BFA8", ") c #6C7664", "! c #565D50", "~ c #676F5F", "{ c #9BA98F", "] c #98A58C", "^ c #32362E", "/ c #586752", "( c #C0CCBB", "_ c #C8D1C1", ": c #ACB8A1", "< c #9FAC92", "[ c #99A68D", "} c #7D9175", "| c #252922", "1 c #434A3D", "2 c #697B63", "3 c #84997E", "4 c #7C9277", "5 c #708669", "6 c #61735B", "7 c #566552", "8 c #3A4238", "9 c #3F413E", "0 c #4B5748", "a c #3C433A", "b c #3A4038", "c c #363B34", "d c #313530", "e c #2F322E", "f c #363E34", "g c #83957E", "h c #81927B", "i c #82937E", "j c #677B63", "k c #596955", "l c #586653", "m c #455242", "n c #606060", "o c #919191", "p c #BFBFBF", "q c #050505", "r c #080808", "s c #353535", "t c #82957E", "u c #80917B", "v c #677B62", "w c #576652", "x c #455142", "y c #879D81", "z c #7B8D75", "A c #859781", "B c #6A7F64", "C c #596855", "D c #5C6D57", "E c #445141", "F c #4B5149", "G c #52634C", "H c #4F5E4A", "I c #4C5C48", "J c #495845", "K c #465443", "L c #1B1B1B", "M c #4C4C4C", "N c #A8A8A8", " ", " .+++++ ", " @#$%&*=-; ", " +>,')!~{]^ ", " +/(_:<{[}| ", " ;123456789 ", " -0abcdef+ ", " -ghijklmnop ", " -ghijklmqrs ", " -tuivkwxqrr ", " -yzABCDEqr ", " FGHIJKLM ", " .+++++N ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/refresh.xpm0000644000175000017500000000072710743421035021651 0ustar stanistani/* XPM */ static char * refresh_xpm[] = { "14 14 11 1", " c None", ". c #000000", "+ c #566B43", "@ c #4C603C", "# c #526741", "$ c #5A7046", "% c #37452B", "& c #425334", "* c #445636", "= c #475937", "- c #5C7449", " . ", " .. ", " .+@.. ", " #$##@.. ", " . .. .%. ", " . . .%. ", " .. .. ", " .. .. ", " .&. . . ", " .*...#= ", " .##-#@. ", " ...@* ", " .. ", " . "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/about.xpm0000644000175000017500000000211310743421035021314 0ustar stanistani/* XPM */ static char * about_xpm[] = { "14 14 53 1", " c None", ". c #FFFFFF", "+ c #FFFBF7", "@ c #EFEBE7", "# c #F7F3F7", "$ c #E7E3DF", "% c #494941", "& c #F7E7D7", "* c #E7CB96", "= c #DFAE61", "- c #E7B651", "; c #E7CBA6", "> c #C7C3BE", ", c #515149", "' c #969696", ") c #D7CBC7", "! c #E7BA49", "~ c #DFAE41", "{ c #C78638", "] c #C7A68E", "^ c #DFDBD7", "/ c #C77D38", "( c #A66551", "_ c #D7D3CF", ": c #D7A641", "< c #AE5D30", "[ c #9E5D49", "} c #DFCFCF", "| c #000000", "1 c #F7EFEF", "2 c #C79249", "3 c #B67130", "4 c #A64D28", "5 c #963828", "6 c #A68679", "7 c #AEA6A6", "8 c #595951", "9 c #302C28", "0 c #E7DBCF", "a c #BE9271", "b c #9E5541", "c c #AE8E8E", "d c #A69E96", "e c #181810", "f c #BEB6B6", "g c #797569", "h c #CFCBCF", "i c #383830", "j c #282820", "k c #8E8686", "l c #BEBAB6", "m c #413C38", "n c #080C08", " ", " ... +@ ", " ++.++#.++$% ", " $+&*=-=;@>, ", " ')--!-~{]$^ ", "@+.*!!!-~/(_.+", " @.;:~!~{<[}@)", " |^12//3456789", " 1+0abb[c_de ", " +.@fgf^@+hi ", " _^'jek1+1li ", " %iee g'km9 ", " nne ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/cut.xpm0000644000175000017500000000072310743421035021002 0ustar stanistani/* XPM */ static char * cut_xpm[] = { "14 14 11 1", " c None", ". c #767676", "+ c #5F5F5F", "@ c #2F2F2F", "# c #BEBEBE", "$ c #8E8E8E", "% c #D6D6D6", "& c #A6A6A6", "* c #474747", "= c #171717", "- c #000000", " ", " ", " . ", " +@ ", " .@# ", "#$$# +@%%#$& ", "+$+@ .@#&*@+& ", "+$+@*=--** ", "#$$#&=$$ ", " &*= ", " &.%* ", " $+.& ", " #$& ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/tutorial.xpm0000644000175000017500000000230610743421035022051 0ustar stanistani/* XPM */ static char * tutorial_xpm[] = { "14 14 61 1", " c None", ". c #8E8E8E", "+ c #A6A6A6", "@ c #767676", "# c #3A4E56", "$ c #465E67", "% c #3E555E", "& c #474747", "* c #BEBEBE", "= c #41484A", "- c #6B8E9B", "; c #5F828F", "> c #5E808D", ", c #1F2A2F", "' c #C0C0C0", ") c #445962", "! c #658896", "~ c #49636D", "{ c #5B5F60", "] c #374950", "^ c #678A98", "/ c #3E4D52", "( c #8D8D8C", "_ c #686965", ": c #678895", "< c #618491", "[ c #3C3C3C", "} c #AEAFAD", "| c #4D4E4C", "1 c #3A5058", "2 c #678A97", "3 c #B4B4B3", "4 c #777974", "5 c #524646", "6 c #373236", "7 c #212D31", "8 c #3A4746", "9 c #56696A", "0 c #5A7B87", "a c #ACACAA", "b c #323331", "c c #382828", "d c #CEB6B4", "e c #F1F0EC", "f c #B1B1AE", "g c #666664", "h c #4B4A49", "i c #6A6B68", "j c #756C6D", "k c #483C3C", "l c #6D7475", "m c #C8CFCC", "n c #E1E0DD", "o c #B2B3B1", "p c #4F504F", "q c #495153", "r c #747C7B", "s c #979B98", "t c #686F69", "u c #696D6E", "v c #0A0E0F", " ", " ......+ ", " @#$%%%%& ", " *=-;>>>,' ", " .)!>>>~{' ", " +]^>>>>/(_ ", " &:<>>>>[}| ", " .12>>>>,34@ ", " 567890~{ab ", " cdeefgh.i. ", " jklmeenop* ", " +&qrst@ ", " *.uv ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/gtk/new.xpm0000644000175000017500000000260410743421035021000 0ustar stanistani/* XPM */ static char * new_xpm[] = { "14 14 74 1", " c None", ". c #A6A6A6", "+ c #8E8E8E", "@ c #50504D", "# c #707064", "$ c #474740", "% c #474747", "& c #7A7A6D", "* c #B1B19F", "= c #DCDCC5", "- c #B5B5A4", "; c #767676", "> c #BEBEBE", ", c #4B4B4B", "' c #52524C", ") c #CBCBB5", "! c #D6D6C0", "~ c #D8D8C1", "{ c #DDDDC5", "] c #E2E2CA", "^ c #88887A", "/ c #949494", "( c #828282", "_ c #6F6F68", ": c #CDCDB7", "< c #D7D7C0", "[ c #DADAC3", "} c #E0E0C8", "| c #E5E5CD", "1 c #D7D7C1", "2 c #6A6A64", "3 c #9D9D9B", "4 c #B2B2AF", "5 c #8F8F80", "6 c #D6D6BF", "7 c #DFDFC7", "8 c #E8E8CF", "9 c #EAEAD2", "0 c #EFEFD6", "a c #CFCFBA", "b c #9E9E99", "c c #7F7F7A", "d c #A3A392", "e c #E4E4CC", "f c #EBEBD2", "g c #F2F2D9", "h c #F3F3DA", "i c #848479", "j c #1A1A19", "k c #B9B9A5", "l c #D9D9C2", "m c #E1E1CA", "n c #E7E7CF", "o c #EEEED5", "p c #F4F4DB", "q c #E8E8D1", "r c #757569", "s c #5E5E59", "t c #DDDDC6", "u c #E9E9D0", "v c #F5F5DC", "w c #BBBBA8", "x c #D8D8C2", "y c #F0F0D7", "z c #99998E", "A c #EDEDD4", "B c #F1F1D8", "C c #68685D", "D c #63635E", "E c #D2D2BC", "F c #A9A997", "G c #71716F", "H c #909082", "I c #545450", " .. ", " +@#$ ", " .%&*=-; ", " >,')!~{]^/ ", " +(_:<[}|12 ", " +34567890a% ", " +bcd[ef0ghi. ", " +jklmnogppqr.", " +s[teu0gvvvw%", " %x]nfyhv0i% ", " .zn9ABh[C. ", " DEoynF; ", " +^BmCG ", " ;HI "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/generate.xpm0000644000175000017500000000072010743421035022017 0ustar stanistani/* XPM */ static char * generate_xpm[] = { "16 16 6 1", " c None", ". c #000080", "+ c #FFFFFF", "@ c #000000", "# c #C0C0C0", "$ c #0000FF", " ", " ", " . ", " .+ ", " .+. ", " .+.. ", " .+... ", " @@@@@@@ .+... ", " @+++++#.+... ", " @++++#.+... ", " @+++#.+... ", " @+++#.... ", " @++#.+.. ", " @++#$$ ", " @@#$ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/exit.xpm0000644000175000017500000000065610743421035021206 0ustar stanistani/* XPM */ static char * exit_xpm[] = { "16 16 4 1", " c None", ". c #000000", "+ c #FF0000", "@ c #FFFFFF", " ", " ... ", " . .+. ", " .. .+. ", " .@. .+. ", " ....@@. .+. ", " .@@@@@@. .+. ", " ..@@@@@@@..+. ", " ..@@@@@@. .+. ", " .....@@.. .+. ", " .....@.. .+. ", " ... .+. ", " .. .+. ", " . .+. ", " ... ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/paste.xpm0000644000175000017500000000075310743421035021347 0ustar stanistani/* XPM */ static char * paste_xpm[] = { "16 16 8 1", " c None", ". c #000000", "+ c #FFFF00", "@ c #808000", "# c #C0C0C0", "$ c #808080", "% c #FFFFFF", "& c #000080", " ", " .... ", " .....++..... ", " .@#@.+..+.#@#. ", "$.#$.%%%%%%.$@. ", "$.@$........$#. ", "$.#@#@##&&&&&&. ", "$.@#@#@$&%%%%&& ", "$.#@#@#$&%%%%&%&", "$.@#@#@$&%..%&&&", "$.#@#@#$&%%%%%%&", "$.@#@#@$&%....%&", " $......&%%%%%%&", " $$$$$$&&&&&&&&", " $$$$$$$ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/copy.xpm0000644000175000017500000000067510743421035021210 0ustar stanistani/* XPM */ static char * copy_xpm[] = { "16 16 5 1", " c None", ". c #000080", "+ c #808080", "@ c #FFFFFF", "# c #000000", " ", " ...... ", "+.@@@@.. ", "+.@@@@.@# ", "+.@##@....... ", "+.@@@@+.@@@@.# ", "+.@####.@@@@.@# ", "+.@@@@+.@##@....", "+.@####.@@@@@@@.", "+.@@@@+.@#####@.", "+.......@@@@@@@.", "+++++++.@#####@.", " +.@@@@@@@.", " +.........", " ++++++++ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/open.xpm0000644000175000017500000000071410743421035021171 0ustar stanistani/* XPM */ static char * open_xpm[] = { "16 16 6 1", " c None", ". c #000000", "+ c #FFFF00", "@ c #FFFFFF", "# c #808080", "$ c #808000", " ", " ", " ... ", " . . .", " ... ..", " .+@+...... ...", " .@+@+@+@+. ", " #.+@+@+@+@. ", " #.@+@+.........", " #.+@+.$$$$$$$$.", " #.@+.$$$$$$$$. ", " #.+.$$..$$$$. ", " #..$$$$$$$$. ", " #.......... ", " ######### ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/prefs.xpm0000644000175000017500000000064010743421035021345 0ustar stanistani/* XPM */ static char * prefs_xpm[] = { "16 16 3 1", " c None", ". c #000000", "+ c #FFFFFF", " ", " ..... .. ", " .+.+++... ", " .....+.+.+++.. ", " .++.+.+.+.++.. ", " .+.+.+.+.+.... ", " .++.+++.+.. .. ", " .+++++++.+. ", " .+++++++++. ", " .+..+....+. ", " .+++++++++. ", " .+..+....+. ", " .+++++++++. ", " ........... ", " ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/save_as.xpm0000644000175000017500000000071710743421035021654 0ustar stanistani/* XPM */ static char * save_as_xpm[] = { "16 16 6 1", " c None", ". c #000000", "+ c #808000", "@ c #C0C0C0", "# c #FFFFFF", "$ c #808080", " ", " ", "........... ", ".+.@#@#@.@. ", ".+.#@...........", ".+.@#.+.@#@#@.@.", ".+.#$.+.#@#@#...", ".+....+.@#@#@.+.", ".+++$.+.#@#@#.+.", ".+....+.......+.", ".+.$$.+++++++++.", ".+.$$.+.......+.", " .....+.$$$.@.+.", " $.+.$$$.@.+.", " $$..........", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/save.xpm0000644000175000017500000000071410743421035021166 0ustar stanistani/* XPM */ static char * save_xpm[] = { "16 16 6 1", " c None", ". c #000000", "+ c #808000", "@ c #C0C0C0", "# c #FFFFFF", "$ c #808080", " ", " ", " ............. ", " .+.@#@#@#@.@. ", " .+.#@#@#@#... ", " .+.@#@#@#@.+. ", " .+.#@#@#@#.+. ", " .+.@#@#@#@.+. ", " .++.......++. ", " .+++++++++++. ", " .++........+. ", " .++..$..@@.+. ", " .++.$.$.@@.+. ", " .++..$..@@.+. ", " ............ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/remove.xpm0000644000175000017500000000067710743421035021535 0ustar stanistani/* XPM */ static char * remove_xpm[] = { "16 16 5 1", " c None", ". c #000000", "+ c #C0C0C0", "@ c #808080", "# c #FFFFFF", " ", " ", " ..... ", " ....++++.... ", " .@@@@@@@@@@. ", " .@+@+#@+@+@. ", " .@@@@@@@@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " .@+@+#@+@. ", " ........ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/refresh.xpm0000644000175000017500000000051710743421035021667 0ustar stanistani/* XPM */ static char * refresh_xpm[] = { "14 14 2 1", " c None", ". c #000080", " ", " ...... ", " ........ ", " ... .. ", " ... .. ", "..... ", " ... . ", " . ... ", " .....", " .. ... ", " .. ... ", " ........ ", " ...... ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/cut.xpm0000644000175000017500000000063610743421035021026 0ustar stanistani/* XPM */ static char * cut_xpm[] = { "16 16 3 1", " c None", ". c #808080", "+ c #000080", " . . ", " . . ", " + + ", " +. .+ ", " ++ ++ ", " .+ +. ", " +++ ", " .+. ", " +++ ", " + +++ ", " +++ + .+ ", " +. + + + ", " + + +. + ", " + .+ ++ ", " ++ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/tutorial.xpm0000644000175000017500000000073710743421035022100 0ustar stanistani/* XPM */ static char * tutorial_xpm[] = { "16 16 7 1", " c None", ". c #000000", "+ c #FFFFFF", "@ c #FFFF00", "# c #000080", "$ c #C0C0C0", "% c #808080", " ", " ...... ", " ..++@+@+.. ", " .@+@####+@+. ", " .++##@$##++. ", " .+@+#%++##@++. ", " .+++@+@%#%++@. ", " .+@+++%#++@++. ", " .+++@+#%@+++@. ", " .@+++@+++@+. ", " .++@+##@+++. ", " .+++@+++.. ", " .+@..... ", " .+. ", " .. ", " . "}; spe-0.8.4.h/_spe/plugins/wxGlade/icons/msw/new.xpm0000644000175000017500000000067410743421035021026 0ustar stanistani/* XPM */ static char * new_xpm[] = { "16 16 5 1", " c None", ". c #000000", "+ c #FFFFFF", "@ c #808080", "# c #C0C0C0", " ", " ", " ....... ", " .+++++.. ", " @.+++++.+. ", " @.+++++.... ", " @.++++++##. ", " @.++++++++. ", " @.++++++++. ", " @.++++++++. ", " @.++++++++. ", " @.++++++++. ", " @.++++++++. ", " @.......... ", " @@@@@@@@@ ", " "}; spe-0.8.4.h/_spe/plugins/wxGlade/codegen/lisp_codegen.py0000644000175000017500000014717710743421035022211 0ustar stanistani# lisp_codegen.py: lisp code generator # $Id: lisp_codegen.py,v 1.5 2006/11/30 16:25:33 jkt Exp $ # # Copyright (c) 2005 Surendra K Singhi # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY """\ How the code is generated: every time the end of an object is reached during the parsing of the xml tree, either the function 'add_object' or the function 'add_class' is called: the latter when the object is a toplevel one, the former when it is not. In the last case, 'add_object' calls the appropriate ``writer'' function for the specific object, found in the 'obj_builders' dict. Such function accepts one argument, the CodeObject representing the object for which the code has to be written, and returns 3 lists of strings, representing the lines to add to the '__init__', '__set_properties' and '__do_layout' methods of the parent object. """ import sys, os, os.path import common, config import cStringIO from xml_parse import XmlParsingError import re try: set except NameError: from sets import Set as set # these two globals must be defined for every code generator module language = 'lisp' writer = sys.modules[__name__] # the writer is the module itself # default extensions for generated files: a list of file extensions default_extensions = ['lisp'] """\ dictionary that maps the lines of code of a class to the name of such class: the lines are divided in 3 categories: '__init__', '__set_properties' and '__do_layout' """ classes = None """dictionary of ``writers'' for the various objects""" obj_builders = {} """\ dictionary of ``property writer'' functions, used to set the properties of a toplevel object """ obj_properties = {} # random number used to be sure that the replaced tags in the sources are # the right ones (see SourceFileContent and add_class) nonce = None # lines common to all the generated files (import of wxCL, ...) header_lines = [] class_lines = [] init_lines = [] # if True, generate a file for each custom class multiple_files = False # if not None, it is the single source file to write into output_file = None # if not None, it is the directory inside which the output files are saved out_dir = None import_packages = [] use_new_namespace = True def cn(class_name): if use_new_namespace: if class_name[:2] == 'wx': return 'wx' + class_name[2:] elif class_name[:4] == 'EVT_': return 'wx' + class_name return class_name def cn_f(flags): if use_new_namespace: return "|".join([cn(f) for f in str(flags).split('|')]) else: return str(flags) # ALB 2004-12-05: wx version we are generating code for for_version = (2, 4) class ClassLines: """\ Stores the lines of lisp code for a custom class """ def __init__(self): self.init = [] # lines of code to insert in the __init__ method # (for children widgets) self.parents_init = [] # lines of code to insert in the __init__ for # container widgets (panels, splitters, ...) self.sizers_init = [] # lines related to sizer objects declarations self.props = [] # lines to insert in the __set_properties method self.layout = [] # lines to insert in the __do_layout method self.dependencies = {} # names of the modules this class depends on self.done = False # if True, the code for this class has already # been generated # ALB 2004-12-05 self.event_handlers = [] # lines to bind events # end of class ClassLines class SourceFileContent: """\ Keeps info about an existing file that has to be updated, to replace only the lines inside a wxGlade block, an to keep the rest of the file as it was """ def __init__(self, name=None, content=None, classes=None): self.name = name # name of the file self.content = content # content of the source file, if it existed # before this session of code generation self.classes = classes # classes declared in the file self.new_classes = [] # new classes to add to the file (they are # inserted BEFORE the old ones) if classes is None: self.classes = {} self.spaces = {} # indentation level for each class # ALB 2004-12-05 self.event_handlers = {} # list of event handlers for each class if self.content is None: self.build_untouched_content() def build_untouched_content(self): """\ Builds a string with the contents of the file that must be left as is, and replaces the wxGlade blocks with tags that in turn will be replaced by the new wxGlade blocks """ class_name = None new_classes_inserted = False # regexp to match class declarations # jdubery - less precise regex, but matches definitions with base # classes having module qualified names class_decl = re.compile(r'^\s*class\s+([a-zA-Z_]\w*)\s*' '(\([\s\w.,]*\))?:\s*$') # regexps to match wxGlade blocks block_start = re.compile(r'^(\s*)#\s*begin\s+wxGlade:\s*' '([A-Za-z_]+\w*)??[.]?(\w+)\s*$') block_end = re.compile(r'^\s*#\s*end\s+wxGlade\s*$') # regexp to match event handlers # ALB 2004-12-05 event_handler = re.compile(r'^\s+def\s+([A-Za-z_]+\w*)\s*\(.*\):\s*' '#\s*wxGlade:\s*(\w+)\.\s*$') inside_block = False inside_triple_quote = False triple_quote_str = None tmp_in = open(self.name) out_lines = [] for line in tmp_in: quote_index = -1 if not inside_triple_quote: triple_dquote_index = line.find('"""') triple_squote_index = line.find("'''") if triple_squote_index == -1: quote_index = triple_dquote_index tmp_quote_str = '"""' elif triple_dquote_index == -1: quote_index = triple_squote_index tmp_quote_str = "'''" else: quote_index, tmp_quote_str = min( (triple_squote_index, "'''"), (triple_dquote_index, '"""')) if not inside_triple_quote and quote_index != -1: inside_triple_quote = True triple_quote_str = tmp_quote_str if inside_triple_quote: end_index = line.rfind(triple_quote_str) if quote_index < end_index and end_index != -1: inside_triple_quote = False result = class_decl.match(line) if not inside_triple_quote and result is not None: ## print ">> class %r" % result.group(1) if class_name is None: # this is the first class declared in the file: insert the # new ones before this out_lines.append('<%swxGlade insert new_classes>' % nonce) new_classes_inserted = True class_name = result.group(1) self.classes[class_name] = 1 # add the found class to the list # of classes of this module out_lines.append(line) elif not inside_block: result = block_start.match(line) if not inside_triple_quote and result is not None: ## print ">> block %r %r %r" % ( ## result.group(1), result.group(2), result.group(3)) # replace the lines inside a wxGlade block with a tag that # will be used later by add_class spaces = result.group(1) which_class = result.group(2) which_block = result.group(3) if which_class is None: which_class = class_name self.spaces[which_class] = spaces inside_block = True if class_name is None: out_lines.append('<%swxGlade replace %s>' % \ (nonce, which_block)) else: out_lines.append('<%swxGlade replace %s %s>' % \ (nonce, which_class, which_block)) else: #- ALB 2004-12-05 ---------- result = event_handler.match(line) if not inside_triple_quote and result is not None: which_handler = result.group(1) which_class = result.group(2) self.event_handlers.setdefault( which_class, {})[which_handler] = 1 if class_name is not None and self.is_end_of_class(line): # add extra event handlers here... out_lines.append('<%swxGlade event_handlers %s>' % (nonce, class_name)) #--------------------------- out_lines.append(line) if self.is_import_line(line): # add a tag to allow extra modules out_lines.append('<%swxGlade extra_modules>\n' % nonce) else: # ignore all the lines inside a wxGlade block if block_end.match(line) is not None: inside_block = False if not new_classes_inserted: # if we are here, the previous ``version'' of the file did not # contain any class, so we must add the new_classes tag at the # end of the file out_lines.append('<%swxGlade insert new_classes>' % nonce) tmp_in.close() # set the ``persistent'' content of the file self.content = "".join(out_lines) def is_import_line(self, line): if use_new_namespace: return line.startswith('import wx') else: return line.startswith('from wxLisp.wx import *') def is_end_of_class(self, line): return line.strip().startswith('# end of class ') # end of class SourceFileContent # if not None, it is an instance of SourceFileContent that keeps info about # the previous version of the source to generate previous_source = None def tabs(number): return ' ' * number # if True, overwrite any previous version of the source file instead of # updating only the wxGlade blocks _overwrite = False # if True, enable gettext support _use_gettext = False _quote_str_pattern = re.compile(r'\\[natbv"]?') def _do_replace(match): if match.group(0) == '\\': return '\\\\' else: return match.group(0) def quote_str(s, translate=True, escape_chars=True): """\ returns a quoted version of 's', suitable to insert in a lisp source file as a string object. Takes care also of gettext support """ if not s: return '""' s = s.replace('"', r'\"') if escape_chars: s = _quote_str_pattern.sub(_do_replace, s) else: s = s.replace('\\', r'\\') # just quote the backslashes try: unicode(s, 'ascii') if _use_gettext and translate: return '_("' + s + '")' else: return '"' + s + '"' except UnicodeDecodeError: if _use_gettext and translate: return '_(u"' + s + '")' else: return 'u"' + s + '"' def initialize(app_attrs): """\ Writer initialization function. - app_attrs: dict of attributes of the application. The following two are always present: path: output path for the generated code (a file if multi_files is False, a dir otherwise) option: if True, generate a separate file for each custom class """ out_path = app_attrs['path'] multi_files = app_attrs['option'] global classes, header_lines, multiple_files, previous_source, nonce, \ _current_extra_modules, _use_gettext, _overwrite, import_packages import time, random try: _use_gettext = int(app_attrs['use_gettext']) except (KeyError, ValueError): _use_gettext = False # overwrite added 2003-07-15 try: _overwrite = int(app_attrs['overwrite']) except (KeyError, ValueError): _overwrite = False # this is to be more sure to replace the right tags nonce = '%s%s' % (str(time.time()).replace('.', ''), random.randrange(10**6, 10**7)) # ALB 2004-01-18 global use_new_namespace try: use_new_namespace = int(app_attrs['use_new_namespace']) except (KeyError, ValueError): pass # use the default value # ALB 2004-12-05 global for_version try: for_version = tuple([int(t) for t in app_attrs['for_version'].split('.')[:2]]) except (KeyError, ValueError): if common.app_tree is not None: for_version = common.app_tree.app.for_version else: for_version = (2, 4) # default... try: _use_gettext = int(app_attrs['use_gettext']) except (KeyError, ValueError): _use_gettext = False try: _overwrite = int(app_attrs['overwrite']) except (KeyError, ValueError): _overwrite = False # add coding (PEP 263) try: _encoding = app_attrs['encoding'] except (KeyError, ValueError): _encoding = None classes = {} _current_extra_modules = {} header_lines = [';;; generated by wxGlade %s on %s%s\n\n' % \ (common.version, time.asctime(), common.generated_from()), '(asdf:operate \'asdf:load-op \'wxcl)\n', '(use-package \"FFI\")\n' '(ffi:default-foreign-language :stdc)\n\n' ] if not config.preferences.write_timestamp: header_lines[0] = ';;; generated by wxGlade %s%s\n\n' % \ (common.version, common.generated_from()) import_packages = set (["wxCL", "wxFrame", "wx_main", "wx_wrapper", "wxWindow", "wxColour", "wxEvtHandler", "wxEvent"]) # add coding (PEP 263) # if _encoding: # header_lines.insert(0, "# -*- coding: %s -*-\n" % _encoding) multiple_files = multi_files if not multiple_files: global output_file, output_file_name if not _overwrite and os.path.isfile(out_path): # the file exists, we must keep all the lines not inside a wxGlade # block. NOTE: this may cause troubles if out_path is not a valid # lisp file, so be careful! previous_source = SourceFileContent(out_path) else: # if the file doesn't exist, create it and write the ``intro'' previous_source = None output_file = cStringIO.StringIO() output_file_name = out_path #-SKS for line in header_lines: #-SKS output_file.write(line) output_file.write('<%swxGlade extra_modules>\n' % nonce) output_file.write('\n') else: previous_source = None global out_dir if not os.path.isdir(out_path): raise XmlParsingError("'path' must be a directory when generating"\ " multiple output files") out_dir = out_path def finalize(): """\ Writer ``finalization'' function: flushes buffers, closes open files, ... """ if previous_source is not None: # insert all the new custom classes inside the old file tag = '<%swxGlade insert new_classes>' % nonce if previous_source.new_classes: code = "".join(previous_source.new_classes) else: code = "" previous_source.content = previous_source.content.replace(tag, code) tag = '<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) previous_source.content = previous_source.content.replace(tag, code) # now remove all the remaining <123415wxGlade ...> tags from the # source: this may happen if we're not generating multiple files, # and one of the container class names is changed tags = re.findall('(<%swxGlade replace ([a-zA-Z_]\w*) +\w+>)' % nonce, previous_source.content) for tag in tags: indent = previous_source.spaces.get(tag[1], tabs(2)) comment = '%s# content of this block not found: ' \ 'did you rename this class?\n%spass\n' % (indent, indent) previous_source.content = previous_source.content.replace(tag[0], comment) # ALB 2004-12-05 tags = re.findall('<%swxGlade event_handlers \w+>' % nonce, previous_source.content) for tag in tags: previous_source.content = previous_source.content.replace(tag, "") # write the new file contents to disk common.save_file(previous_source.name, previous_source.content, 'codegen') elif not multiple_files: global output_file em = "".join(_current_extra_modules.keys()) content = output_file.getvalue().replace( '<%swxGlade extra_modules>\n' % nonce, em) output_file.close() try: common.save_file(output_file_name, content, 'codegen') # make the file executable if _app_added: os.chmod(output_file_name, 0755) except IOError, e: raise XmlParsingError(str(e)) except OSError: pass # this isn't necessary a bad error del output_file def test_attribute(obj): """\ Returns True if 'obj' should be added as an attribute of its parent's class, False if it should be created as a local variable of __do_layout. To do so, tests for the presence of the special property 'attribute' """ try: return int(obj.properties['attribute']) except (KeyError, ValueError): return True # this is the default def add_object(top_obj, sub_obj): """\ adds the code to build 'sub_obj' to the class body of 'top_obj'. """ global import_packages try: klass = classes[top_obj.klass] except KeyError: klass = classes[top_obj.klass] = ClassLines() try: builder = obj_builders[sub_obj.base] except KeyError: # no code generator found: write a comment about it klass.init.extend(['\n', ';;; code for %s (type %s) not generated: ' 'no suitable writer found' % (sub_obj.name, sub_obj.klass),'\n']) else: try: sub_obj.name = sub_obj.name.replace('_','-') sub_obj.parent.name = sub_obj.parent.name.replace('_','-') if(sub_obj.name != "spacer"): class_lines.append(sub_obj.name) if (sub_obj.klass == "wxBoxSizer" or sub_obj.klass == "wxStaticBoxSizer" or sub_obj.klass == "wxGridSizer" or sub_obj.klass == "wxFlexGridSizer"): import_packages = import_packages | set(["wxSizer"]) else: if (sub_obj.klass != "spacer"): import_packages = import_packages | set([sub_obj.klass]) if (sub_obj.klass == "wxMenuBar" ): import_packages = import_packages | set(["wxMenu"]) init, props, layout = builder.get_code(sub_obj) except: print sub_obj raise # this shouldn't happen if sub_obj.in_windows: # the object is a wxWindow instance # --- patch 2002-08-26 ------------------------------------------ if sub_obj.is_container and not sub_obj.is_toplevel: init.reverse() klass.parents_init.extend(init) else: klass.init.extend(init) # --------------------------------------------------------------- # ALB 2004-12-05 mycn = getattr(builder, 'cn', cn) if hasattr(builder, 'get_events'): evts = builder.get_events(sub_obj) for id, event, handler in evts: klass.event_handlers.append((id, mycn(event), handler)) elif 'events' in sub_obj.properties: id_name, id = generate_code_id(sub_obj) #if id == '-1': id = 'self.%s.GetId()' % sub_obj.name if id == '-1': id = '#obj.%s' % sub_obj.name for event, handler in sub_obj.properties['events'].iteritems(): klass.event_handlers.append((id, mycn(event), handler)) else: # the object is a sizer # ALB 2004-09-17: workaround (hack) for static box sizers... # SKS- if sub_obj.base == 'wxStaticBoxSizer': #SKS- klass.parents_init.insert(1, init.pop(0)) klass.sizers_init.extend(init) klass.props.extend(props) klass.layout.extend(layout) if multiple_files and \ (sub_obj.is_toplevel and sub_obj.base != sub_obj.klass): key = 'from %s import %s\n' % (sub_obj.klass, sub_obj.klass) klass.dependencies[key] = 1 ## for dep in _widget_extra_modules.get(sub_obj.base, []): for dep in getattr(obj_builders.get(sub_obj.base), 'import_modules', []): klass.dependencies[dep] = 1 def add_sizeritem(toplevel, sizer, obj, option, flag, border): """\ writes the code to add the object 'obj' to the sizer 'sizer' in the 'toplevel' object. """ # an ugly hack to allow the addition of spacers: if obj_name can be parsed # as a couple of integers, it is the size of the spacer to add global import_packages sizer.name = sizer.name.replace('_','-') obj_name = obj.name try: w, h = [ int(s) for s in obj_name.split(',') ] except ValueError: if obj.base == 'wxNotebook' and for_version < (2, 5): obj_name = cn('wxNotebookSizer') + '(%s)' % obj_name else: obj_name = '(%d, %d)' % (w, h) # it was the dimension of a spacer try: klass = classes[toplevel.klass] except KeyError: klass = classes[toplevel.klass] = ClassLines() flag = '%s' % cn_f(flag) flag = flag.strip().replace('|',' ') if flag.find(' ') != -1: flag = '(logior %s)' % flag if (obj.klass == "wxBoxSizer" or obj.klass == "wxStaticBoxSizer" or obj.klass == "wxGridSizer" or obj.klass == "wxFlexGridSizer"): buffer = '(wxSizer_AddSizer (slot-%s obj) (slot-%s obj) %s %s %s nil)\n' % \ (sizer.name, obj_name, option, flag, cn_f(border)) else: buffer = '(wxSizer_AddWindow (slot-%s obj) (slot-%s obj) %s %s %s nil)\n' % \ (sizer.name, obj_name, option, flag,cn_f(border)) print klass.layout.append(buffer) def add_class(code_obj): """\ Generates the code for a custom class. """ global _current_extra_modules, import_packages if not multiple_files: # in this case, previous_source is the SourceFileContent instance # that keeps info about the single file to generate prev_src = previous_source else: # let's see if the file to generate exists, and in this case # create a SourceFileContent instance filename = os.path.join(out_dir, code_obj.klass.replace('.', '_') + '.py') if _overwrite or not os.path.exists(filename): prev_src = None else: prev_src = SourceFileContent(filename) _current_extra_modules = {} if classes.has_key(code_obj.klass) and classes[code_obj.klass].done: return # the code has already been generated try: #SKS- builder = obj_builders[code_obj.base] builder="" mycn = getattr(builder, 'cn', cn) mycn_f = getattr(builder, 'cn_f', cn_f) except KeyError: raise # this is an error, let the exception be raised if prev_src is not None and prev_src.classes.has_key(code_obj.klass): is_new = False indentation = prev_src.spaces[code_obj.klass] else: # this class wasn't in the previous version of the source (if any) is_new = True indentation = tabs(2) ## mods = _widget_extra_modules.get(code_obj.base) mods = getattr(builder, 'extra_modules', []) if mods: for m in mods: _current_extra_modules[m] = 1 buffer = [] write = buffer.append for l in header_lines: write(l) for l in import_packages: write('(use-package :%s)\n' % l) if not classes.has_key(code_obj.klass): # if the class body was empty, create an empty ClassLines classes[code_obj.klass] = ClassLines() ## # first thing to do, call the property writer: we do this now because it ## # can have side effects that modify the ClassLines instance (this is used ## # in the toplevel menubar) ## props_builder = obj_properties.get(code_obj.base) ## write_body = len(classes[code_obj.klass].props) ## if props_builder: ## obj_p = obj_properties[code_obj.base](code_obj) ## if not write_body: write_body = len(obj_p) ## else: obj_p = [] tab = indentation if is_new: base = mycn(code_obj.base) if code_obj.preview and code_obj.klass == base: import random klass = code_obj.klass + ('_%d' % random.randrange(10**8, 10**9)) else: klass = code_obj.klass write('\n(defclass %s()\n' % klass) write("\t((top-window :initform nil :accessor slot-top-window)") for l in class_lines: write("\n"+tab+"("+l+" :initform nil :accessor slot-"+l+")") write("))\n") write("\n(defun make-%s ()\n" % klass) write(tab+"(let ((obj (make-instance '%s)))\n" % klass) write(tab+" (init obj)\n") write(tab+" (set-properties obj)\n") write(tab+" (do-layout obj)\n") write(tab+" obj))\n") write('\n(defmethod init ((obj %s))\n' % klass) write("\"Method creates the objects contained in the class.\"\n") # __init__ begin tag write(indentation + ';;;begin wxGlade: %s.__init__\n' % code_obj.klass) prop = code_obj.properties style = prop.get("style", None) if style: style = mycn_f(style) style = style.strip().replace('.','') style = style.replace('|',' ') if style.find(' ') != -1: style = '(logior %s)' % style if code_obj.base == "wxFrame": write(indentation + "(setf (slot-top-window obj) (wxFrame_create nil -1 \"\" -1 -1 -1 -1 %s))\n" % style) else: if code_obj.base == "wxDialog": write(indentation + "(setf (slot-top-window obj) (wxDialog_create nil -1 \"\" -1 -1 -1 -1 %s))\n" % style) import_packages = import_packages | set(['wxDialog']) # __init__ # write(indentation + '%s.__init__(obj, *args, **kwds)\n' % \ # mycn(code_obj.base)) init_lines = classes[code_obj.klass].init # --- patch 2002-08-26 --------------------------------------------------- parents_init = classes[code_obj.klass].parents_init parents_init.reverse() for l in parents_init: write(tab+l) # ------------------------------------------------------------------------ for l in init_lines: write(tab + l) # now check if there are extra lines to add to the init method if hasattr(builder, 'get_init_code'): for l in builder.get_init_code(code_obj): write(tab + l) # ALB 2004-12-05 now let's write the "event table"... event_handlers = classes[code_obj.klass].event_handlers if hasattr(builder, 'get_events'): for id, event, handler in builder.get_events(code_obj): event_handlers.append((id, mycn(event), handler)) if event_handlers: write('\n') if for_version < (2, 5) or not use_new_namespace: for win_id, event, handler in event_handlers: if win_id.startswith('#'): win_id = win_id[1:] + '.GetId()' write(tab + '%s(obj %s obj.%s)\n' % \ (event, win_id, handler)) else: for win_id, event, handler in event_handlers: if win_id.startswith('#'): write(tab + "(wxEvtHandler_Connect (slot-top-window obj) %s (exp%s)" "\n\t\t(wxClosure_Create #'%s obj))\n" % (win_id[1:],event, handler, )) else: write(tab + "(wxEvtHandler_Connect (slot-top-window obj) %s (exp%s)" "\n\t\t(wxClosure_Create #'%s obj))\n" % (win_id,event, handler, )) # end tag write(tab + ')\n') write(tab + ';;; end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __init__ wxGlade block with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__init__') if prev_src.content.find(tag) < 0: # no __init__ tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade __init__ block not found," \ " __init__ code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __set_properties ## props_builder = obj_properties.get(code_obj.base) ## write_body = len(classes[code_obj.klass].props) ## if props_builder: ## obj_p = obj_properties[code_obj.base](code_obj) ## if not write_body: write_body = len(obj_p) ## else: obj_p = [] obj_p = getattr(builder, 'get_properties_code', generate_common_properties)(code_obj) obj_p.extend(classes[code_obj.klass].props) write_body = len(obj_p) if is_new: write('\n(defmethod set-properties ((obj %s))\n' % klass) # begin tag write(tab + ';;;begin wxGlade: %s.__set_properties\n' % code_obj.klass) if not write_body: write(tab + 'pass\n') else: for l in obj_p: write(tab + l) # end tag write(tab + ')\n;;;end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __set_properties wxGlade block # with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__set_properties') if prev_src.content.find(tag) < 0: # no __set_properties tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade __set_properties block " \ "not found, __set_properties code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __do_layout if is_new: write('\n' + '(defmethod do-layout ((obj %s))\n' % klass) layout_lines = classes[code_obj.klass].layout sizers_init_lines = classes[code_obj.klass].sizers_init # check if there are extra layout lines to add if hasattr(builder, 'get_layout_code'): extra_layout_lines = builder.get_layout_code(code_obj) else: extra_layout_lines = [] # begin tag write(tab + ';;;begin wxGlade: %s.__do_layout\n' % code_obj.klass) if layout_lines or sizers_init_lines or extra_layout_lines: sizers_init_lines.reverse() for l in sizers_init_lines: write(tab + l) for l in layout_lines: write(tab + l) #write(tab + 'self.Layout()\n') for l in extra_layout_lines: write(tab + l) else: write(tab + 'pass\n') # end tag write(tab + ')\n;;;end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __do_layout wxGlade block # with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__do_layout') if prev_src.content.find(tag) < 0: # no __do_layout tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade __do_layout block " \ "not found, __do_layout code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) # ALB 2004-12-05 now let's generate the event handler stubs... if prev_src is not None and not is_new: already_there = prev_src.event_handlers.get(code_obj.klass, {}) buf = [] for name, event, handler in event_handlers: if handler not in already_there: buf.append('(defun %s (function data event) ' ';;;wxGlade: %s.\n' % (handler, code_obj.klass)) buf.append(tab + '(print "Event handler `%s\' not implemented")\n' % handler) buf.append(tab + '(when event\n') buf.append(tab + '(wxEvent:wxEvent_Skip event)))\n') already_there[handler] = 1 tag = '<%swxGlade event_handlers %s>' % (nonce, code_obj.klass) if prev_src.content.find(tag) < 0: # no event_handlers tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade event_handlers block " \ "not found, event_handlers code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buf)) del buf else: already_there = {} for name, event, handler in event_handlers: if handler not in already_there: write('\n' + '(defun %s (function data event) ' ';;;wxGlade: %s.\n' % (handler, code_obj.klass)) write(tab + '(print "Event handler `%s\' not implemented!")\n' % handler) write(tab + '(when event\n') write(tab + tab + '(wxEvent:wxEvent_Skip event)))\n') already_there[handler] = 1 # the code has been generated classes[code_obj.klass].done = True write('\n;;; end of class %s\n\n\n' % code_obj.klass) if not multiple_files and prev_src is not None: # if this is a new class, add its code to the new_classes list of the # SourceFileContent instance if is_new: prev_src.new_classes.append("".join(buffer)) return if multiple_files: if prev_src is not None: tag = '<%swxGlade insert new_classes>' % nonce prev_src.content = prev_src.content.replace(tag, "") #code) # insert the extra modules tag = '<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) prev_src.content = prev_src.content.replace(tag, code) # insert the module dependencies of this class extra_modules = classes[code_obj.klass].dependencies.keys() deps = ['# begin wxGlade: dependencies\n'] + extra_modules + \ ['# end wxGlade\n'] tag = '<%swxGlade replace dependencies>' % nonce prev_src.content = prev_src.content.replace(tag, "".join(deps)) try: # store the new file contents to disk common.save_file(filename, prev_src.content, 'codegen') except: raise IOError("py_codegen.add_class: %s, %s, %s" % \ (out_dir, prev_src.name, code_obj.klass)) return # create the new source file filename = os.path.join(out_dir, code_obj.klass + '.py') out = cStringIO.StringIO() write = out.write # write the common lines for line in header_lines: write(line) # write the module dependecies for this class write('\n;;;begin wxGlade: dependencies\n') for module in classes[code_obj.klass].dependencies: write(module) write(';;;end wxGlade\n') write('\n') # write the class body for line in buffer: write(line) try: # store the contents to filename common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_exc() out.close() else: # not multiple_files # write the class body onto the single source file for dep in classes[code_obj.klass].dependencies: _current_extra_modules[dep] = 1 write = output_file.write for line in buffer: write(line) _app_added = False def add_app(app_attrs, top_win_class): """\ Generates the code for a wxApp instance. If the file to write into already exists, this function does nothing. """ global _app_added _app_added = True name = app_attrs.get('name') if not name: name = 'app' if not multiple_files: prev_src = previous_source else: filename = os.path.join(out_dir, name + '.py') if not os.path.exists(filename): prev_src = None else: # prev_src doesn't need to be a SourceFileContent instance in this # case, as we do nothing if it is not None prev_src = 1 if prev_src is not None: return # do nothing if the file existed klass = app_attrs.get('class') top_win = app_attrs.get('top_window') if not top_win: return # do nothing if there is no top window lines = [] append = lines.append if klass: tab = tabs(2) # append('class %s(%s):\n' % (klass, cn('wxApp'))) append('(defun init-func (fun data evt)\n') else: tab = tabs(1) append('(defun init-func (fun data evt)\n') if _use_gettext: append(tab + 'import gettext\n') append(tab + 'gettext.install("%s") # replace with the appropriate' ' catalog name\n\n' % name) # append(tab + '%s = %s(0)\n' % (name, cn('wxPySimpleApp'))) top_win = top_win.replace('_','-') # top_win_class = top_win_class.replace('_','-') append(tab + '(let ((%s (make-%s)))\n' % (top_win, top_win_class)) if klass: append(tab + '(ELJApp_SetTopWindow (slot-top-window %s))\n' % top_win) append(tab + '(wxWindow_Show (slot-top-window %s))))\n' % top_win) # append(tab + 'return 1\n\n') append(';;; end of class %s\n\n' % klass) # append('if __name__ == "__main__":\n') tab = tabs(1) if _use_gettext: append(tab + 'import gettext\n') append(tab + 'gettext.install("%s") # replace with the appropriate' ' catalog name\n\n' % name) # append(tab + '%s = %s(0)\n' % (name, klass)) else: append(tab + '(ELJApp_SetTopWindow (slot-top-window %s))\n' % top_win) append(tab + '(wxWindow_Show (slot-top-window %s))))\n' % top_win) append("\n(unwind-protect\n\t(Eljapp_initializeC (wxclosure_Create #'init-func nil) 0 nil)") append("\n (ffi:close-foreign-library \"../miscellaneous/wxc-msw2.6.2.dll\"))\n") if multiple_files: filename = os.path.join(out_dir, name + '.py') out = cStringIO.StringIO() write = out.write write('#!/usr/bin/env lisp\n') # write the common lines for line in header_lines: write(line) # import the top window module write('from %s import %s\n\n' % (top_win_class, top_win_class)) # write the wxApp code for line in lines: write(line) try: common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_exc() # make the file executable try: os.chmod(filename, 0755) except OSError: pass # this is not a bad error out.close() else: write = output_file.write for line in lines: write(line) def _get_code_name(obj): if obj.is_toplevel: return '(slot-top-window obj)' else: if test_attribute(obj): return '(slot-%s obj)' % obj.name else: return obj.name def generate_code_size(obj): """\ returns the code fragment that sets the size of the given object. """ name = _get_code_name(obj) size = obj.properties.get('size', '').strip() use_dialog_units = (size[-1] == 'd') if for_version < (2, 5) or obj.parent is None: method = 'wxWindow_SetSize' else: method = 'SetMinSize' if use_dialog_units: return "("+ method + ' '+name +'(' + cn('wxDLG_SZE') + \ '(%s (%s)))\n' % (name, size[:-1]) else: return name + '.' + method + '((%s))\n' % size def _string_to_colour(s): return '%d %d %d' % (int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16)) def generate_code_foreground(obj): """\ returns the code fragment that sets the foreground colour of the given object. """ global import_packages self = _get_code_name(obj) try: color = cn('(wxColour_CreateRGB ') + '%s)' % \ _string_to_colour(obj.properties['foreground']) except (IndexError, ValueError): # the color is from system settings color = cn('(wxSystemSettings_GetColour ') + '%s)' % \ cn(obj.properties['foreground']) import_packages = import_packages | set(['wxColour']) return self + '(wxWindow_SetForegroundColour %s %s)\n' % (self,color) def generate_code_background(obj): """\ returns the code fragment that sets the background colour of the given object. """ global import_packages self = _get_code_name(obj) try: color = ('(wxColour_CreateRGB ') + '%s)' % \ _string_to_colour(obj.properties['background']) except (IndexError, ValueError): # the color is from system settings color = cn('(wxSystemSettings_GetColour ') + '%s)' % \ cn(obj.properties['background']) import_packages = import_packages | set(['wxColour']) print import_packages return '(wxWindow_SetBackgroundColour %s %s)\n' % (self,color) def generate_code_font(obj): """\ returns the code fragment that sets the font of the given object. """ global import_packages font = obj.properties['font'] size = font['size'] family = cn(font['family']) underlined = font['underlined'] style = cn(font['style']) weight = cn(font['weight']) face = '"%s"' % font['face'].replace('"', r'\"') self = _get_code_name(obj) import_packages = import_packages | set(['wxFont']) return ('(wxWindow_SetFont %s (wxFont_Create %s %s %s %s %s %s wxFONTENCODING_DEFAULT))\n' % (self, size, family, style, weight, underlined, face)) def generate_code_id(obj, id=None): """\ returns a 2-tuple of strings representing the LOC that sets the id of the given object: the first line is the declaration of the variable, and is empty if the object's id is a constant, and the second line is the value of the id """ if obj and obj.preview: return '', '-1' # never generate ids for preview code if id is None: id = obj.properties.get('id') if id is None: return '', '-1' tokens = id.split('=') if len(tokens) > 1: name, val = tokens[:2] else: return '', tokens[0] # we assume name is declared elsewhere if not name: return '', val if val.strip() == '?': val = cn('wxNewId()') # check to see if we have to make the var global or not... name = name.strip() val = val.strip() if '.' in name: return ('%s = %s\n' % (name, val), name) return ('global %s; %s = %s\n' % (name, name, val), name) def generate_code_tooltip(obj): """\ returns the code fragment that sets the tooltip of the given object. """ self = _get_code_name(obj) return '(wxWindow_SetToolTip ' + self + '%s)\n' % \ quote_str(obj.properties['tooltip']) def generate_code_disabled(obj): self = _get_code_name(obj) try: disabled = int(obj.properties['disabled']) except: disabled = False if disabled: return '(wxWindow_IsEnabled ' + self + '0)\n' def generate_code_focused(obj): self = _get_code_name(obj) try: focused = int(obj.properties['focused']) except: focused = False if focused: return '(wxWindow_SetFocus ' + self + ')\n' def generate_code_hidden(obj): self = _get_code_name(obj) try: hidden = int(obj.properties['hidden']) except: hidden = False if hidden: return '(wxWindow_Hide ' + self + ')\n' def generate_common_properties(widget): """\ generates the code for various properties common to all widgets (background and foreground colors, font, ...) Returns a list of strings containing the generated code """ prop = widget.properties out = [] if prop.get('size', '').strip(): out.append(generate_code_size(widget)) if prop.get('background'): out.append(generate_code_background(widget)) if prop.get('foreground'): out.append(generate_code_foreground(widget)) if prop.get('font'): out.append(generate_code_font(widget)) # tooltip if prop.get('tooltip'): out.append(generate_code_tooltip(widget)) # trivial boolean properties if prop.get('disabled'): out.append(generate_code_disabled(widget)) if prop.get('focused'): out.append(generate_code_focused(widget)) if prop.get('hidden'): out.append(generate_code_hidden(widget)) return out # custom property handlers class FontPropertyHandler: """Handler for font properties""" font_families = { 'default': 'wxDEFAULT', 'decorative': 'wxDECORATIVE', 'roman': 'wxROMAN', 'swiss': 'wxSWISS', 'script': 'wxSCRIPT', 'modern': 'wxMODERN', 'teletype': 'wxTELETYPE' } font_styles = { 'normal': 'wxNORMAL', 'slant': 'wxSLANT', 'italic': 'wxITALIC' } font_weights = { 'normal': 'wxNORMAL', 'light': 'wxLIGHT', 'bold': 'wxBOLD' } def __init__(self): self.dicts = { 'family': self.font_families, 'style': self.font_styles, 'weight': self.font_weights } self.attrs = { 'size': '0', 'style': '0', 'weight': '0', 'family': '0', 'underlined': '0', 'face': '' } self.current = None self.curr_data = [] def start_elem(self, name, attrs): self.curr_data = [] if name != 'font' and name in self.attrs: self.current = name else: self.current = None def end_elem(self, name, code_obj): if name == 'font': code_obj.properties['font'] = self.attrs return True elif self.current is not None: decode = self.dicts.get(self.current) if decode: val = decode.get("".join(self.curr_data), '0') else: val = "".join(self.curr_data) self.attrs[self.current] = val def char_data(self, data): self.curr_data.append(data) # end of class FontPropertyHandler class DummyPropertyHandler: """Empty handler for properties that do not need code""" def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): return True def char_data(self, data): pass # end of class DummyPropertyHandler class EventsPropertyHandler(object): def __init__(self): self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name, code_obj): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': code_obj.properties['events'] = self.handlers return True def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler # dictionary whose items are custom handlers for widget properties _global_property_writers = { 'font': FontPropertyHandler, 'events': EventsPropertyHandler, } # dictionary of dictionaries of property handlers specific for a widget # the keys are the class names of the widgets # Ex: _property_writers['wxRadioBox'] = {'choices', choices_handler} _property_writers = {} # map of widget class names to a list of extra modules needed for the # widget. Example: 'wxGrid': 'from wxLisp.grid import *\n' _widget_extra_modules = {} # set of lines of extra modules to add to the current file _current_extra_modules = {} def get_property_handler(property_name, widget_name): try: cls = _property_writers[widget_name][property_name] except KeyError: cls = _global_property_writers.get(property_name, None) if cls: return cls() return None def add_property_handler(property_name, handler, widget_name=None): """\ sets a function to parse a portion of XML to get the value of the property property_name. If widget_name is not None, the function is called only if the property in inside a widget whose class is widget_name """ if widget_name is None: _global_property_writers[property_name] = handler else: try: _property_writers[widget_name][property_name] = handler except KeyError: _property_writers[widget_name] = { property_name: handler } class WidgetHandler: """\ Interface the various code generators for the widgets must implement """ """list of modules to import (eg. ['from wxLisp.grid import *\n'])""" import_modules = [] def get_code(self, obj): """\ Handler for normal widgets (non-toplevel): returns 3 lists of strings, init, properties and layout, that contain the code for the corresponding methods of the class to generate """ return [], [], [] def get_properties_code(self, obj): """\ Handler for the code of the set_properties method of toplevel objects. Returns a list of strings containing the code to generate """ return [] def get_init_code(self, obj): """\ Handler for the code of the constructor of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add). The generated lines are appended at the end of the constructor """ return [] def get_layout_code(self, obj): """\ Handler for the code of the do_layout method of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add) """ return [] # end of class WidgetHandler def add_widget_handler(widget_name, handler): obj_builders[widget_name] = handler def setup(): """\ Code generator setup function. This is called once, when the code generator is loaded in wxglade. """ # scan widgets.txt for widgets, load lisp_codegen's _widgets_dir = os.path.join(common.wxglade_path, 'widgets') widgets_file = os.path.join(_widgets_dir, 'widgets.txt') if not os.path.isfile(widgets_file): print >> sys.stderr, "widgets file (%s) doesn't exist" % widgets_file return import sys sys.path.append(_widgets_dir) modules = open(widgets_file) for line in modules: module_name = line.strip() if not module_name or module_name.startswith('#'): continue module_name = module_name.split('#')[0].strip() try: m = __import__(module_name + '.lisp_codegen', {}, {}, ['initialize']) m.initialize() except (ImportError, AttributeError): pass ## print 'ERROR loading "%s"' % module_name ## import traceback; ## traceback.print_exc() ## else: ## print 'initialized lisp generator for ', module_name modules.close() # ...then, the sizers import edit_sizers.lisp_sizers_codegen edit_sizers.lisp_sizers_codegen.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/codegen/pl_codegen.py0000644000175000017500000014350410743421035021643 0ustar stanistani# pl_codegen.py: perl code generator # $Id: pl_codegen.py,v 1.41 2007/08/07 12:26:20 agriggio Exp $ # # Copyright (c) 2002-2004 D.H. aka crazyinsomniac on sourceforge.net # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # # like all other perl parts, based on the pre-existing python generators # """\ How the code is generated: every time the end of an object is reached during the parsing of the xml tree, either the function 'add_object' or the function 'add_class' is called: the latter when the object is a toplevel one, the former when it is not. In the last case, 'add_object' calls the appropriate ``writer'' function for the specific object, found in the 'obj_builders' dict. Such function accepts one argument, the CodeObject representing the object for which the code has to be written, and returns 3 lists of strings, representing the lines to add to the '__init__', '__set_properties' and '__do_layout' methods of the parent object. """ import sys, os, os.path import common, config import cStringIO from xml_parse import XmlParsingError # these two globals must be defined for every code generator module language = 'perl' writer = sys.modules[__name__] # the writer is the module itself # default extensions for generated files: a list of file extensions default_extensions = ['pl','pm'] """\ dictionary that maps the lines of code of a class to the name of such class: the lines are divided in 3 categories: '__init__', '__set_properties' and '__do_layout' """ classes = None """dictionary of ``writers'' for the various objects""" obj_builders = {} """\ dictionary of ``property writer'' functions, used to set the properties of a toplevel object """ obj_properties = {} # random number used to be sure that the replaced tags in the sources are # the right ones (see SourceFileContent and add_class) nonce = None # lines common to all the generated files (use Wx [:everything], ...) header_lines = [] # if True, generate a file for each custom class multiple_files = False # if not None, it is the single source file to write into output_file = None # if not None, it is the directory inside which the output files are saved out_dir = None def cn(class_name): if class_name[:2] == 'wx': return 'Wx::' + class_name[2:] elif class_name[:4] == 'EVT_': return 'Wx::' + class_name else: return class_name class ClassLines: """\ Stores the lines of perl code for a custom class """ def __init__(self): self.init = [] # lines of code to insert in the __init__ method # (for children widgets) self.parents_init = [] # lines of code to insert in the __init__ for # container widgets (panels, splitters, ...) self.sizers_init = [] # lines related to sizer objects declarations self.props = [] # lines to insert in the __set_properties method self.layout = [] # lines to insert in the __do_layout method self.dependencies = {} # names of the modules this class depends on self.done = False # if True, the code for this class has already # been generated self.event_handlers = [] # lines to bind events # end of class ClassLines class SourceFileContent: """\ Keeps info about an existing file that has to be updated, to replace only the lines inside a wxGlade block, an to keep the rest of the file as it was WARNING: NOT YET COMPLETE (always overwrites destination file, ALWAYS) -- crazyinsomniac alb - the warning above shouldn't be true anymore... but we need testing... """ def __init__(self, name=None, content=None, classes=None): self.name = name # name of the file self.content = content # content of the source file, if it existed # before this session of code generation self.classes = classes # classes declared in the file self.new_classes = [] # new classes to add to the file (they are # inserted BEFORE the old ones) if classes is None: self.classes = {} self.spaces = {} # indentation level for each class self.event_handlers = {} # list of event handlers for each class if self.content is None: self.build_untouched_content() def build_untouched_content(self): """\ Builds a string with the contents of the file that must be left as is, and replaces the wxGlade blocks with tags that in turn will be replaced by the new wxGlade blocks WARNING: NOT YET COMPLETE -- crazyinsomniac alb - almost done :) WARNING: There is *NO* support for here documents: if you put wxGlade blocks inside a here document, you're likely going into troubles... """ import re class_name = None new_classes_inserted = False # regexp to match class declarations # package Foo; or package Foo::bar::baz ; #class_decl = re.compile(r'^\s*package\s+[a-zA-Z]\w*(::\w+)*\s*;\s*$') # less precise regex, but working :-P class_decl = re.compile(r'^\s*package\s+([a-zA-Z_][\w:]*)\s*;.*$') # regexps to match wxGlade blocks block_start = re.compile(r'^(\s*)#\s*begin\s+wxGlade:\s*' '([a-zA-Z_][\w:]*?)::(\w+)\s*$') block_end = re.compile(r'^\s*#\s*end\s+wxGlade\s*$') pod_re = re.compile(r'^\s*=[A-Za-z_]+\w*.*$') event_handler = re.compile( r'#\s*wxGlade:\s*([\w:]+)::(\w+) \s*$') inside_block = False inside_pod = False tmp_in = open(self.name) out_lines = [] for line in tmp_in: result = pod_re.match(line) if result is not None: inside_pod = True if inside_pod: out_lines.append(line) if line.startswith('=cut'): inside_pod = False continue result = class_decl.match(line) if result is not None: #print ">> found class %s" % result.group(1) if class_name is None: # this is the first class declared in the file: insert the # new ones before this out_lines.append('#<%swxGlade insert new_classes>' % nonce) new_classes_inserted = True class_name = result.group(1) self.classes[class_name] = 1 # add the found class to the list # of classes of this module out_lines.append(line) elif not inside_block: result = block_start.match(line) if result is not None: # replace the lines inside a wxGlade block with a tag that # will be used later by add_class spaces = result.group(1) which_class = result.group(2) which_block = result.group(3) if which_class is None: which_class = class_name self.spaces[which_class] = spaces inside_block = True if class_name is None: out_lines.append('#<%swxGlade replace %s>' % \ (nonce, which_block)) else: out_lines.append('#<%swxGlade replace %s %s>' % \ (nonce, which_class, which_block)) else: #- ALB 2004-12-05 ---------- result = event_handler.match(line) if result is not None: which_handler = result.group(2) which_class = result.group(1) self.event_handlers.setdefault( which_class, {})[which_handler] = 1 if class_name is not None and self.is_end_of_class(line): # add extra event handlers here... out_lines.append('#<%swxGlade event_handlers %s>' % (nonce, class_name)) #--------------------------- out_lines.append(line) if line.lstrip().startswith('use Wx'): # add a tag to allow extra modules out_lines.append('#<%swxGlade extra_modules>\n' % nonce) else: # ignore all the lines inside a wxGlade block if block_end.match(line) is not None: inside_block = False if not new_classes_inserted: # if we are here, the previous ``version'' of the file did not # contain any class, so we must add the new_classes tag at the # end of the file out_lines.append('#<%swxGlade insert new_classes>' % nonce) tmp_in.close() # set the ``persistent'' content of the file self.content = "".join(out_lines) def is_end_of_class(self, line): return line.strip().startswith('# end of class ') # end of class SourceFileContent # if not None, it is an instance of SourceFileContent that keeps info about # the previous version of the source to generate previous_source = None # if True, overwrite any previous version of the source file instead of # updating only the wxGlade blocks _overwrite = False # if True, enable gettext support _use_gettext = False import re _quote_str_re = re.compile( r'\\(?![nrt])' ) def quote_str(s): """\ returns a quoted version of 's', suitable to insert in a perl source file as a string object. Takes care also of gettext support """ if not s: return '""' s = _quote_str_re.sub(r'\\\\', s ) s = s.replace('"', r'\"') s = s.replace('$', r'\$') s = s.replace('@', r'\@') if _use_gettext: return '_T("' + s + '")' else: return '"' + s + '"' def quote_path(s): """\ escapes all " and \ , thus making a path suitable to insert in a perl source file """ # " alb: comment needed to avoid emacs going insane with colorization.. s = s.replace('\\', '\\\\') s = s.replace('"', r'\"') s = s.replace('$', r'\$') # sigh s = s.replace('@', r'\@') return '"' + s + '"' def initialize(app_attrs): """\ Writer initialization function. - app_attrs: dict of attributes of the application. The following two are always present: path: output path for the generated code (a file if multi_files is False, a dir otherwise) option: if True, generate a separate file for each custom class """ out_path = app_attrs['path'] multi_files = app_attrs['option'] global classes, header_lines, multiple_files, previous_source, nonce, \ _current_extra_modules, _use_gettext, _overwrite import time, random ## # scan widgets.txt for widgets, load perl_codegen's ## _widgets_dir = os.path.join(common.wxglade_path, 'widgets') ## widgets_file = os.path.join(_widgets_dir, 'widgets.txt') ## if not os.path.isfile(widgets_file): ## print >> sys.stderr, "widgets file (%s) doesn't exist" % widgets_file ## return ## import sys ## sys.path.append(_widgets_dir) ## modules = open(widgets_file) ## for line in modules: ## module_name = line.strip() ## if not module_name or module_name.startswith('#'): continue ## module_name = module_name.split('#')[0].strip() ## try: ## m = __import__( ## module_name + '.perl_codegen', {}, {}, ['initialize']) ## m.initialize() ## except (ImportError, AttributeError): ## print 'ERROR loading "%s"' % module_name ## import traceback; ## traceback.print_exc() ## ## else: ## ## print 'initialized perl generator for ', module_name ## modules.close() ## # ...then, the sizers ## import edit_sizers.perl_sizers_codegen ## edit_sizers.perl_sizers_codegen.initialize() try: _use_gettext = int(app_attrs['use_gettext']) except (KeyError, ValueError): _use_gettext = False try: _overwrite = int(app_attrs['overwrite']) except (KeyError, ValueError): _overwrite = False # this is to be more sure to replace the right tags nonce = '%s%s' % (str(time.time()).replace('.', ''), random.randrange(10**6, 10**7)) # ALB 2004-12-05 global for_version try: for_version = tuple([int(t) for t in app_attrs['for_version'].split('.')[:2]]) except (KeyError, ValueError): if common.app_tree is not None: for_version = common.app_tree.app.for_version else: for_version = (2, 4) # default... classes = {} _current_extra_modules = {} header_lines = [ '# generated by wxGlade %s on %s%s\n' % \ (common.version, time.asctime(), common.generated_from()), '# To get wxPerl visit http://wxPerl.sourceforge.net/\n\n', 'use Wx 0.15 qw[:allclasses];\nuse strict;\n' ] if not config.preferences.write_timestamp: header_lines[0] = '# generated by wxGlade %s%s\n' % \ (common.version, common.generated_from()) multiple_files = multi_files if not multiple_files: global output_file, output_file_name if not _overwrite and os.path.isfile(out_path): # the file exists, we must keep all the lines not inside a wxGlade # block. NOTE: this may cause troubles if out_path is not a valid # perl file, so be careful! previous_source = SourceFileContent(out_path) else: # if the file doesn't exist, create it and write the ``intro'' previous_source = None output_file = cStringIO.StringIO() output_file_name = out_path output_file.write('#!/usr/bin/perl -w -- \n') for line in header_lines: output_file.write(line) output_file.write('#<%swxGlade extra_modules>\n' % nonce) output_file.write('\n') else: previous_source = None global out_dir if not os.path.isdir(out_path): raise XmlParsingError("'path' must be a directory when generating"\ " multiple output files") out_dir = out_path def finalize(): """\ Writer ``finalization'' function: flushes buffers, closes open files, ... """ if previous_source is not None: # insert all the new custom classes inside the old file tag = '#<%swxGlade insert new_classes>' % nonce if previous_source.new_classes: code = "".join(previous_source.new_classes) else: code = "" previous_source.content = previous_source.content.replace(tag, code) tag = '#<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) previous_source.content = previous_source.content.replace(tag, code) # now remove all the remaining <123415wxGlade ...> tags from the # source: this may happen if we're not generating multiple files, # and one of the container class names is changed import re tags = re.findall('(#<%swxGlade replace ([a-zA-Z_]\w*) +\w+>)' % nonce, previous_source.content) for tag in tags: indent = previous_source.spaces.get(tag[1], '\t') comment = '%s# content of this block not found: ' \ 'did you rename this class?\n' % indent previous_source.content = previous_source.content.replace(tag[0], comment) tags = re.findall('#<%swxGlade event_handlers \w+>' % nonce, previous_source.content) for tag in tags: previous_source.content = previous_source.content.replace(tag, "") # write the new file contents to disk common.save_file(previous_source.name, previous_source.content, 'codegen') elif not multiple_files: global output_file em = "".join(_current_extra_modules.keys()) content = output_file.getvalue().replace( '#<%swxGlade extra_modules>\n' % nonce, em) output_file.close() try: common.save_file(output_file_name, content, 'codegen') # make the file executable if _app_added: os.chmod(output_file_name, 0755) except IOError, e: raise XmlParsingError(str(e)) except OSError: pass # this isn't necessary a bad error del output_file def test_attribute(obj): """\ Returns True if 'obj' should be added as an attribute of its parent's class, False if it should be created as a local variable of __do_layout. To do so, tests for the presence of the special property 'attribute' """ try: return int(obj.properties['attribute']) except (KeyError, ValueError): return True # this is the default def add_object(top_obj, sub_obj): """\ adds the code to build 'sub_obj' to the class body of 'top_obj'. """ try: klass = classes[top_obj.klass] except KeyError: klass = classes[top_obj.klass] = ClassLines() try: builder = obj_builders[sub_obj.base] except KeyError: # no code generator found: write a comment about it klass.init.extend(['\n', '# code for %s (type %s) not generated: ' 'no suitable writer found' % (sub_obj.name, sub_obj.klass),'\n']) else: try: init, props, layout = builder.get_code(sub_obj) except: print sub_obj raise # this shouldn't happen if sub_obj.in_windows: # the object is a wxWindow instance # --- patch 2002-08-26 ------------------------------------------ if sub_obj.is_container and not sub_obj.is_toplevel: init.reverse() klass.parents_init.extend(init) else: klass.init.extend(init) # --------------------------------------------------------------- mycn = getattr(builder, 'cn', cn) if hasattr(builder, 'get_events'): evts = builder.get_events(sub_obj) for id, event, handler in evts: klass.event_handlers.append((id, event, handler)) elif 'events' in sub_obj.properties: id_name, id = generate_code_id(sub_obj) #if id == '-1': id = 'self.%s.GetId()' % sub_obj.name if id == '-1': id = '#$self->%s' % sub_obj.name for event, handler in sub_obj.properties['events'].iteritems(): klass.event_handlers.append((id, event, handler)) else: # the object is a sizer if sub_obj.base == 'wxStaticBoxSizer': klass.parents_init.insert(1, init.pop(0)) # ${staticboxsizername}_staticbox klass.sizers_init.extend(init) klass.props.extend(props) klass.layout.extend(layout) if multiple_files and \ (sub_obj.is_toplevel and sub_obj.base != sub_obj.klass): key = 'use %s;\n' % sub_obj.klass klass.dependencies[key] = 1 ## for dep in _widget_extra_modules.get(sub_obj.base, []): for dep in getattr(obj_builders.get(sub_obj.base), 'import_modules', []): klass.dependencies[dep] = 1 def add_sizeritem(toplevel, sizer, obj, option, flag, border): """\ writes the code to add the object 'obj' to the sizer 'sizer' in the 'toplevel' object. """ # an ugly hack to allow the addition of spacers: if obj_name can be parsed # as a couple of integers, it is the size of the spacer to add obj_name = obj.name try: w, h = [ int(s) for s in obj_name.split(',') ] except ValueError: if obj.in_windows: # attribute is a special property, which tells us if the object # is a local variable or an attribute of its paren if test_attribute(obj): obj_name = '$self->{%s}' % obj_name if obj.base == 'wxNotebook' and for_version < (2, 6): # deprecated since wxWidgets 2.5.3 obj_name = 'Wx::NotebookSizer->new(%s)' % obj_name elif obj_name[0:1] != '$': obj_name = '$self->{%s}' % obj_name try: klass = classes[toplevel.klass] except KeyError: klass = classes[toplevel.klass] = ClassLines() buffer = '$self->{%s}->Add(%s, %s, %s, %s);\n' % \ (sizer.name, obj_name, option, flag, border) klass.layout.append(buffer) new_defaults = { '$parent' : '\t$parent = undef unless defined $parent;\n' , '$id' : '\t$id = -1 unless defined $id;\n' , '$title' : '\t$title = "" unless defined $title;\n' , '$pos' : '\t$pos = wxDefaultPosition unless defined $pos;\n' , '$size' : '\t$size = wxDefaultSize unless defined $size;\n' , '$name' : '\t$name = "" unless defined $name;\n\n', # '$style' is a special case } def add_class(code_obj): """\ Generates the code for a custom class. """ global _current_extra_modules if not multiple_files: # in this case, previous_source is the SourceFileContent instance # that keeps info about the single file to generate prev_src = previous_source else: # let's see if the file to generate exists, and in this case # create a SourceFileContent instance filename = os.path.join(out_dir, code_obj.klass + '.pm') # MODULE!! if not os.path.exists(filename): prev_src = None else: prev_src = SourceFileContent(filename) _current_extra_modules = {} if classes.has_key(code_obj.klass) and classes[code_obj.klass].done: return # the code has already been generated try: builder = obj_builders[code_obj.base] except KeyError: print code_obj raise # this is an error, let the exception be raised if prev_src is not None and prev_src.classes.has_key(code_obj.klass): is_new = False else: # this class wasn't in the previous version of the source (if any) is_new = True mods = getattr(builder, 'extra_modules', []) if mods: for m in mods: _current_extra_modules[m] = 1 buffer = [] write = buffer.append if not classes.has_key(code_obj.klass): # if the class body was empty, create an empty ClassLines classes[code_obj.klass] = ClassLines() new_signature = getattr(builder, 'new_signature', [] ) if _use_gettext and not is_new: classes[code_obj.klass].dependencies[ "use Wx::Locale gettext => '_T';\n"]=1 if is_new: write('package %s;\n\n' % code_obj.klass ) write('use Wx qw[:everything];\nuse base qw(%s);\nuse strict;\n\n' % code_obj.base.replace('wx','Wx::',1) ) if _use_gettext: if multiple_files: classes[code_obj.klass].dependencies[ "use Wx::Locale gettext => '_T';\n"]=1 else: write("use Wx::Locale gettext => '_T';\n") if multiple_files: # write the module dependecies for this class (package) write('# begin wxGlade: ::dependencies\n') for module in classes[code_obj.klass].dependencies: write(module) write('# end wxGlade\n') write('\n') write('sub new {\n') write("\tmy( $self, %s ) = @_;\n" % ", ".join( new_signature ) ) if new_signature: for k in new_signature : if new_defaults.has_key(k) : write( new_defaults[k] ) else: new_signature = [ '@_[1 .. $#_]' ] # shift(@_)->SUPER::new(@_); print code_obj.klass + " did not declare new_defaults " # constructor (new) begin tag write('# begin wxGlade: %s::new\n\n' % code_obj.klass) prop = code_obj.properties style = prop.get("style", None) if style: write('\t$style = %s \n\t\tunless defined $style;\n\n' % style) # constructor (new) write('\t$self = $self->SUPER::new( %s );\n' % ", ".join( new_signature )) init_lines = classes[code_obj.klass].init parents_init = classes[code_obj.klass].parents_init parents_init.reverse() for l in parents_init: write('\t' +l) for l in init_lines: write('\t' +l) # now check if there are extra lines to add to the init method if hasattr(builder, 'get_init_code'): for l in builder.get_init_code(code_obj): write('\t' + l) write('\n\t$self->__set_properties();\n') write('\t$self->__do_layout();\n\n') event_handlers = classes[code_obj.klass].event_handlers if hasattr(builder, 'get_events'): for id, event, handler in builder.get_events(code_obj): event_handlers.append((id, event, handler)) for win_id, event, handler in event_handlers: if win_id.startswith('#'): win_id = '$self->{' + win_id[8:] + '}->GetId' write('\tWx::Event::%s($self, %s, \\&%s);\n' % \ (event, win_id, handler)) if event_handlers: write('\n') write('# end wxGlade\n') if is_new: write('\treturn $self;\n\n') write('}\n\n') if prev_src is not None and not is_new: # replace the lines inside the ::new wxGlade block with the new ones tag = '#<%swxGlade replace %s %s>' % (nonce, code_obj.klass, 'new') if prev_src.content.find(tag) < 0: # no __init__ tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade ::new block not found," \ " constructor code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __set_properties obj_p = getattr(builder, 'get_properties_code', generate_common_properties)(code_obj) obj_p.extend(classes[code_obj.klass].props) write_body = len(obj_p) if is_new: write('\nsub __set_properties {\n\tmy $self = shift;\n\n') write('# begin wxGlade: %s::__set_properties\n\n' % code_obj.klass) if not write_body: write('\treturn;\n') else: for l in obj_p: write('\t' +l) write('\n# end wxGlade\n') if is_new: write('}\n') if prev_src is not None and not is_new: # replace the lines inside the __set_properties wxGlade block # with the new ones tag = '#<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__set_properties') if prev_src.content.find(tag) < 0: # no __set_properties tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade __set_properties block " \ "not found, __set_properties code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __do_layout if is_new: write('\nsub __do_layout {\n\tmy $self = shift;\n\n') layout_lines = classes[code_obj.klass].layout sizers_init_lines = classes[code_obj.klass].sizers_init # check if there are extra layout lines to add if hasattr(builder, 'get_layout_code'): extra_layout_lines = builder.get_layout_code(code_obj) else: extra_layout_lines = [] write('# begin wxGlade: %s::__do_layout\n\n' % code_obj.klass) if layout_lines or sizers_init_lines or extra_layout_lines: sizers_init_lines.reverse() for l in sizers_init_lines : write('\t' +l) for l in layout_lines : write('\t' +l) for l in extra_layout_lines : write('\t' +l) else: write('\treturn;\n') write('\n# end wxGlade\n') if is_new: write('}\n') if prev_src is not None and not is_new: # replace the lines inside the __do_layout wxGlade block # with the new ones tag = '#<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__do_layout') if prev_src.content.find(tag) < 0: # no __do_layout tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade __do_layout block " \ "not found, __do_layout code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) if prev_src is not None and not is_new: already_there = prev_src.event_handlers.get(code_obj.klass, {}) buf = [] for name, event, handler in event_handlers: if handler not in already_there: buf.append('\nsub %s {\n' '\tmy ($self, $event) = @_;\n' '# wxGlade: %s::%s \n\n' '\twarn "Event handler (%s) not implemented";\n' '\t$event->Skip;\n\n# end wxGlade\n}\n\n' % (handler, code_obj.klass,handler, handler)) already_there[handler] = 1 tag = '#<%swxGlade event_handlers %s>' % (nonce, code_obj.klass) if prev_src.content.find(tag) < 0: # no event_handlers tag found, issue a warning and do nothing print >> sys.stderr, "WARNING: wxGlade event_handlers block " \ "not found, event_handlers code NOT generated" else: prev_src.content = prev_src.content.replace(tag, "".join(buf)) del buf else: already_there = {} for name, event, handler in event_handlers: if handler not in already_there: write('\nsub %s {\n' '\tmy ($self, $event) = @_;\n' '# wxGlade: %s::%s \n\n' '\twarn "Event handler (%s) not implemented";\n' '\t$event->Skip;\n\n# end wxGlade\n}\n\n' % (handler, code_obj.klass,handler, handler)) already_there[handler] = 1 # the code has been generated classes[code_obj.klass].done = True write('\n# end of class %s\n\n1;\n\n' % code_obj.klass) if not multiple_files and prev_src is not None: # if this is a new class, add its code to the new_classes list of the # SourceFileContent instance if is_new: prev_src.new_classes.append("".join(buffer)) return if multiple_files: #return # not implemented yet -- crazyinsomniac if prev_src is not None: tag = '#<%swxGlade insert new_classes>' % nonce prev_src.content = prev_src.content.replace(tag, "") # insert the extra modules tag = '#<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) prev_src.content = prev_src.content.replace(tag, code) # insert the module dependencies of this class extra_modules = classes[code_obj.klass].dependencies.keys() deps = ['# begin wxGlade: ::dependencies\n'] + extra_modules + \ ['# end wxGlade\n'] tag = '#<%swxGlade replace %s dependencies>' % \ (nonce, code_obj.klass) prev_src.content = prev_src.content.replace(tag, "".join(deps)) try: # store the new file contents to disk common.save_file(filename, prev_src.content, 'codegen') except: raise IOError("pl_codegen.add_class: %s, %s, %s" % \ (out_dir, prev_src.name, code_obj.klass)) return # create the new source file filename = code_obj.klass.replace('::', os.sep ) + '.pm' # MODULE!! filename = os.path.join(out_dir, filename ) out = cStringIO.StringIO() write = out.write # write the common lines for line in header_lines: write(line) # write the class body for line in buffer: write(line) try: dirname = os.path.dirname(filename) # create Foo in Foo::Bar, # Foo/Bar.pm if not os.path.exists(dirname): os.makedirs(dirname) # store the contents to filename common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_exc() out.close() else: # not multiple_files # write the class body onto the single source file for dep in classes[code_obj.klass].dependencies: _current_extra_modules[dep] = 1 write = output_file.write for line in buffer: write(line) _app_added = False def add_app(app_attrs, top_win_class): """\ Generates the code for a wxApp instance. If the file to write into already exists, this function does nothing. """ global _app_added _app_added = True name = app_attrs.get('name') if not name: name = 'app' if not multiple_files: prev_src = previous_source else: filename = os.path.join(out_dir, name + '.pl') if not os.path.exists(filename): prev_src = None elif _overwrite: prev_src = None else: # prev_src doesn't need to be a SourceFileContent instance in this # case, as we do nothing if it is not None prev_src = 1 if prev_src is not None: return # do nothing if the file existed klass = app_attrs.get('class') top_win = app_attrs.get('top_window') if not top_win: return # do nothing if there is no top window lines = [] append = lines.append if klass: append('package %s;\n' % klass) append('\nuse base qw(Wx::App);\nuse strict;\n\n') if multiple_files: # import the top window module append('use %s;\n\n' % top_win_class) append('sub OnInit {\n\tmy( $self ) = shift;\n\n') else: append('1;\n\npackage main;\n') if multiple_files: # import the top window module append('\nuse %s;\n\n' % top_win_class ) append('\nunless(caller){\n') if _use_gettext: append('\tmy $local = Wx::Locale->new("English", "en", "en");' + ' # replace with ??\n') append('\t$local->AddCatalog("%s");' % name + ' # replace with the appropriate catalog name\n\n' ) # and now, basically fake wxPySimpleApp append('\tlocal *Wx::App::OnInit = sub{1};\n') append('\tmy $%s = Wx::App->new();\n'% name) append('\tWx::InitAllImageHandlers();\n\n') # we add this to avoid troubles append('\tmy $%s = %s->new();\n\n' % (top_win, top_win_class)) if klass: append('\t$self->SetTopWindow($%s);\n' % top_win) append('\t$%s->Show(1);\n\n' % top_win) append('\treturn 1;\n}\n') append('# end of class %s\n\n' % klass) append('package main;\n\nunless(caller){\n') if _use_gettext: append('\tmy $local = Wx::Locale->new("English", "en", "en");' + ' # replace with ??\n') append('\t$local->AddCatalog("%s");' % name + ' # replace with the appropriate catalog name\n\n') append('\tmy $%s = %s->new();\n' % (name, klass)) else: append('\t$%s->SetTopWindow($%s);\n' % (name, top_win)) append('\t$%s->Show(1);\n' % top_win) append('\t$%s->MainLoop();\n}\n' % name) if multiple_files: # not read yet filename = os.path.join(out_dir, name + '.pl') out = cStringIO.StringIO() write = out.write write('#!/usr/bin/perl -w -- \n') # write the common lines for line in header_lines: write(line) # write the wxApp code for line in lines: write(line) try: common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_wexc() # make the file executable try: os.chmod(filename, 0755) except OSError: pass # this is not a bad error out.close() else: write = output_file.write for line in lines: write(line) def _get_code_name(obj): """\ returns the name of the variable ( either $self, $foo, or $self->{foo} ) """ if obj.is_toplevel: return '$self' else: if test_attribute(obj): return '$self->{%s}' % obj.name else: # it's an already declared lexical (my $foo) if obj.name[0] == '$': return obj.name else: return '$' + obj.name def generate_code_size(obj): """\ returns the code fragment that sets the size of the given object. """ name = _get_code_name(obj) size = obj.properties.get('size', '').strip() use_dialog_units = (size[-1] == 'd') if for_version < (2, 5) or obj.parent is None: method = 'SetSize' else: method = 'SetMinSize' if use_dialog_units: return name + '->' + method + \ '(%s->ConvertDialogSizeToPixels(Wx::Size->new(%s)));\n' % \ (name, size[:-1]) return name + '->' + method + '(Wx::Size->new(%s));\n' % size def _string_to_colour(s): return '%d, %d, %d' % (int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16)) def generate_code_foreground(obj): """\ returns the code fragment that sets the foreground colour of the given object. """ self = _get_code_name(obj) try: color = 'Wx::Colour->new(%s)' % \ _string_to_colour(obj.properties['foreground']) except (IndexError, ValueError): # the color is from system settings color = 'Wx::SystemSettings::GetColour(%s)' % \ obj.properties['foreground'] return self + '->SetForegroundColour(%s);\n' % color def generate_code_background(obj): """\ returns the code fragment that sets the background colour of the given object. """ self = _get_code_name(obj) try: color = 'Wx::Colour->new(%s)' % \ _string_to_colour(obj.properties['background']) except (IndexError, ValueError): # the color is from system settings color = 'Wx::SystemSettings::GetColour(%s)' % \ obj.properties['background'] return self + '->SetBackgroundColour(%s);\n' % color def generate_code_font(obj): """\ returns the code fragment that sets the font of the given object. """ font = obj.properties['font'] size = font['size']; family = font['family'] underlined = font['underlined'] style = font['style']; weight = font['weight'] face = '"%s"' % font['face'].replace('"', r'\"') self = _get_code_name(obj) return self + \ '->SetFont(Wx::Font->new(%s, %s, %s, %s, %s, %s));\n' % \ (size, family, style, weight, underlined, face) def generate_code_id(obj, id=None): """\ returns a 2-tuple of strings representing the LOC that sets the id of the given object: the first line is the declaration of the variable, and is empty if the object's id is a constant, and the second line is the value of the id """ if obj and id is None: id = obj.properties.get('id') if id is None: return '', '-1' tokens = id.split('=') if len(tokens) > 1: name, val = tokens[:2] else: return '', tokens[0] # we assume name is declared elsewhere if not name: return '', val if val.strip() == '?': val = 'Wx::NewId()' return ('use constant %s => %s;\n' % (name, val), name) def generate_code_tooltip(obj): """\ returns the code fragment that sets the tooltip of the given object. """ self = _get_code_name(obj) return self + \ '->SetToolTipString(%s);\n' % quote_str(obj.properties['tooltip']) def generate_code_disabled(obj): self = _get_code_name(obj) try: disabled = int(obj.properties['disabled']) except: disabled = False if disabled: return self + '->Enable(0);\n' # Disable() is not available def generate_code_focused(obj): self = _get_code_name(obj) try: focused = int(obj.properties['focused']) except: focused = False if focused: return self + '->SetFocus();\n' def generate_code_hidden(obj): self = _get_code_name(obj) try: hidden = int(obj.properties['hidden']) except: hidden = False if hidden: return self + '->Show(0);\n' # Hide() is not available def generate_code_extraproperties(obj): self = _get_code_name(obj) prop = obj.properties['extraproperties'] ret = [] for name in sorted(prop): ret.append(self + '->Set%s(%s);\n' % (name, prop[name])) return ret def generate_common_properties(widget): """\ generates the code for various properties common to all widgets (background and foreground colors, font, ...) Returns a list of strings containing the generated code """ prop = widget.properties out = [] if prop.get('size', '').strip(): out.append(generate_code_size(widget)) if prop.get('background'): out.append(generate_code_background(widget)) if prop.get('foreground'): out.append(generate_code_foreground(widget)) if prop.get('font'): out.append(generate_code_font(widget)) # tooltip if prop.get('tooltip'): out.append(generate_code_tooltip(widget)) # trivial boolean properties if prop.get('disabled'): out.append(generate_code_disabled(widget)) if prop.get('focused'): out.append(generate_code_focused(widget)) if prop.get('hidden'): out.append(generate_code_hidden(widget)) # ALB 2007-09-01 extra properties if prop.get('extraproperties') and not widget.preview: out.extend(generate_code_extraproperties(widget)) return out # custom property handlers class FontPropertyHandler: """Handler for font properties""" font_families = { 'default': 'wxDEFAULT', 'decorative': 'wxDECORATIVE', 'roman': 'wxROMAN', 'swiss': 'wxSWISS', 'script': 'wxSCRIPT', 'modern': 'wxMODERN', 'teletype': 'wxTELETYPE' } font_styles = { 'normal': 'wxNORMAL', 'slant': 'wxSLANT', 'italic': 'wxITALIC' } font_weights = { 'normal': 'wxNORMAL', 'light': 'wxLIGHT', 'bold': 'wxBOLD' } def __init__(self): self.dicts = { 'family': self.font_families, 'style': self.font_styles, 'weight': self.font_weights } self.attrs = { 'size': '0', 'style': '0', 'weight': '0', 'family': '0', 'underlined': '0', 'face': '' } self.current = None self.curr_data = [] def start_elem(self, name, attrs): self.curr_data = [] if name != 'font' and name in self.attrs: self.current = name else: self.current = None def end_elem(self, name, code_obj): if name == 'font': code_obj.properties['font'] = self.attrs return True elif self.current is not None: decode = self.dicts.get(self.current) if decode: val = decode.get("".join(self.curr_data), '0') else: val = "".join(self.curr_data) self.attrs[self.current] = val def char_data(self, data): self.curr_data.append(data) # end of class FontPropertyHandler class DummyPropertyHandler: """Empty handler for properties that do not need code""" def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): return True def char_data(self, data): pass # end of class DummyPropertyHandler class EventsPropertyHandler(object): def __init__(self): self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name, code_obj): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': code_obj.properties['events'] = self.handlers return True def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler class ExtraPropertiesPropertyHandler(object): def __init__(self): self.props = {} self.prop_name = None self.curr_prop = [] def start_elem(self, name, attrs): if name == 'property': name = attrs['name'] if name and name[0].islower(): name = name[0].upper() + name[1:] self.prop_name = name def end_elem(self, name, code_obj): if name == 'property': if self.prop_name and self.curr_prop: self.props[self.prop_name] = ''.join(self.curr_prop) self.prop_name = None self.curr_prop = [] elif name == 'extraproperties': code_obj.properties['extraproperties'] = self.props return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_prop.append(data) # end of class ExtraPropertiesPropertyHandler # dictionary whose items are custom handlers for widget properties _global_property_writers = { 'font': FontPropertyHandler, 'events': EventsPropertyHandler, 'extraproperties': ExtraPropertiesPropertyHandler, } # dictionary of dictionaries of property handlers specific for a widget # the keys are the class names of the widgets # Ex: _property_writers['wxRadioBox'] = {'choices', choices_handler} _property_writers = {} # map of widget class names to a list of extra modules needed for the # widget. Example: 'wxGrid': 'use Wx::Grid;\n' _widget_extra_modules = {} # set of lines of extra modules to add to the current file _current_extra_modules = {} def get_property_handler(property_name, widget_name): try: cls = _property_writers[widget_name][property_name] except KeyError: cls = _global_property_writers.get(property_name, None) if cls: return cls() return None def add_property_handler(property_name, handler, widget_name=None): """\ sets a function to parse a portion of XML to get the value of the property property_name. If widget_name is not None, the function is called only if the property in inside a widget whose class is widget_name """ if widget_name is None: _global_property_writers[property_name] = handler else: try: _property_writers[widget_name][property_name] = handler except KeyError: _property_writers[widget_name] = { property_name: handler } class WidgetHandler: """\ Interface the various code generators for the widgets must implement """ """list of modules to import (eg. ['use Wx::Grid;\n'])""" import_modules = [] """constructor signature ($self->SUPER::new(@stuff), see new_defaults )""" new_signature = [] def get_code(self, obj): """\ Handler for normal widgets (non-toplevel): returns 3 lists of strings, init, properties and layout, that contain the code for the corresponding methods of the class to generate """ return [], [], [] def get_properties_code(self, obj): """\ Handler for the code of the set_properties method of toplevel objects. Returns a list of strings containing the code to generate """ return [] def get_init_code(self, obj): """\ Handler for the code of the constructor of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add). The generated lines are appended at the end of the constructor """ return [] def get_layout_code(self, obj): """\ Handler for the code of the do_layout method of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add) """ return [] # end of class WidgetHandler def add_widget_handler(widget_name, handler): obj_builders[widget_name] = handler def setup(): """\ Code generator setup function. This is called once, when the code generator is loaded in wxglade. """ # scan widgets.txt for widgets, load perl_codegen's _widgets_dir = os.path.join(common.wxglade_path, 'widgets') widgets_file = os.path.join(_widgets_dir, 'widgets.txt') if not os.path.isfile(widgets_file): print >> sys.stderr, "widgets file (%s) doesn't exist" % widgets_file return import sys sys.path.append(_widgets_dir) modules = open(widgets_file) for line in modules: module_name = line.strip() if not module_name or module_name.startswith('#'): continue module_name = module_name.split('#')[0].strip() try: m = __import__( module_name + '.perl_codegen', {}, {}, ['initialize']) m.initialize() except (ImportError, AttributeError): pass ## print 'ERROR loading "%s"' % module_name ## import traceback; ## traceback.print_exc() ## else: ## print 'initialized perl generator for ', module_name modules.close() # ...then, the sizers import edit_sizers.perl_sizers_codegen edit_sizers.perl_sizers_codegen.initialize() spe-0.8.4.h/_spe/plugins/wxGlade/codegen/py_codegen.py0000644000175000017500000015473410743421035021667 0ustar stanistani# py_codegen.py: python code generator # $Id: py_codegen.py,v 1.66 2007/08/07 12:15:21 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY # this version hacked by John Dubery """\ How the code is generated: every time the end of an object is reached during the parsing of the xml tree, either the function 'add_object' or the function 'add_class' is called: the latter when the object is a toplevel one, the former when it is not. In the last case, 'add_object' calls the appropriate ``writer'' function for the specific object, found in the 'obj_builders' dict. Such function accepts one argument, the CodeObject representing the object for which the code has to be written, and returns 3 lists of strings, representing the lines to add to the '__init__', '__set_properties' and '__do_layout' methods of the parent object. """ import sys, os, os.path import common, config import cStringIO from xml_parse import XmlParsingError import re # these two globals must be defined for every code generator module language = 'python' writer = sys.modules[__name__] # the writer is the module itself # default extensions for generated files: a list of file extensions default_extensions = ['py'] """\ dictionary that maps the lines of code of a class to the name of such class: the lines are divided in 3 categories: '__init__', '__set_properties' and '__do_layout' """ classes = None """dictionary of ``writers'' for the various objects""" obj_builders = {} """\ dictionary of ``property writer'' functions, used to set the properties of a toplevel object """ obj_properties = {} # random number used to be sure that the replaced tags in the sources are # the right ones (see SourceFileContent and add_class) nonce = None # lines common to all the generated files (import of wxPython, ...) header_lines = [] # if True, generate a file for each custom class multiple_files = False # if not None, it is the single source file to write into output_file = None output_file_name = None # if not None, it is the directory inside which the output files are saved out_dir = None # ALB 2003-11-20: transition to the new wxPython, i.e. from: # from wxPython.wx import * # w = wxWindow(...) # # to # # import wx # w = wx.Window(...) use_new_namespace = True def cn(class_name): if use_new_namespace: if class_name[:2] == 'wx': return 'wx.' + class_name[2:] elif class_name[:4] == 'EVT_': return 'wx.' + class_name return class_name def cn_f(flags): if use_new_namespace: return "|".join([cn(f) for f in str(flags).split('|')]) else: return str(flags) # ALB 2004-12-05: wx version we are generating code for for_version = (2, 4) class ClassLines: """\ Stores the lines of python code for a custom class """ def __init__(self): self.init = [] # lines of code to insert in the __init__ method # (for children widgets) self.parents_init = [] # lines of code to insert in the __init__ for # container widgets (panels, splitters, ...) self.sizers_init = [] # lines related to sizer objects declarations self.props = [] # lines to insert in the __set_properties method self.layout = [] # lines to insert in the __do_layout method self.dependencies = {} # names of the modules this class depends on self.done = False # if True, the code for this class has already # been generated # ALB 2004-12-05 self.event_handlers = [] # lines to bind events self.extra_code = [] # extra code to output before this class # end of class ClassLines class SourceFileContent: """\ Keeps info about an existing file that has to be updated, to replace only the lines inside a wxGlade block, an to keep the rest of the file as it was """ def __init__(self, name=None, content=None, classes=None): self.name = name # name of the file self.content = content # content of the source file, if it existed # before this session of code generation self.classes = classes # classes declared in the file self.new_classes = [] # new classes to add to the file (they are # inserted BEFORE the old ones) if classes is None: self.classes = {} self.spaces = {} # indentation level for each class # ALB 2004-12-05 self.event_handlers = {} # list of event handlers for each class if self.content is None: self.build_untouched_content() def build_untouched_content(self): """\ Builds a string with the contents of the file that must be left as is, and replaces the wxGlade blocks with tags that in turn will be replaced by the new wxGlade blocks """ class_name = None new_classes_inserted = False # regexp to match class declarations # jdubery - less precise regex, but matches definitions with base # classes having module qualified names class_decl = re.compile(r'^\s*class\s+([a-zA-Z_]\w*)\s*' '(\([\s\w.,]*\))?:\s*$') # regexps to match wxGlade blocks block_start = re.compile(r'^(\s*)#\s*begin\s+wxGlade:\s*' '([A-Za-z_]+\w*)??[.]?(\w+)\s*$') block_end = re.compile(r'^\s*#\s*end\s+wxGlade\s*$') # regexp to match event handlers # ALB 2004-12-05 event_handler = re.compile(r'^\s+def\s+([A-Za-z_]+\w*)\s*\(.*\):\s*' '#\s*wxGlade:\s*(\w+)\.\s*$') inside_block = False inside_triple_quote = False triple_quote_str = None tmp_in = open(self.name) out_lines = [] for line in tmp_in: quote_index = -1 if not inside_triple_quote: triple_dquote_index = line.find('"""') triple_squote_index = line.find("'''") if triple_squote_index == -1: quote_index = triple_dquote_index tmp_quote_str = '"""' elif triple_dquote_index == -1: quote_index = triple_squote_index tmp_quote_str = "'''" else: quote_index, tmp_quote_str = min( (triple_squote_index, "'''"), (triple_dquote_index, '"""')) if not inside_triple_quote and quote_index != -1: inside_triple_quote = True triple_quote_str = tmp_quote_str if inside_triple_quote: end_index = line.rfind(triple_quote_str) if quote_index < end_index and end_index != -1: inside_triple_quote = False result = class_decl.match(line) if not inside_triple_quote and not inside_block and \ result is not None: ## print ">> class %r" % result.group(1) if class_name is None: # this is the first class declared in the file: insert the # new ones before this out_lines.append('<%swxGlade insert new_classes>' % nonce) new_classes_inserted = True class_name = result.group(1) # ALB 2007-08-06: if we're in a subpackage, we should include # the package name in the class name class_name = self.add_package(class_name) self.classes[class_name] = 1 # add the found class to the list # of classes of this module out_lines.append(line) elif not inside_block: result = block_start.match(line) if not inside_triple_quote and result is not None: ## print ">> block %r %r %r" % ( ## result.group(1), result.group(2), result.group(3)) # replace the lines inside a wxGlade block with a tag that # will be used later by add_class spaces = result.group(1) which_class = result.group(2) which_block = result.group(3) if which_class is None: which_class = class_name else: which_class = self.add_package(which_class) self.spaces[which_class] = spaces inside_block = True if class_name is None: out_lines.append('<%swxGlade replace %s>' % \ (nonce, which_block)) else: out_lines.append('<%swxGlade replace %s %s>' % \ (nonce, which_class, which_block)) else: #- ALB 2004-12-05 ---------- result = event_handler.match(line) if not inside_triple_quote and result is not None: which_handler = result.group(1) which_class = self.add_package(result.group(2)) self.event_handlers.setdefault( which_class, {})[which_handler] = 1 if class_name is not None and self.is_end_of_class(line): # add extra event handlers here... out_lines.append('<%swxGlade event_handlers %s>' % (nonce, class_name)) #--------------------------- out_lines.append(line) if self.is_import_line(line): # add a tag to allow extra modules out_lines.append('<%swxGlade extra_modules>\n' % nonce) else: # ignore all the lines inside a wxGlade block if block_end.match(line) is not None: ## print 'end block' inside_block = False if not new_classes_inserted: # if we are here, the previous ``version'' of the file did not # contain any class, so we must add the new_classes tag at the # end of the file out_lines.append('<%swxGlade insert new_classes>' % nonce) tmp_in.close() # set the ``persistent'' content of the file self.content = "".join(out_lines) def is_import_line(self, line): if use_new_namespace: return line.startswith('import wx') else: return line.startswith('from wxPython.wx import *') def is_end_of_class(self, line): return line.strip().startswith('# end of class ') def add_package(self, class_name): if not multiple_files: return class_name name = self.name if out_dir is not None: name = name.replace(out_dir, '') pkg = os.path.dirname(name).replace(os.sep, '.') if pkg.startswith('.'): pkg = pkg[1:] if pkg: return pkg + '.' + class_name else: return class_name # end of class SourceFileContent # if not None, it is an instance of SourceFileContent that keeps info about # the previous version of the source to generate previous_source = None def tabs(number): return ' ' * number # if True, overwrite any previous version of the source file instead of # updating only the wxGlade blocks _overwrite = False # if True, enable gettext support _use_gettext = False _quote_str_pattern = re.compile(r'\\[natbv"]?') def _do_replace(match): if match.group(0) == '\\': return '\\\\' else: return match.group(0) def quote_str(s, translate=True, escape_chars=True): """\ returns a quoted version of 's', suitable to insert in a python source file as a string object. Takes care also of gettext support """ if not s: return '""' s = s.replace('"', r'\"') if escape_chars: s = _quote_str_pattern.sub(_do_replace, s) else: s = s.replace('\\', r'\\') # just quote the backslashes try: unicode(s, 'ascii') if _use_gettext and translate: return '_("' + s + '")' else: return '"' + s + '"' except UnicodeDecodeError: if _use_gettext and translate: return '_(u"' + s + '")' else: return 'u"' + s + '"' def initialize(app_attrs): """\ Writer initialization function. - app_attrs: dict of attributes of the application. The following two are always present: path: output path for the generated code (a file if multi_files is False, a dir otherwise) option: if True, generate a separate file for each custom class """ out_path = app_attrs['path'] multi_files = app_attrs['option'] global classes, header_lines, multiple_files, previous_source, nonce, \ _current_extra_modules, _use_gettext, _overwrite, _current_extra_code import time, random try: _use_gettext = int(app_attrs['use_gettext']) except (KeyError, ValueError): _use_gettext = False # overwrite added 2003-07-15 try: _overwrite = int(app_attrs['overwrite']) except (KeyError, ValueError): _overwrite = False # this is to be more sure to replace the right tags nonce = '%s%s' % (str(time.time()).replace('.', ''), random.randrange(10**6, 10**7)) # ALB 2004-01-18 global use_new_namespace try: use_new_namespace = int(app_attrs['use_new_namespace']) except (KeyError, ValueError): pass # use the default value # ALB 2004-12-05 global for_version try: for_version = tuple([int(t) for t in app_attrs['for_version'].split('.')[:2]]) except (KeyError, ValueError): if common.app_tree is not None: for_version = common.app_tree.app.for_version else: for_version = (2, 4) # default... # add coding (PEP 263) try: _encoding = app_attrs['encoding'] except (KeyError, ValueError): _encoding = None classes = {} _current_extra_modules = {} header_lines = ['# generated by wxGlade %s on %s%s\n\n' % \ (common.version, time.asctime(), common.generated_from()), use_new_namespace and 'import wx\n' or 'from wxPython.wx import *\n'] if not config.preferences.write_timestamp: header_lines[0] = '# generated by wxGlade %s%s\n\n' % \ (common.version, common.generated_from()) # extra lines to generate (see the 'extracode' property of top-level # widgets) _current_extra_code = [] # add coding (PEP 263) if _encoding: header_lines.insert(0, "# -*- coding: %s -*-\n" % _encoding.lower()) multiple_files = multi_files if not multiple_files: global output_file, output_file_name if not _overwrite and os.path.isfile(out_path): # the file exists, we must keep all the lines not inside a wxGlade # block. NOTE: this may cause troubles if out_path is not a valid # python file, so be careful! previous_source = SourceFileContent(out_path) else: # if the file doesn't exist, create it and write the ``intro'' previous_source = None output_file = cStringIO.StringIO() output_file_name = out_path output_file.write('#!/usr/bin/env python\n') for line in header_lines: output_file.write(line) output_file.write('<%swxGlade extra_modules>\n' % nonce) output_file.write('\n<%swxGlade replace extracode>\n\n' % nonce) output_file.write('\n') else: previous_source = None global out_dir if not os.path.isdir(out_path): raise XmlParsingError("'path' must be a directory when generating"\ " multiple output files") out_dir = out_path def finalize(): """\ Writer ``finalization'' function: flushes buffers, closes open files, ... """ if previous_source is not None: # insert all the new custom classes inside the old file tag = '<%swxGlade insert new_classes>' % nonce if previous_source.new_classes: code = "".join(previous_source.new_classes) else: code = "" previous_source.content = previous_source.content.replace(tag, code) tag = '<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) previous_source.content = previous_source.content.replace(tag, code) # extra code (see the 'extracode' property of top-level widgets) tag = '<%swxGlade replace extracode>' % nonce code = "\n".join(['# begin wxGlade: extracode'] + _current_extra_code + ['# end wxGlade\n']) previous_source.content = previous_source.content.replace(tag, code) # now remove all the remaining <123415wxGlade ...> tags from the # source: this may happen if we're not generating multiple files, # and one of the container class names is changed tags = re.findall('(<%swxGlade replace ([a-zA-Z_]\w*) +[.\w]+>)' % \ nonce, previous_source.content) for tag in tags: indent = previous_source.spaces.get(tag[1], tabs(2)) comment = '%s# content of this block not found: ' \ 'did you rename this class?\n%spass\n' % (indent, indent) previous_source.content = previous_source.content.replace(tag[0], comment) # ALB 2004-12-05 tags = re.findall('<%swxGlade event_handlers \w+>' % nonce, previous_source.content) for tag in tags: previous_source.content = previous_source.content.replace(tag, "") # write the new file contents to disk common.save_file(previous_source.name, previous_source.content, 'codegen') elif not multiple_files: global output_file em = "".join(_current_extra_modules.keys()) content = output_file.getvalue().replace( '<%swxGlade extra_modules>\n' % nonce, em) # extra code (see the 'extracode' property of top-level widgets) tag = '<%swxGlade replace extracode>' % nonce code = "\n".join(['# begin wxGlade: extracode'] + _current_extra_code + ['# end wxGlade\n']) content = content.replace(tag, code) output_file.close() try: common.save_file(output_file_name, content, 'codegen') # make the file executable if _app_added: os.chmod(output_file_name, 0755) except IOError, e: raise XmlParsingError(str(e)) except OSError: pass # this isn't necessary a bad error del output_file def test_attribute(obj): """\ Returns True if 'obj' should be added as an attribute of its parent's class, False if it should be created as a local variable of __do_layout. To do so, tests for the presence of the special property 'attribute' """ try: return int(obj.properties['attribute']) except (KeyError, ValueError): return True # this is the default def add_object(top_obj, sub_obj): """\ adds the code to build 'sub_obj' to the class body of 'top_obj'. """ try: klass = classes[top_obj.klass] except KeyError: klass = classes[top_obj.klass] = ClassLines() try: builder = obj_builders[sub_obj.base] except KeyError: # no code generator found: write a comment about it klass.init.extend(['\n', '# code for %s (type %s) not generated: ' 'no suitable writer found' % (sub_obj.name, sub_obj.klass),'\n']) common.message('WARNING', 'code for %s (type %s) not generated: ' 'no suitable writer found', sub_obj.name, sub_obj.klass) else: try: init, props, layout = builder.get_code(sub_obj) except: print sub_obj raise # this shouldn't happen if sub_obj.in_windows: # the object is a wxWindow instance # --- patch 2002-08-26 ------------------------------------------ if sub_obj.is_container and not sub_obj.is_toplevel: init.reverse() klass.parents_init.extend(init) else: klass.init.extend(init) # --------------------------------------------------------------- # ALB 2004-12-05 mycn = getattr(builder, 'cn', cn) if hasattr(builder, 'get_events'): evts = builder.get_events(sub_obj) for id, event, handler in evts: klass.event_handlers.append((id, mycn(event), handler)) elif 'events' in sub_obj.properties: id_name, id = generate_code_id(sub_obj) #if id == '-1': id = 'self.%s.GetId()' % sub_obj.name if id == '-1': id = '#self.%s' % sub_obj.name for event, handler in sub_obj.properties['events'].iteritems(): klass.event_handlers.append((id, mycn(event), handler)) # try to see if there's some extra code to add to this class if not sub_obj.preview: extra_code = getattr(builder, 'extracode', sub_obj.properties.get('extracode', "")) if extra_code: extra_code = re.sub(r'\\n', '\n', extra_code) klass.extra_code.append(extra_code) # if we are not overwriting existing source, warn the user # about the presence of extra code if multiple_files: warn = False else: warn = previous_source is not None if warn: common.message( 'WARNING', '%s has extra code, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ sub_obj.name) else: # the object is a sizer # ALB 2004-09-17: workaround (hack) for static box sizers... if sub_obj.base == 'wxStaticBoxSizer': klass.parents_init.insert(1, init.pop(0)) klass.sizers_init.extend(init) klass.props.extend(props) klass.layout.extend(layout) if multiple_files and \ (sub_obj.is_toplevel and sub_obj.base != sub_obj.klass): key = 'from %s import %s\n' % (sub_obj.klass, without_package(sub_obj.klass)) klass.dependencies[key] = 1 ## for dep in _widget_extra_modules.get(sub_obj.base, []): for dep in getattr(obj_builders.get(sub_obj.base), 'import_modules', []): klass.dependencies[dep] = 1 def add_sizeritem(toplevel, sizer, obj, option, flag, border): """\ writes the code to add the object 'obj' to the sizer 'sizer' in the 'toplevel' object. """ # an ugly hack to allow the addition of spacers: if obj_name can be parsed # as a couple of integers, it is the size of the spacer to add obj_name = obj.name try: w, h = [ int(s) for s in obj_name.split(',') ] except ValueError: if obj.in_windows: # attribute is a special property, which tells us if the object # is a local variable or an attribute of its parent if test_attribute(obj): obj_name = 'self.' + obj_name if obj.base == 'wxNotebook' and for_version < (2, 5): obj_name = cn('wxNotebookSizer') + '(%s)' % obj_name else: obj_name = '(%d, %d)' % (w, h) # it was the dimension of a spacer try: klass = classes[toplevel.klass] except KeyError: klass = classes[toplevel.klass] = ClassLines() buffer = '%s.Add(%s, %s, %s, %s)\n' % \ (sizer.name, obj_name, option, cn_f(flag), cn_f(border)) klass.layout.append(buffer) def without_package(class_name): """\ Removes the package name from the given class name """ return class_name.split('.')[-1] def add_class(code_obj): """\ Generates the code for a custom class. """ global _current_extra_modules if not multiple_files: # in this case, previous_source is the SourceFileContent instance # that keeps info about the single file to generate prev_src = previous_source else: # let's see if the file to generate exists, and in this case # create a SourceFileContent instance filename = os.path.join(out_dir, code_obj.klass.replace('.', os.sep) + '.py') if _overwrite or not os.path.exists(filename): prev_src = None else: prev_src = SourceFileContent(filename) _current_extra_modules = {} if classes.has_key(code_obj.klass) and classes[code_obj.klass].done: return # the code has already been generated try: builder = obj_builders[code_obj.base] mycn = getattr(builder, 'cn', cn) mycn_f = getattr(builder, 'cn_f', cn_f) except KeyError: raise # this is an error, let the exception be raised if prev_src is not None and prev_src.classes.has_key(code_obj.klass): is_new = False indentation = prev_src.spaces[code_obj.klass] else: # this class wasn't in the previous version of the source (if any) is_new = True indentation = tabs(2) mods = getattr(builder, 'extra_modules', []) if mods: for m in mods: _current_extra_modules[m] = 1 buffer = [] write = buffer.append if not classes.has_key(code_obj.klass): # if the class body was empty, create an empty ClassLines classes[code_obj.klass] = ClassLines() # try to see if there's some extra code to add to this class if not code_obj.preview: extra_code = getattr(builder, 'extracode', code_obj.properties.get('extracode', "")) if extra_code: extra_code = re.sub(r'\\n', '\n', extra_code) classes[code_obj.klass].extra_code.append(extra_code) if not is_new: common.message('WARNING', '%s has extra code, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ code_obj.name) if not multiple_files and extra_code: _current_extra_code.append("".join( classes[code_obj.klass].extra_code[::-1])) # ALB 2007-08-31 custom base classes support custom_base = getattr(code_obj, 'custom_base', code_obj.properties.get('custom_base', None)) if code_obj.preview or (custom_base and not custom_base.strip()): custom_base = None if is_new: base = mycn(code_obj.base) if custom_base is not None: base = ", ".join([b.strip() for b in custom_base.split(',')]) if code_obj.preview and code_obj.klass == base: import random klass = code_obj.klass + ('_%d' % random.randrange(10**8, 10**9)) else: klass = code_obj.klass write('class %s(%s):\n' % (without_package(klass), base)) write(tabs(1) + 'def __init__(self, *args, **kwds):\n') elif custom_base is not None: # custom base classes set, but "overwrite existing sources" not # set. Issue a warning about this common.message('WARNING', '%s has custom base classes, but you are ' 'not overwriting existing sources: please check that ' 'the resulting code is correct!' % code_obj.name) # __init__ begin tag write(indentation + '# begin wxGlade: %s.__init__\n' % \ without_package(code_obj.klass)) prop = code_obj.properties style = prop.get("style", None) if style: write(indentation + 'kwds["style"] = %s\n' % mycn_f(style)) # __init__ if custom_base is not None: bases = [b.strip() for b in custom_base.split(',')] for i, b in enumerate(bases): if not i: write(indentation + '%s.__init__(self, *args, **kwds)\n' % b) else: write(indentation + '%s.__init__(self)\n' % b) else: write(indentation + '%s.__init__(self, *args, **kwds)\n' % \ mycn(code_obj.base)) tab = indentation init_lines = classes[code_obj.klass].init # --- patch 2002-08-26 --------------------------------------------------- parents_init = classes[code_obj.klass].parents_init parents_init.reverse() for l in parents_init: write(tab+l) # ------------------------------------------------------------------------ for l in init_lines: write(tab + l) # now check if there are extra lines to add to the init method if hasattr(builder, 'get_init_code'): for l in builder.get_init_code(code_obj): write(tab + l) write('\n' + tab + 'self.__set_properties()\n') write(tab + 'self.__do_layout()\n') # ALB 2004-12-05 now let's write the "event table"... event_handlers = classes[code_obj.klass].event_handlers if hasattr(builder, 'get_events'): for id, event, handler in builder.get_events(code_obj): event_handlers.append((id, mycn(event), handler)) if event_handlers: write('\n') if for_version < (2, 5) or not use_new_namespace: for win_id, event, handler in event_handlers: if win_id.startswith('#'): win_id = win_id[1:] + '.GetId()' write(tab + '%s(self, %s, self.%s)\n' % \ (event, win_id, handler)) else: for win_id, event, handler in event_handlers: if win_id.startswith('#'): write(tab + 'self.Bind(%s, self.%s, %s)\n' % \ (event, handler, win_id[1:])) else: write(tab + 'self.Bind(%s, self.%s, id=%s)\n' % \ (event, handler, win_id)) # end tag write(tab + '# end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __init__ wxGlade block with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__init__') if prev_src.content.find(tag) < 0: # no __init__ tag found, issue a warning and do nothing common.message("WARNING", "wxGlade __init__ block not found for %s," \ " __init__ code NOT generated" % code_obj.name) else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __set_properties obj_p = getattr(builder, 'get_properties_code', generate_common_properties)(code_obj) obj_p.extend(classes[code_obj.klass].props) write_body = len(obj_p) if is_new: write('\n%sdef __set_properties(self):\n' % tabs(1)) # begin tag write(tab + '# begin wxGlade: %s.__set_properties\n' % \ without_package(code_obj.klass)) if not write_body: write(tab + 'pass\n') else: for l in obj_p: write(tab + l) # end tag write(tab + '# end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __set_properties wxGlade block # with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__set_properties') if prev_src.content.find(tag) < 0: # no __set_properties tag found, issue a warning and do nothing common.message("WARNING", "wxGlade __set_properties block " \ "not found for %s, " "__set_properties code NOT generated" % code_obj.name) else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) buffer = [] write = buffer.append # __do_layout if is_new: write('\n' + tabs(1) + 'def __do_layout(self):\n') layout_lines = classes[code_obj.klass].layout sizers_init_lines = classes[code_obj.klass].sizers_init # check if there are extra layout lines to add if hasattr(builder, 'get_layout_code'): extra_layout_lines = builder.get_layout_code(code_obj) else: extra_layout_lines = [] # begin tag write(tab + '# begin wxGlade: %s.__do_layout\n' % \ without_package(code_obj.klass)) if layout_lines or sizers_init_lines or extra_layout_lines: sizers_init_lines.reverse() for l in sizers_init_lines: write(tab + l) for l in layout_lines: write(tab + l) #write(tab + 'self.Layout()\n') for l in extra_layout_lines: write(tab + l) else: write(tab + 'pass\n') # end tag write(tab + '# end wxGlade\n') if prev_src is not None and not is_new: # replace the lines inside the __do_layout wxGlade block # with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, '__do_layout') if prev_src.content.find(tag) < 0: # no __do_layout tag found, issue a warning and do nothing common.message("WARNING", "wxGlade __do_layout block " \ "not found for %s, __do_layout code NOT generated" % code_obj.name) else: prev_src.content = prev_src.content.replace(tag, "".join(buffer)) # ALB 2004-12-05 now let's generate the event handler stubs... if prev_src is not None and not is_new: already_there = prev_src.event_handlers.get(code_obj.klass, {}) buf = [] for name, event, handler in event_handlers: if handler not in already_there: buf.append(tabs(1) + 'def %s(self, event): ' '# wxGlade: %s.\n' % (handler, without_package(code_obj.klass))) buf.append( tab + 'print "Event handler `%s\' not implemented"\n' % handler) buf.append(tab + 'event.Skip()\n\n') already_there[handler] = 1 tag = '<%swxGlade event_handlers %s>' % (nonce, code_obj.klass) if prev_src.content.find(tag) < 0: # no event_handlers tag found, issue a warning and do nothing common.message("WARNING", "wxGlade event_handlers block " \ "not found for %s," " event_handlers code NOT generated" % code_obj.name) else: prev_src.content = prev_src.content.replace(tag, "".join(buf)) del buf else: already_there = {} for name, event, handler in event_handlers: if handler not in already_there: write('\n' + tabs(1) + 'def %s(self, event): ' '# wxGlade: %s.\n' % (handler, without_package(code_obj.klass))) write(tab + 'print "Event handler `%s\' not implemented!"\n' % handler) write(tab + 'event.Skip()\n') already_there[handler] = 1 # the code has been generated classes[code_obj.klass].done = True write('\n# end of class %s\n\n\n' % without_package(code_obj.klass)) if not multiple_files and prev_src is not None: # if this is a new class, add its code to the new_classes list of the # SourceFileContent instance if is_new: prev_src.new_classes.append("".join(buffer)) return if multiple_files: if prev_src is not None: tag = '<%swxGlade insert new_classes>' % nonce prev_src.content = prev_src.content.replace(tag, "") #code) # insert the extra modules tag = '<%swxGlade extra_modules>\n' % nonce code = "".join(_current_extra_modules.keys()) prev_src.content = prev_src.content.replace(tag, code) # insert the module dependencies of this class extra_modules = classes[code_obj.klass].dependencies.keys() deps = ['# begin wxGlade: dependencies\n'] + extra_modules + \ ['# end wxGlade\n'] tag = '<%swxGlade replace dependencies>' % nonce prev_src.content = prev_src.content.replace(tag, "".join(deps)) # insert the extra code of this class extra_code = "".join(classes[code_obj.klass].extra_code[::-1]) # if there's extra code but we are not overwriting existing # sources, warn the user if extra_code: common.message('WARNING', '%s (or one of its chilren) has ' 'extra code classes, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ code_obj.name) extra_code = '# begin wxGlade: extracode\n%s\n# end wxGlade\n' % \ extra_code ## "".join(classes[code_obj.klass].extra_code[::-1]) tag = '<%swxGlade replace extracode>' % nonce prev_src.content = prev_src.content.replace(tag, extra_code) try: # store the new file contents to disk common.save_file(filename, prev_src.content, 'codegen') except: raise IOError("py_codegen.add_class: %s, %s, %s" % \ (out_dir, prev_src.name, code_obj.klass)) return # create the new source file filename = os.path.join(out_dir, code_obj.klass.replace('.', os.sep) + '.py') out = cStringIO.StringIO() write = out.write # write the common lines for line in header_lines: write(line) # write the module dependecies for this class write('\n# begin wxGlade: dependencies\n') for module in classes[code_obj.klass].dependencies: write(module) write('# end wxGlade\n') write('\n') # insert the extra code of this class extra_code = "".join(classes[code_obj.klass].extra_code[::-1]) extra_code = '# begin wxGlade: extracode\n%s\n# end wxGlade\n' % \ extra_code write(extra_code) write('\n') # write the class body for line in buffer: write(line) try: # store the contents to filename common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_exc() out.close() else: # not multiple_files # write the class body onto the single source file for dep in classes[code_obj.klass].dependencies: _current_extra_modules[dep] = 1 if classes[code_obj.klass].extra_code: _current_extra_code.extend(classes[code_obj.klass].extra_code[::-1]) write = output_file.write for line in buffer: write(line) _app_added = False def add_app(app_attrs, top_win_class): """\ Generates the code for a wxApp instance. If the file to write into already exists, this function does nothing. """ global _app_added _app_added = True name = app_attrs.get('name') if not name: name = 'app' if not multiple_files: prev_src = previous_source else: filename = os.path.join(out_dir, name + '.py') if not os.path.exists(filename): prev_src = None elif _overwrite: prev_src = None else: # prev_src doesn't need to be a SourceFileContent instance in this # case, as we do nothing if it is not None prev_src = 1 if prev_src is not None: return # do nothing if the file existed klass = app_attrs.get('class') top_win = app_attrs.get('top_window') if not top_win: return # do nothing if there is no top window lines = [] append = lines.append if klass: tab = tabs(2) append('class %s(%s):\n' % (klass, cn('wxApp'))) append(tabs(1) + 'def OnInit(self):\n') else: tab = tabs(1) append('if __name__ == "__main__":\n') if _use_gettext: append(tab + 'import gettext\n') append(tab + 'gettext.install("%s") # replace with the appropriate' ' catalog name\n\n' % name) append(tab + '%s = %s(0)\n' % (name, cn('wxPySimpleApp'))) append(tab + cn('wxInitAllImageHandlers') + '()\n') # to avoid troubles append(tab + '%s = %s(None, -1, "")\n' % (top_win, top_win_class)) if klass: append(tab + 'self.SetTopWindow(%s)\n' % top_win) append(tab + '%s.Show()\n' % top_win) append(tab + 'return 1\n\n') append('# end of class %s\n\n' % klass) append('if __name__ == "__main__":\n') tab = tabs(1) if _use_gettext: append(tab + 'import gettext\n') append(tab + 'gettext.install("%s") # replace with the appropriate' ' catalog name\n\n' % name) append(tab + '%s = %s(0)\n' % (name, klass)) else: append(tab + '%s.SetTopWindow(%s)\n' % (name, top_win)) append(tab + '%s.Show()\n' % top_win) append(tab + '%s.MainLoop()\n' % name) if multiple_files: filename = os.path.join(out_dir, name + '.py') out = cStringIO.StringIO() write = out.write write('#!/usr/bin/env python\n') # write the common lines for line in header_lines: write(line) # import the top window module write('from %s import %s\n\n' % (top_win_class, top_win_class)) # write the wxApp code for line in lines: write(line) try: common.save_file(filename, out.getvalue(), 'codegen') except: import traceback; traceback.print_exc() # make the file executable try: os.chmod(filename, 0755) except OSError: pass # this is not a bad error out.close() else: write = output_file.write for line in lines: write(line) def _get_code_name(obj): if obj.is_toplevel: return 'self' else: if test_attribute(obj): return 'self.%s' % obj.name else: return obj.name def generate_code_size(obj): """\ returns the code fragment that sets the size of the given object. """ name = _get_code_name(obj) size = obj.properties.get('size', '').strip() use_dialog_units = (size[-1] == 'd') if for_version < (2, 5) or obj.parent is None: method = 'SetSize' else: method = 'SetMinSize' if use_dialog_units: return name + '.' + method + '(' + cn('wxDLG_SZE') + \ '(%s, (%s)))\n' % (name, size[:-1]) else: return name + '.' + method + '((%s))\n' % size def _string_to_colour(s): return '%d, %d, %d' % (int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16)) def generate_code_foreground(obj): """\ returns the code fragment that sets the foreground colour of the given object. """ self = _get_code_name(obj) try: color = cn('wxColour') + '(%s)' % \ _string_to_colour(obj.properties['foreground']) except (IndexError, ValueError): # the color is from system settings color = cn('wxSystemSettings_GetColour') + '(%s)' % \ cn(obj.properties['foreground']) return self + '.SetForegroundColour(%s)\n' % color def generate_code_background(obj): """\ returns the code fragment that sets the background colour of the given object. """ self = _get_code_name(obj) try: color = cn('wxColour') + '(%s)' % \ _string_to_colour(obj.properties['background']) except (IndexError, ValueError): # the color is from system settings color = cn('wxSystemSettings_GetColour') + '(%s)' % \ cn(obj.properties['background']) return self + '.SetBackgroundColour(%s)\n' % color def generate_code_font(obj): """\ returns the code fragment that sets the font of the given object. """ font = obj.properties['font'] size = font['size'] family = cn(font['family']) underlined = font['underlined'] style = cn(font['style']) weight = cn(font['weight']) face = '"%s"' % font['face'].replace('"', r'\"') self = _get_code_name(obj) return self + '.SetFont(' + cn('wxFont') + '(%s, %s, %s, %s, %s, %s))\n' %\ (size, family, style, weight, underlined, face) def generate_code_id(obj, id=None): """\ returns a 2-tuple of strings representing the LOC that sets the id of the given object: the first line is the declaration of the variable, and is empty if the object's id is a constant, and the second line is the value of the id """ if obj and obj.preview: return '', '-1' # never generate ids for preview code if id is None: id = obj.properties.get('id') if id is None: return '', '-1' tokens = id.split('=') if len(tokens) > 1: name, val = tokens[:2] else: return '', tokens[0] # we assume name is declared elsewhere if not name: return '', val if val.strip() == '?': val = cn('wxNewId()') # check to see if we have to make the var global or not... name = name.strip() val = val.strip() if '.' in name: return ('%s = %s\n' % (name, val), name) return ('global %s; %s = %s\n' % (name, name, val), name) def generate_code_tooltip(obj): """\ returns the code fragment that sets the tooltip of the given object. """ self = _get_code_name(obj) return self + '.SetToolTipString(%s)\n' % \ quote_str(obj.properties['tooltip']) def generate_code_disabled(obj): self = _get_code_name(obj) try: disabled = int(obj.properties['disabled']) except: disabled = False if disabled: return self + '.Enable(False)\n' def generate_code_focused(obj): self = _get_code_name(obj) try: focused = int(obj.properties['focused']) except: focused = False if focused: return self + '.SetFocus()\n' def generate_code_hidden(obj): self = _get_code_name(obj) try: hidden = int(obj.properties['hidden']) except: hidden = False if hidden: return self + '.Hide()\n' def generate_code_extraproperties(obj): self = _get_code_name(obj) prop = obj.properties['extraproperties'] ret = [] for name in sorted(prop): ret.append(self + '.Set%s(%s)\n' % (name, prop[name])) return ret def generate_common_properties(widget): """\ generates the code for various properties common to all widgets (background and foreground colors, font, ...) Returns a list of strings containing the generated code """ prop = widget.properties out = [] if prop.get('size', '').strip(): out.append(generate_code_size(widget)) if prop.get('background'): out.append(generate_code_background(widget)) if prop.get('foreground'): out.append(generate_code_foreground(widget)) if prop.get('font'): out.append(generate_code_font(widget)) # tooltip if prop.get('tooltip'): out.append(generate_code_tooltip(widget)) # trivial boolean properties if prop.get('disabled'): out.append(generate_code_disabled(widget)) if prop.get('focused'): out.append(generate_code_focused(widget)) if prop.get('hidden'): out.append(generate_code_hidden(widget)) # ALB 2007-09-01 extra properties if prop.get('extraproperties') and not widget.preview: out.extend(generate_code_extraproperties(widget)) return out # custom property handlers class FontPropertyHandler: """Handler for font properties""" font_families = { 'default': 'wxDEFAULT', 'decorative': 'wxDECORATIVE', 'roman': 'wxROMAN', 'swiss': 'wxSWISS', 'script': 'wxSCRIPT', 'modern': 'wxMODERN', 'teletype': 'wxTELETYPE' } font_styles = { 'normal': 'wxNORMAL', 'slant': 'wxSLANT', 'italic': 'wxITALIC' } font_weights = { 'normal': 'wxNORMAL', 'light': 'wxLIGHT', 'bold': 'wxBOLD' } def __init__(self): self.dicts = { 'family': self.font_families, 'style': self.font_styles, 'weight': self.font_weights } self.attrs = { 'size': '0', 'style': '0', 'weight': '0', 'family': '0', 'underlined': '0', 'face': '' } self.current = None self.curr_data = [] def start_elem(self, name, attrs): self.curr_data = [] if name != 'font' and name in self.attrs: self.current = name else: self.current = None def end_elem(self, name, code_obj): if name == 'font': code_obj.properties['font'] = self.attrs return True elif self.current is not None: decode = self.dicts.get(self.current) if decode: val = decode.get("".join(self.curr_data), '0') else: val = "".join(self.curr_data) self.attrs[self.current] = val def char_data(self, data): self.curr_data.append(data) # end of class FontPropertyHandler class DummyPropertyHandler: """Empty handler for properties that do not need code""" def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): return True def char_data(self, data): pass # end of class DummyPropertyHandler class EventsPropertyHandler(object): def __init__(self): self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name, code_obj): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': code_obj.properties['events'] = self.handlers return True def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler class ExtraPropertiesPropertyHandler(object): def __init__(self): self.props = {} self.prop_name = None self.curr_prop = [] def start_elem(self, name, attrs): if name == 'property': name = attrs['name'] if name and name[0].islower(): name = name[0].upper() + name[1:] self.prop_name = name def end_elem(self, name, code_obj): if name == 'property': if self.prop_name and self.curr_prop: self.props[self.prop_name] = ''.join(self.curr_prop) self.prop_name = None self.curr_prop = [] elif name == 'extraproperties': code_obj.properties['extraproperties'] = self.props return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_prop.append(data) # end of class ExtraPropertiesPropertyHandler # dictionary whose items are custom handlers for widget properties _global_property_writers = { 'font': FontPropertyHandler, 'events': EventsPropertyHandler, 'extraproperties': ExtraPropertiesPropertyHandler, } # dictionary of dictionaries of property handlers specific for a widget # the keys are the class names of the widgets # Ex: _property_writers['wxRadioBox'] = {'choices', choices_handler} _property_writers = {} # map of widget class names to a list of extra modules needed for the # widget. Example: 'wxGrid': 'from wxPython.grid import *\n' _widget_extra_modules = {} # set of lines of extra modules to add to the current file _current_extra_modules = {} def get_property_handler(property_name, widget_name): try: cls = _property_writers[widget_name][property_name] except KeyError: cls = _global_property_writers.get(property_name, None) if cls: return cls() return None def add_property_handler(property_name, handler, widget_name=None): """\ sets a function to parse a portion of XML to get the value of the property property_name. If widget_name is not None, the function is called only if the property in inside a widget whose class is widget_name """ if widget_name is None: _global_property_writers[property_name] = handler else: try: _property_writers[widget_name][property_name] = handler except KeyError: _property_writers[widget_name] = { property_name: handler } class WidgetHandler: """\ Interface the various code generators for the widgets must implement """ """list of modules to import (eg. ['from wxPython.grid import *\n'])""" import_modules = [] def get_code(self, obj): """\ Handler for normal widgets (non-toplevel): returns 3 lists of strings, init, properties and layout, that contain the code for the corresponding methods of the class to generate """ return [], [], [] def get_properties_code(self, obj): """\ Handler for the code of the set_properties method of toplevel objects. Returns a list of strings containing the code to generate """ return [] def get_init_code(self, obj): """\ Handler for the code of the constructor of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add). The generated lines are appended at the end of the constructor """ return [] def get_layout_code(self, obj): """\ Handler for the code of the do_layout method of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add) """ return [] # end of class WidgetHandler def add_widget_handler(widget_name, handler): obj_builders[widget_name] = handler spe-0.8.4.h/_spe/plugins/wxGlade/codegen/xrc_codegen.py0000644000175000017500000004217410743421035022025 0ustar stanistani# xrc_codegen.py: wxWidgets resources XRC code generator # $Id: xrc_codegen.py,v 1.21 2007/03/27 07:02:06 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY """\ Generates the xml code for the app in XRC format. Calls the appropriate ``writers'' of the various objects. These functions return an instance of XrcObject """ import common, config import sys import cStringIO from xml_parse import XmlParsingError from xml.sax.saxutils import escape, quoteattr, unescape language = "XRC" writer = sys.modules[__name__] # default extensions for generated files: a list of file extensions default_extensions = ['xrc'] # output string buffer for the code output_file = None # name of the output file output_file_name = None # dictionary of ``writers'' for the various objects obj_builders = {} # current indentation level curr_tab = 0 def tabs(number): return ' ' * number # encoding of the application app_encoding = 'ISO-8859-1' # default, if nothing else found class XrcObject: """\ Class to produce the XRC code for a given widget. This is a base class which does nothing """ def __init__(self): self.properties = {} self.children = [] # sub-objects def write_child_prologue(self, child, out_file, ntabs): pass def write_child_epilogue(self, child, out_file, ntabs): pass def write_property(self, name, val, outfile, ntabs): pass def write(self, out_file, ntabs): pass # end of class XrcObject """\ dictionary of active XrcObject instances: during the code generation it stores all the non-sizer objects that have children (i.e. frames, dialogs, panels, notebooks, etc.), while at the end of the code generation, before finalize is called, it contains only the true toplevel objects (frames and dialogs), and is used to write their XML code (see finalize). The other objects are deleted when add_object is called with their corresponding code_object as argument (see add_object) """ xrc_objects = None class SizerItemXrcObject(XrcObject): """\ XrcObject to handle sizer items """ def __init__(self, obj, option, flag, border): XrcObject.__init__(self) self.obj = obj # the XrcObject representing the widget self.option = option self.flag = flag self.border = border def write(self, out_file, ntabs): write = out_file.write write(tabs(ntabs) + '\n') if self.option != '0': write(tabs(ntabs+1) + '\n' % self.option) if self.flag and self.flag != '0': write(tabs(ntabs+1) + '%s\n' % self.flag) if self.border != '0': write(tabs(ntabs+1) + '%s\n' % self.border) # write the widget self.obj.write(out_file, ntabs+1) write(tabs(ntabs) + '\n') # end of class SizerItemXrcObject class SpacerXrcObject(XrcObject): """\ XrcObject to handle widgets """ def __init__(self, size_str, option, flag, border): self.size_str = size_str self.option = option self.flag = flag self.border = border def write(self, out_file, ntabs): write = out_file.write write(tabs(ntabs) + '\n') write(tabs(ntabs+1) + '%s\n' % self.size_str.strip()) if self.option != '0': write(tabs(ntabs+1) + '\n' % self.option) if self.flag and self.flag != '0': write(tabs(ntabs+1) + '%s\n' % self.flag) if self.border != '0': write(tabs(ntabs+1) + '%s\n' % self.border) write(tabs(ntabs) + '\n') # end of class SpacerXrcObject class DefaultXrcObject(XrcObject): """\ Standard XrcObject for every widget, used if no specific XrcObject is available """ def __init__(self, code_obj): XrcObject.__init__(self) self.properties = code_obj.properties self.code_obj = code_obj self.name = code_obj.name self.klass = code_obj.base # custom classes aren't allowed in XRC self.subclass = code_obj.klass def write_property(self, name, val, outfile, ntabs): if val: name = escape(name) outfile.write(tabs(ntabs) + '<%s>%s\n' % \ (name, escape(val), name)) def write(self, out_file, ntabs): write = out_file.write if self.code_obj.in_sizers: write(tabs(ntabs) + '\n' % quoteattr(self.klass)) else: if self.subclass and self.subclass != self.klass: write(tabs(ntabs) + '\n' % \ (quoteattr(self.klass), quoteattr(self.name), quoteattr(self.subclass))) else: write(tabs(ntabs) + '\n' % \ (quoteattr(self.klass), quoteattr(self.name))) tab_str = tabs(ntabs+1) # write the properties if self.properties.has_key('foreground'): if self.properties['foreground'].startswith('#'): # XRC does not support colors from system settings self.properties['fg'] = self.properties['foreground'] del self.properties['foreground'] if self.properties.has_key('background'): if self.properties['background'].startswith('#'): # XRC does not support colors from system settings self.properties['bg'] = self.properties['background'] del self.properties['background'] if self.properties.has_key('font'): font = self.properties['font'] del self.properties['font'] else: font = None style = str(self.properties.get('style', '')) if style and style == '0': del self.properties['style'] if 'id' in self.properties: del self.properties['id'] # id has no meaning for XRC # ALB 2004-12-05 if 'events' in self.properties: #del self.properties['events'] # no event handling in XRC for handler, event in self.properties['events'].iteritems(): write(tab_str + '%s\n' % \ (quoteattr(handler), escape(event))) del self.properties['events'] # 'disabled' property is actually 'enabled' for XRC if 'disabled' in self.properties: try: val = int(self.properties['disabled']) except: val = False if val: self.properties['enabled'] = '0' del self.properties['disabled'] # ALB 2007-08-31 extracode property if 'extracode' in self.properties: write(self.properties['extracode'].replace('\\n', '\n')) del self.properties['extracode'] # custom base classes are ignored for XRC... if 'custom_base' in self.properties: del self.properties['custom_base'] if 'extraproperties' in self.properties: prop = self.properties['extraproperties'] del self.properties['extraproperties'] self.properties.update(prop) for name, val in self.properties.iteritems(): self.write_property(str(name), val, out_file, ntabs+1) # write the font, if present if font: write(tab_str + '\n') tab_str = tabs(ntabs+2) for key, val in font.iteritems(): if val: write(tab_str + '<%s>%s\n' % \ (escape(key), escape(val), escape(key))) write(tabs(ntabs+1) + '\n') # write the children for c in self.children: self.write_child_prologue(c, out_file, ntabs+1) c.write(out_file, ntabs+1) self.write_child_epilogue(c, out_file, ntabs+1) write(tabs(ntabs) + '\n') # end of class DefaultXrcObject class NotImplementedXrcObject(XrcObject): """\ XrcObject used when no code for the widget can be generated (for example, because XRC does not currently handle such widget) """ def __init__(self, code_obj): XrcObject.__init__(self) self.code_obj = code_obj def write(self, outfile, ntabs): m = 'code generator for %s objects not available' % self.code_obj.base print >> sys.stderr, 'WARNING: %s' % m outfile.write(tabs(ntabs) + '\n' % m) # end of class NotImplementedXrcObject def initialize(app_attrs): #out_path, multi_files): """\ Code generator initialization function. """ out_path = app_attrs['path'] multi_files = app_attrs['option'] global output_file, curr_tab, xrc_objects, output_file_name, app_encoding # first, set the app encoding if 'encoding' in app_attrs: app_encoding = app_attrs['encoding'] # wx doesn't like latin-1 if app_encoding == 'latin-1': app_encoding = 'ISO-8859-1' if multi_files: # for now we handle only single-file code generation raise IOError("XRC code cannot be split into multiple files") output_file_name = out_path output_file = cStringIO.StringIO() #open(out_path, 'w') from time import asctime header_lines = ['' % app_encoding, '' % \ (common.version, asctime(), common.generated_from())] if not config.preferences.write_timestamp: header_lines[1] = '' % \ (common.version, common.generated_from()) for line in header_lines: output_file.write(line + '\n') output_file.write('\n\n') curr_tab = 1 xrc_objects = {} def finalize(): """\ Code generator finalization function. """ # write the code for every toplevel object for obj in xrc_objects.itervalues(): obj.write(output_file, 1) output_file.write('\n') #output_file.close() # store the contents to file common.save_file(output_file_name, output_file.getvalue(), 'codegen') def add_object(unused, sub_obj): """\ Adds the object sub_obj to the XRC tree. The first argument is unused. """ # what we need in XRC is not top_obj, but sub_obj's true parent top_obj = sub_obj.parent builder = obj_builders.get(sub_obj.base, DefaultXrcObject) try: # check whether we already created the xrc_obj xrc_obj = sub_obj.xrc except AttributeError: xrc_obj = builder(sub_obj) # builder functions must return a subclass # of XrcObject sub_obj.xrc = xrc_obj else: # if we found it, remove it from the xrc_objects dictionary (if it was # there, i.e. the object is not a sizer), because this isn't a true # toplevel object if sub_obj in xrc_objects: del xrc_objects[sub_obj] # let's see if sub_obj's parent already has an XrcObject: if so, it is # temporairly stored in the xrc_objects dict... try: top_xrc = xrc_objects[top_obj] except KeyError: # ...otherwise, create it and store it in the xrc_objects dict top_xrc = obj_builders.get(top_obj.base, DefaultXrcObject)(top_obj) top_obj.xrc = top_xrc xrc_objects[top_obj] = top_xrc top_obj.xrc.children.append(xrc_obj) def add_sizeritem(unused, sizer, obj, option, flag, border): """\ Adds a sizeritem to the XRC tree. The first argument is unused. """ # what we need in XRC is not toplevel, but sub_obj's true parent toplevel = obj.parent top_xrc = toplevel.xrc obj_xrc = obj.xrc try: sizer_xrc = sizer.xrc except AttributeError: # if the sizer has not an XrcObject yet, create it now sizer_xrc = obj_builders.get(sizer.base, DefaultXrcObject)(sizer) sizer.xrc = sizer_xrc # we now have to move the children from 'toplevel' to 'sizer' index = top_xrc.children.index(obj_xrc) if obj.klass == 'spacer': w = obj.properties.get('width', '0') h = obj.properties.get('height', '0') obj_xrc = SpacerXrcObject('%s, %s' % (w, h), str(option), str(flag), str(border)) sizer.xrc.children.append(obj_xrc) else: sizeritem_xrc = SizerItemXrcObject(obj_xrc, str(option), str(flag), str(border)) sizer.xrc.children.append(sizeritem_xrc) del top_xrc.children[index] def add_class(code_obj): """\ Add class behaves very differently for XRC output than for other lanaguages (i.e. pyhton): since custom classes are not supported in XRC, this has effect only for true toplevel widgets, i.e. frames and dialogs. For other kinds of widgets, this is equivalent to add_object """ if not xrc_objects.has_key(code_obj): builder = obj_builders.get(code_obj.base, DefaultXrcObject) xrc_obj = builder(code_obj) code_obj.xrc = xrc_obj # add the xrc_obj to the dict of the toplevel ones xrc_objects[code_obj] = xrc_obj def add_app(app_attrs, top_win_class): # in the case of XRC output, there's no wxApp code to generate pass class FontPropertyHandler: def __init__(self): self.props = {'size': '', 'family': '', 'style': '', 'weight': '', 'underlined': '', 'face': ''} self.current = None def start_elem(self, name, attrs): self.current = name def end_elem(self, name, code_obj): if name == 'font': code_obj.properties['font'] = self.props return True # to remove this handler def char_data(self, data): self.props[self.current] = str(data.strip()) # end of class FontHandler class EventsPropertyHandler(object): def __init__(self): self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name, code_obj): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': code_obj.properties['events'] = self.handlers return True def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler class DummyPropertyHandler: """Empty handler for properties that do not need code""" def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): return True def char_data(self, data): pass # end of class DummyPropertyHandler class ExtraPropertiesPropertyHandler(object): def __init__(self): self.props = {} self.prop_name = None self.curr_prop = [] def start_elem(self, name, attrs): if name == 'property': self.prop_name = attrs['name'] def end_elem(self, name, code_obj): if name == 'property': if self.prop_name and self.curr_prop: self.props[self.prop_name] = ''.join(self.curr_prop) self.prop_name = None self.curr_prop = [] elif name == 'extraproperties': code_obj.properties['extraproperties'] = self.props return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_prop.append(data) # end of class ExtraPropertiesPropertyHandler # dictionary whose items are custom handlers for widget properties _global_property_writers = { 'font': FontPropertyHandler, 'events': EventsPropertyHandler, 'extraproperties': ExtraPropertiesPropertyHandler, } # dictionary of dictionaries of property handlers specific for a widget # the keys are the class names of the widgets # Ex: _property_writers['wxRadioBox'] = {'choices', choices_handler} _property_writers = {} def get_property_handler(property_name, widget_name): try: cls = _property_writers[widget_name][property_name] except KeyError: cls = _global_property_writers.get(property_name, None) if cls: return cls() return None def add_property_handler(property_name, handler, widget_name=None): """\ sets a function to parse a portion of XML to get the value of the property property_name. If widget_name is not None, the function is called only if the property in inside a widget whose class is widget_name """ if widget_name is None: _global_property_writers[property_name] = handler else: try: _property_writers[widget_name][property_name] = handler except KeyError: _property_writers[widget_name] = { property_name: handler } def add_widget_handler(widget_name, handler, *args, **kwds): obj_builders[widget_name] = handler spe-0.8.4.h/_spe/plugins/wxGlade/codegen/cpp_codegen.py0000644000175000017500000020565210743421035022015 0ustar stanistani# cpp_codegen.py: C++ code generator # $Id: cpp_codegen.py,v 1.49 2007/03/30 06:37:53 agriggio Exp $ # # Copyright (c) 2002-2007 Alberto Griggio # License: MIT (see license.txt) # THIS PROGRAM COMES WITH NO WARRANTY import sys, os, os.path import common, config import cStringIO, re from xml_parse import XmlParsingError # these two globals must be defined for every code generator module language = 'C++' writer = sys.modules[__name__] # the writer is the module itself # default extensions for generated files: a list of file extensions default_extensions = ['h', 'cpp'] """\ dictionary that maps the lines of code of a class to the name of such class: the lines are divided in 3 categories: lines in the constructor, 'set_properties' and 'do_layout' """ classes = None """\ dictionary of ``writers'' for the various objects. These are objects that must implement the WidgetHandler interface (see below) """ obj_builders = {} # random number used to be sure that the replaced tags in the sources are # the right ones (see SourceFileContent and add_class) nonce = None # lines common to all the generated files (include of , ...) header_lines = [] # if True, generate a file for each custom class multiple_files = False # if not None, they are the header and source file to write into output_header, output_source = None, None # if not None, name (without extension) of the file to write into output_name = None # if not None, it is the directory inside which the output files are saved out_dir = None # ALB 2004-12-05: wx version we are generating code for for_version = (2, 4) class ClassLines: """\ Stores the lines of python code for a custom class """ def __init__(self): self.init = [] # lines of code to insert in the constructor self.parents_init = [] # lines of code to insert in the constructor for # container widgets (panels, splitters, ...) self.ids = [] # ids declared in the source (to use for Event handling): # these are grouped together into a public enum in # the custom class self.sizers_init = [] # lines related to sizer objects declarations self.props = [] # lines to insert in the __set_properties method self.layout = [] # lines to insert in the __do_layout method self.sub_objs = [] # list of 2-tuples (type, name) of the # sub-objects which are attributes of the # toplevel object self.dependencies = [] # names of the modules this class depends on self.done = False # if True, the code for this class has already # been generated # ALB 2004-12-08 self.event_handlers = [] # lines to bind events self.extra_code_h = [] # extra code to output self.extra_code_cpp = [] # end of class ClassLines class SourceFileContent: """\ Keeps info about an existing file that has to be updated, to replace only the lines inside a wxGlade block, an to keep the rest of the file as it was """ def __init__(self, name): self.name = name # name of the file without extension # (both header and .cpp) self.header_content = None # content of the header file self.source_content = None self.classes = {} # classes declared in the file self.new_classes = [] # new classes to add to the file (they are # inserted BEFORE the old ones) # ALB 2004-12-08 self.event_handlers = {} # list of event handlers for each class self.event_table_decl = {} self.event_table_def = {} self.end_class_re = re.compile('^\s*};\s*//\s+wxGlade:\s+end class\s*$') if classes is None: self.classes = {} self.build_untouched_content() def build_untouched_content(self): """\ Builds a string with the contents of the file that must be left as is, and replaces the wxGlade blocks with tags that in turn will be replaced by the new wxGlade blocks """ self._build_untouched(self.name + '.h', True) self._build_untouched(self.name + '.cpp', False) def _build_untouched(self, filename, is_header): class_name = None new_classes_inserted = False # regexp to match class declarations (this isn't very accurate - # doesn't match template classes, nor virtual inheritance, but # should be enough for most cases) class_decl = re.compile(r'^\s*class\s+([a-zA-Z_]\w*)\s*') ## '(:\s*(public|protected|private)?\s+[\w:]+' ## '(,\s*(public|protected|private)?\s+[\w:]+)*' ## ')?') # regexps to match wxGlade blocks block_start = re.compile(r'^\s*//\s*begin\s+wxGlade:\s*' '(\w*)::(\w+)\s*$') block_end = re.compile(r'^\s*//\s*end\s+wxGlade\s*$') # regexp to match event handlers # ALB 2004-12-08 event_handler = re.compile(r'^\s*(?:virtual\s+)?' 'void\s+([A-Za-z_]+\w*)\s*' '\([A-Za-z_:0-9]+\s*&\s*\w*\)\s*;\s*' '//\s*wxGlade:\s*\s*$') decl_event_table = re.compile(r'^\s*DECLARE_EVENT_TABLE\s*\(\s*\)' '\s*;?\s*$') def_event_table = re.compile(r'^\s*BEGIN_EVENT_TABLE\s*\(\s*(\w+)\s*,' '\s*(\w+)\s*\)\s*$') event_handlers_marker = re.compile(r'^\s*//\s*wxGlade:\s*add\s+' '((?:\w|:)+)\s+event handlers\s*$') prev_was_handler = False events_tag_added = False inside_block = False inside_comment = False tmp_in = open(filename) out_lines = [] for line in tmp_in: comment_index = line.find('/*') if not inside_comment and comment_index != -1 \ and comment_index > line.find('//'): inside_comment = True if inside_comment: end_index = line.find('*/') if end_index > comment_index: inside_comment = False if not is_header: result = None else: result = class_decl.match(line) if not inside_comment and not inside_block and result is not None: if class_name is None: # this is the first class declared in the file: insert the # new ones before this out_lines.append('<%swxGlade insert new_classes>' % nonce) new_classes_inserted = True class_name = result.group(1) ## print 'OK:', class_name self.classes[class_name] = 1 # add the found class to the list # of classes of this module out_lines.append(line) elif not inside_block: result = block_start.match(line) if not inside_comment and result is not None: # replace the lines inside a wxGlade block with a tag that # will be used later by add_class inside_block = True out_lines.append('<%swxGlade replace %s %s>' % \ (nonce, result.group(1), result.group(2))) else: dont_append = False # ALB 2004-12-08 event handling support... if is_header and not inside_comment: result = event_handler.match(line) if result is not None: prev_was_handler = True which_handler = result.group(1) which_class = class_name #result.group(2) self.event_handlers.setdefault( which_class, {})[which_handler] = 1 else: if prev_was_handler: # add extra event handlers here... out_lines.append('<%swxGlade event_handlers %s>' % (nonce, class_name)) prev_was_handler = False events_tag_added = True elif not events_tag_added and \ self.is_end_of_class(line): out_lines.append('<%swxGlade event_handlers %s>' % (nonce, class_name)) # now try to see if we already have a # DECLARE_EVENT_TABLE result = decl_event_table.match(line) if result is not None: self.event_table_decl[class_name] = True elif not inside_comment: result = event_handlers_marker.match(line) if result is not None: out_lines.append('<%swxGlade add %s event ' 'handlers>' % \ (nonce, result.group(1))) dont_append = True result = def_event_table.match(line) if result is not None: which_class = result.group(1) self.event_table_def[which_class] = True # ---------------------------------------- if not dont_append: out_lines.append(line) else: # ignore all the lines inside a wxGlade block if block_end.match(line) is not None: inside_block = False if is_header and not new_classes_inserted: # if we are here, the previous ``version'' of the file did not # contain any class, so we must add the new_classes tag at the # end of the file out_lines.append('<%swxGlade insert new_classes>' % nonce) tmp_in.close() # set the ``persistent'' content of the file if is_header: self.header_content = "".join(out_lines) else: self.source_content = "".join(out_lines) def is_end_of_class(self, line): # not really, but for wxglade-generated code it should work... return self.end_class_re.match(line) is not None #[:2] == '};' # end of class SourceFileContent # if not None, it is an instance of SourceFileContent that keeps info about # the previous version of the source to generate previous_source = None def tabs(number): return ' ' * number # if True, overwrite any previous version of the source file instead of # updating only the wxGlade blocks _overwrite = False # if True, enable gettext support _use_gettext = False _quote_str_pattern = re.compile(r'\\[natbv"]?') def _do_replace(match): if match.group(0) == '\\': return '\\\\' else: return match.group(0) def quote_str(s, translate=True, escape_chars=True): """\ returns a quoted version of 's', suitable to insert in a C++ source file as a string object. Takes care also of gettext support """ if not s: return 'wxEmptyString' s = s.replace('"', r'\"') if escape_chars: s = _quote_str_pattern.sub(_do_replace, s) else: s = s.replace('\\', r'\\') if _use_gettext and translate: return '_("' + s + '")' else: return 'wxT("' + s + '")' def initialize(app_attrs): """\ Writer initialization function. See py_codegen.initialize for a description of the parameter. """ out_path = app_attrs['path'] multi_files = app_attrs['option'] global classes, header_lines, multiple_files, previous_source, nonce, \ _use_gettext, _overwrite, _last_generated_id, \ _current_extra_code_h, _current_extra_code_cpp import time, random _last_generated_id = 1000 try: _use_gettext = int(app_attrs['use_gettext']) except (KeyError, ValueError): _use_gettext = False # overwrite added 2003-07-15 try: _overwrite = int(app_attrs['overwrite']) except (KeyError, ValueError): _overwrite = False # ALB 2004-12-05 global for_version try: for_version = tuple([int(t) for t in app_attrs['for_version'].split('.')[:2]]) except (KeyError, ValueError): if common.app_tree is not None: for_version = common.app_tree.app.for_version else: for_version = (2, 4) # default... # this is to be more sure to replace the right tags nonce = '%s%s' % (str(time.time()).replace('.', ''), random.randrange(10**6, 10**7)) classes = {} header_lines = ['// -*- C++ -*- generated by wxGlade %s on %s%s\n\n' % \ (common.version, time.asctime(), common.generated_from()), '#include \n', '#include \n'] if not config.preferences.write_timestamp: header_lines[0] = '// -*- C++ -*- generated by wxGlade %s%s\n\n' % \ (common.version, common.generated_from()) # extra lines to generate (see the 'extracode' property of top-level # widgets) _current_extra_code_h = [] _current_extra_code_cpp = [] multiple_files = multi_files if not multiple_files: global output_header, output_source, output_name name, ext = os.path.splitext(out_path) output_name = name if not _overwrite and os.path.isfile(name + '.h'): # the file exists, we must keep all the lines not inside a wxGlade # block. NOTE: this may cause troubles if out_path is not a valid # C++ file, so be careful! previous_source = SourceFileContent(name) else: previous_source = None output_header = cStringIO.StringIO() output_source = cStringIO.StringIO() for line in header_lines: output_header.write(line) #output_source.write(line) # isolation directives oh = os.path.basename(name + '.h').upper().replace('.', '_') # extra headers #for val in _obj_headers.itervalues(): ## for handler in obj_builders.itervalues(): ## for header in getattr(handler, 'extra_headers', []): ## output_header.write('#include %s\n' % header) # now, write the tag to store dependencies output_header.write('<%swxGlade replace dependencies>\n' % nonce) output_header.write('\n#ifndef %s\n#define %s\n' % (oh, oh)) output_header.write('\n') # write the tag to store extra code output_header.write('\n<%swxGlade replace extracode>\n' % nonce) output_source.write(header_lines[0]) output_source.write('#include "%s%s"\n\n' % \ (os.path.basename(name), '.h')) output_source.write('<%swxGlade replace extracode>\n\n' % nonce) else: previous_source = None global out_dir if not os.path.isdir(out_path): raise IOError("'path' must be a directory when generating"\ " multiple output files") out_dir = out_path def finalize(): """\ Writer ``finalization'' function: flushes buffers, closes open files, ... """ if previous_source is not None: # insert all the new custom classes inside the old file tag = '<%swxGlade insert new_classes>' % nonce if previous_source.new_classes: code = "".join([ c[0] for c in previous_source.new_classes]) else: code = "" header_content = previous_source.header_content.replace(tag, code) extra_source = "".join([ c[1] for c in previous_source.new_classes]) source_content = previous_source.source_content # extra code (see the 'extracode' property of top-level widgets) tag = '<%swxGlade replace extracode>' % nonce code = "\n".join(['// begin wxGlade: ::extracode'] + _current_extra_code_h + ['// end wxGlade\n']) header_content = header_content.replace(tag, code) code = "\n".join(['// begin wxGlade: ::extracode'] + _current_extra_code_cpp + ['// end wxGlade\n']) source_content = source_content.replace(tag, code) # -------------------------------------------------------------- # now remove all the remaining <123415wxGlade ...> tags from the # source: this may happen if we're not generating multiple files, # and one of the container class names is changed tags = re.findall('(<%swxGlade replace ([a-zA-Z_]*\w*) (\w+)>)' % nonce, header_content) for tag in tags: if tag[2] == 'dependencies': #print 'writing dependencies' deps = [] for code in classes.itervalues(): deps.extend(code.dependencies) tmp = ["// begin wxGlade: ::dependencies\n"] for dep in _unique(deps): if dep and ('"' != dep[0] != '<'): tmp.append('#include "%s.h"\n' % dep) else: tmp.append('#include %s\n' % dep) tmp.append("// end wxGlade\n") lines = "".join(tmp) elif tag[2] == 'methods': lines = '%svoid set_properties();\n%svoid do_layout();\n' \ % (tabs(1), tabs(1)) else: lines = '// content of this block (%s) not found: ' \ 'did you rename this class?\n' % tag[2] header_content = header_content.replace(tag[0], lines) tags = re.findall('(<%swxGlade replace ([a-zA-Z_]\w*) +(\w+)>)' % nonce, source_content) for tag in tags: comment = '// content of this block not found: ' \ 'did you rename this class?\n' source_content = source_content.replace(tag[0], comment) # ALB 2004-12-08 tags = re.findall('<%swxGlade event_handlers \w+>' % nonce, header_content) for tag in tags: header_content = header_content.replace(tag, "") tags = re.findall('<%swxGlade add \w+ event_handlers>' % nonce, source_content) for tag in tags: source_content = source_content.replace(tag, "") # write the new file contents to disk common.save_file(previous_source.name + '.h', header_content, 'codegen') common.save_file(previous_source.name + '.cpp', source_content + '\n\n' + extra_source, 'codegen') elif not multiple_files: oh = os.path.basename(output_name).upper() + '_H' output_header.write('\n#endif // %s\n' % oh) # write the list of include files header_content = output_header.getvalue() source_content = output_source.getvalue() tags = re.findall('<%swxGlade replace dependencies>' % nonce, header_content) deps = [] for code in classes.itervalues(): deps.extend(code.dependencies) tmp = ["// begin wxGlade: ::dependencies\n"] for dep in _unique(deps): if dep and ('"' != dep[0] != '<'): tmp.append('#include "%s.h"\n' % dep) else: tmp.append('#include %s\n' % dep) tmp.append("// end wxGlade\n") header_content = header_content.replace( '<%swxGlade replace dependencies>' % nonce, "".join(tmp)) # extra code (see the 'extracode' property of top-level widgets) tag = '<%swxGlade replace extracode>' % nonce code = "\n".join(['// begin wxGlade: ::extracode'] + _current_extra_code_h + ['// end wxGlade\n']) header_content = header_content.replace(tag, code) code = "\n".join(['// begin wxGlade: ::extracode'] + _current_extra_code_cpp + ['// end wxGlade\n']) source_content = source_content.replace(tag, code) # -------------------------------------------------------------- common.save_file(output_name + '.h', header_content, 'codegen') common.save_file(output_name + '.cpp', source_content, 'codegen') def test_attribute(obj): """\ Returns True if 'obj' should be added as an attribute of its parent's class, False if it should be created as a local variable of __do_layout. To do so, tests for the presence of the special property 'attribute' """ try: return int(obj.properties['attribute']) except (KeyError, ValueError): return True # this is the default def add_object(top_obj, sub_obj): """\ adds the code to build 'sub_obj' to the class body of 'top_obj'. """ try: klass = classes[top_obj.klass] except KeyError: klass = classes[top_obj.klass] = ClassLines() try: builder = obj_builders[sub_obj.base] except KeyError: # no code generator found: write a comment about it klass.init.extend(['\n', '// code for %s (type %s) not generated: ' 'no suitable writer found' % (sub_obj.name, sub_obj.klass),'\n']) else: try: init, ids, props, layout = builder.get_code(sub_obj) #builder(sub_obj) except: print sub_obj raise if sub_obj.in_windows: # the object is a wxWindow instance # --- patch 2002-08-26 ------------------------------------------ if sub_obj.is_container and not sub_obj.is_toplevel: init.reverse() klass.parents_init.extend(init) else: klass.init.extend(init) # --------------------------------------------------------------- # -- ALB 2004-12-08 --------------------------------------------- if hasattr(builder, 'get_events'): klass.event_handlers.extend(builder.get_events(sub_obj)) elif 'events' in sub_obj.properties: id_name, id = generate_code_id(sub_obj) #if id == '-1': id = 'self.%s.GetId()' % sub_obj.name for event, handler in sub_obj.properties['events'].iteritems(): klass.event_handlers.append((id, event, handler)) # --------------------------------------------------------------- # try to see if there's some extra code to add to this class extra_code = getattr(builder, 'extracode', sub_obj.properties.get('extracode', "")) if extra_code: extra_code = re.sub(r'\\n', '\n', extra_code) extra_code = re.split(re.compile(r'^###\s*$', re.M), extra_code, 1) klass.extra_code_h.append(extra_code[0]) if len(extra_code) > 1: klass.extra_code_cpp.append(extra_code[1]) # if we are not overwriting existing source, warn the user # about the presence of extra code if multiple_files: warn = False else: warn = previous_source is not None if warn: common.message( 'WARNING', '%s has extra code, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ sub_obj.name) # ----------------------------------------------------------- klass.ids.extend(ids) if sub_obj.klass != 'spacer': # attribute is a special property which control whether # sub_obj must be accessible as an attribute of top_obj, # or as a local variable in the do_layout method if test_attribute(sub_obj): klass.sub_objs.append( (sub_obj.klass, sub_obj.name) ) else: # the object is a sizer # ALB 2004-09-17: workaround (hack) for static box sizers... if sub_obj.base == 'wxStaticBoxSizer': klass.sub_objs.insert(0, ('wxStaticBox', '%s_staticbox' % sub_obj.name)) klass.parents_init.insert(1, init.pop(0)) klass.sizers_init.extend(init) klass.props.extend(props) klass.layout.extend(layout) if multiple_files and \ (sub_obj.is_toplevel and sub_obj.base != sub_obj.klass): #print top_obj.name, sub_obj.name klass.dependencies.append(sub_obj.klass) else: ## headers = _obj_headers.get(sub_obj.base, []) if sub_obj.base in obj_builders: headers = getattr(obj_builders[sub_obj.base], 'extra_headers', []) klass.dependencies.extend(headers) def add_sizeritem(toplevel, sizer, obj, option, flag, border): """\ writes the code to add the object 'obj' to the sizer 'sizer' in the 'toplevel' object. """ try: klass = classes[toplevel.klass] except KeyError: klass = classes[toplevel.klass] = ClassLines() name = obj.name if obj.base == 'wxNotebook' and for_version < (2, 5): name = 'new wxNotebookSizer(%s)' % obj.name buffer = '%s->Add(%s, %s, %s, %s);\n' % \ (sizer.name, name, option, flag, border) klass.layout.append(buffer) def add_class(code_obj): """\ Generates the code for a custom class. """ if classes.has_key(code_obj.klass) and classes[code_obj.klass].done: return # the code has already been generated if not multiple_files: # in this case, previous_source is the SourceFileContent instance # that keeps info about the single file to generate prev_src = previous_source else: # let's see if the file to generate exists, and in this case # create a SourceFileContent instance filename = os.path.join(out_dir, code_obj.klass.replace('::', '_') + '.h') if _overwrite or not os.path.exists(filename): prev_src = None else: prev_src = SourceFileContent(os.path.join(out_dir, code_obj.klass)) if prev_src is not None and prev_src.classes.has_key(code_obj.klass): # this class wasn't in the previous version of the source (if any) is_new = False else: is_new = True header_buffer = [] source_buffer = [] hwrite = header_buffer.append swrite = source_buffer.append if not classes.has_key(code_obj.klass): # if the class body was empty, create an empty ClassLines classes[code_obj.klass] = ClassLines() ## # first thing to do, call the property writer: we do this here because it ## # is admissible for the property code generator to have side effects (i.e. ## # to operate on the ClassLines instance): this is actually done in the ## # toplevel menubar ## props_builder = obj_properties.get(code_obj.base) ## write_body = len(classes[code_obj.klass].props) ## if props_builder: ## obj_p = props_builder(code_obj)#obj_properties[code_obj.base](code_obj) ## if not write_body: write_body = len(obj_p) ## else: obj_p = [] try: builder = obj_builders[code_obj.base] except KeyError: print code_obj raise # this shouldn't happen # try to see if there's some extra code to add to this class extra_code = getattr(builder, 'extracode', code_obj.properties.get('extracode', "")) if extra_code: extra_code = re.sub(r'\\n', '\n', extra_code) extra_code = re.split(re.compile(r'^###\s*$', re.M), extra_code, 1) classes[code_obj.klass].extra_code_h.append(extra_code[0]) if len(extra_code) > 1: classes[code_obj.klass].extra_code_cpp.append(extra_code[1]) if not is_new: common.message('WARNING', '%s has extra code, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ code_obj.name) if not multiple_files and extra_code: _current_extra_code_h.append("".join( classes[code_obj.klass].extra_code_h[::-1])) _current_extra_code_cpp.append("".join( classes[code_obj.klass].extra_code_cpp[::-1])) #------------------------------------------------------------ default_sign = [('wxWindow*', 'parent'), ('int', 'id')] ## sign = obj_constructors.get(code_obj.base, default_sign) sign = getattr(builder, 'constructor', default_sign) defaults = [] for t in sign: if len(t) == 3: defaults.append(t[2]) else: defaults.append(None) tmp_sign = [ t[0] + ' ' + t[1] for t in sign ] sign_decl2 = ', '.join(tmp_sign) for i in range(len(tmp_sign)): if defaults[i] is not None: tmp_sign[i] += '=%s' % defaults[i] sign_decl1 = ', '.join(tmp_sign) sign_inst = ', '.join([ t[1] for t in sign]) # ALB 2004-12-08 event handling event_handlers = classes[code_obj.klass].event_handlers if hasattr(builder, 'get_events'): event_handlers.extend(builder.get_events(code_obj)) # ALB 2007-08-31 custom base classes support custom_base = getattr(code_obj, 'custom_base', code_obj.properties.get('custom_base', None)) if custom_base and not custom_base.strip(): custom_base = None if not is_new and custom_base is not None: # custom base classes set, but "overwrite existing sources" not # set. Issue a warning about this common.message('WARNING', '%s has custom base classes, but you are ' 'not overwriting existing sources: please check that ' 'the resulting code is correct!' % code_obj.name) if is_new: # header file base = code_obj.base if custom_base is not None: base = ", public ".join([b.strip() for b in custom_base.split(',')]) hwrite('\nclass %s: public %s {\n' % (code_obj.klass, base)) hwrite('public:\n') # the first thing to add it the enum of the various ids hwrite(tabs(1) + '// begin wxGlade: %s::ids\n' % code_obj.klass) ids = classes[code_obj.klass].ids # let's try to see if there are extra ids to add to the enum if hasattr(builder, 'get_ids_code'): ids.extend(builder.get_ids_code(code_obj)) if ids: hwrite(tabs(1) + 'enum {\n') ids = (',\n' + tabs(2)).join(ids) hwrite(tabs(2) + ids) hwrite('\n' + tabs(1) + '};\n') hwrite(tabs(1) + '// end wxGlade\n\n') # constructor prototype hwrite(tabs(1) + '%s(%s);\n' % (code_obj.klass, sign_decl1)) hwrite('\nprivate:\n') # set_properties and do_layout prototypes hwrite(tabs(1) + '// begin wxGlade: %s::methods\n' % code_obj.klass) hwrite(tabs(1) + 'void set_properties();\n') hwrite(tabs(1) + 'void do_layout();\n') hwrite(tabs(1) + '// end wxGlade\n') # declarations of the attributes hwrite('\n') hwrite('protected:\n') hwrite(tabs(1) + '// begin wxGlade: %s::attributes\n' % code_obj.klass) for o_type, o_name in classes[code_obj.klass].sub_objs: hwrite(tabs(1) + '%s* %s;\n' % (o_type, o_name)) hwrite(tabs(1) + '// end wxGlade\n') # ALB 2004-12-08 event handling if event_handlers: t = tabs(1) hwrite('\n' + t + 'DECLARE_EVENT_TABLE();\n') hwrite('\npublic:\n') already_there = {} for tpl in event_handlers: if len(tpl) == 4: win_id, event, handler, evt_type = tpl else: win_id, event, handler = tpl evt_type = 'wxCommandEvent' if handler not in already_there: # Sebastien JEFFROY & Steve MULLER contribution # Adding virtual attribute permits to derivate from the # class generated by wxGlade hwrite(t + 'virtual void %s(%s &event); ' '// wxGlade: \n' % (handler, evt_type)) already_there[handler] = 1 hwrite('}; // wxGlade: end class\n\n') elif prev_src is not None: hwrite(tabs(1) + '// begin wxGlade: %s::ids\n' % code_obj.klass) ids = classes[code_obj.klass].ids # let's try to see if there are extra ids to add to the enum if hasattr(builder, 'get_ids_code'): ids.extend(builder.get_ids_code(code_obj)) if ids: hwrite(tabs(1) + 'enum {\n') ids = (',\n' + tabs(2)).join(ids) hwrite(tabs(2) + ids) hwrite('\n' + tabs(1) + '};\n') hwrite(tabs(1) + '// end wxGlade\n') tag = '<%swxGlade replace %s ids>' % (nonce, code_obj.klass) if prev_src.header_content.find(tag) < 0: # no ids tag found, issue a warning and do nothing common.message("WARNING", "wxGlade ids block not found for %s," \ " ids declarations code NOT generated" % \ code_obj.name) else: prev_src.header_content = prev_src.header_content.\ replace(tag, "".join(header_buffer)) header_buffer = [ tabs(1) + '// begin wxGlade: %s::methods\n' % \ code_obj.klass, tabs(1) + 'void set_properties();\n', tabs(1) + 'void do_layout();\n', tabs(1) + '// end wxGlade\n' ] tag = '<%swxGlade replace %s methods>' % (nonce, code_obj.klass) if prev_src.header_content.find(tag) < 0: # no methods tag found, issue a warning and do nothing common.message("WARNING", "wxGlade methods block not found for %s," \ " methods declarations code NOT generated" % \ code_obj.name) else: prev_src.header_content = prev_src.header_content.\ replace(tag, "".join(header_buffer)) header_buffer = [] hwrite = header_buffer.append hwrite(tabs(1) + '// begin wxGlade: %s::attributes\n' % code_obj.klass) for o_type, o_name in classes[code_obj.klass].sub_objs: hwrite(tabs(1) + '%s* %s;\n' % (o_type, o_name)) hwrite(tabs(1) + '// end wxGlade\n') tag = '<%swxGlade replace %s attributes>' % (nonce, code_obj.klass) if prev_src.header_content.find(tag) < 0: # no attributes tag found, issue a warning and do nothing common.message("WARNING", "wxGlade attributes block " \ "not found for %s, attributes declarations code " \ "NOT generated" % code_obj.name) else: prev_src.header_content = prev_src.header_content.\ replace(tag, "".join(header_buffer)) header_buffer = [] hwrite = header_buffer.append # ALB 2004-12-08 event handling if event_handlers: already_there = prev_src.event_handlers.get(code_obj.klass, {}) t = tabs(1) for tpl in event_handlers: if len(tpl) == 4: win_id, event, handler, evt_type = tpl else: win_id, event, handler = tpl evt_type = 'wxCommandEvent' if handler not in already_there: # Sebastien JEFFROY & Steve MULLER contribution : # Adding virtual attribute permits to derivate from the # class generated by wxGlade hwrite(t + 'virtual void %s(%s &event); // wxGlade: ' '\n' % (handler, evt_type)) already_there[handler] = 1 if code_obj.klass not in prev_src.event_table_def: hwrite('\nprotected:\n') hwrite(tabs(1) + 'DECLARE_EVENT_TABLE()\n') tag = '<%swxGlade event_handlers %s>' % (nonce, code_obj.klass) if prev_src.header_content.find(tag) < 0: # no attributes tag found, issue a warning and do nothing common.message("WARNING", "wxGlade events block " \ "not found for %s, event table code NOT generated" % code_obj.name) else: prev_src.header_content = prev_src.header_content.\ replace(tag, "".join(header_buffer)) # source file # set the window's style prop = code_obj.properties style = prop.get("style", None) if style is not None: sign_inst = sign_inst.replace('style', '%s' % style) # constructor if is_new: base = "%s(%s)" % (code_obj.base, sign_inst) if custom_base: bases = [b.strip() for b in custom_base.split(',')] if bases: base = "%s(%s)" % (bases[0], sign_inst) rest = ", ".join([b + "()" for b in bases[1:]]) if rest: base += ", " + rest swrite('\n%s::%s(%s):\n%s%s\n{\n' % (code_obj.klass, code_obj.klass, sign_decl2, tabs(1), base)) ## code_obj.base, sign_inst)) swrite(tabs(1) + '// begin wxGlade: %s::%s\n' % (code_obj.klass, code_obj.klass)) tab = tabs(1) init_lines = classes[code_obj.klass].init # --- patch 2002-08-26 --------------------------------------------------- parents_init = classes[code_obj.klass].parents_init parents_init.reverse() for l in parents_init: swrite(tab + l) # ------------------------------------------------------------------------ for l in init_lines: swrite(tab + l) # now see if there are extra init lines to add if hasattr(builder, 'get_init_code'): for l in builder.get_init_code(code_obj): swrite(tab + l) swrite('\n' + tab + 'set_properties();\n') swrite(tab + 'do_layout();\n') # end tag swrite(tab + '// end wxGlade\n') if is_new: swrite('}\n\n') if prev_src is not None and not is_new: # replace the lines inside the constructor wxGlade block # with the new ones tag = '<%swxGlade replace %s %s>' % (nonce, code_obj.klass, code_obj.klass) if prev_src.source_content.find(tag) < 0: # no constructor tag found, issue a warning and do nothing common.message("WARNING", "wxGlade %s::%s block not found," \ " relative code NOT generated" % (code_obj.klass, code_obj.klass)) else: prev_src.source_content = prev_src.source_content.\ replace(tag, "".join(source_buffer)) source_buffer = [] swrite = source_buffer.append # ALB 2004-12-08 event handling code if event_handlers: # 1) event table declaration/definition... if prev_src is not None and \ code_obj.klass in prev_src.event_table_decl: has_event_table = True else: has_event_table = False if is_new or not has_event_table: swrite('\nBEGIN_EVENT_TABLE(%s, %s)\n' % \ (code_obj.klass, code_obj.base)) swrite(tab + '// begin wxGlade: %s::event_table\n' % code_obj.klass) for tpl in event_handlers: win_id, event, handler = tpl[:3] swrite(tab + '%s(%s, %s::%s)\n' % \ (event, win_id, code_obj.klass, handler)) swrite(tab + '// end wxGlade\n') if is_new or not has_event_table: swrite('END_EVENT_TABLE();\n') if prev_src is not None and not is_new: tag = '<%swxGlade replace %s event_table>' % (nonce, code_obj.klass) if prev_src.source_content.find(tag) < 0: # no constructor tag found, issue a warning and do nothing common.message("WARNING", "wxGlade %s::event_table block " \ "not found, relative code NOT generated" % \ (code_obj.klass)) else: prev_src.source_content = prev_src.source_content.\ replace(tag, "".join(source_buffer)) source_buffer = [] swrite = source_buffer.append # 2) event handler stubs... if prev_src is not None: already_there = prev_src.event_handlers.get(code_obj.klass, {}) else: already_there = {} for tpl in event_handlers: if len(tpl) == 4: win_id, event, handler, evt_type = tpl else: win_id, event, handler = tpl evt_type = 'wxCommandEvent' if handler not in already_there: swrite('\n\nvoid %s::%s(%s &event)\n{\n' % \ (code_obj.klass, handler, evt_type)) swrite(tab + 'event.Skip();\n') swrite(tab + 'wxLogDebug(wxT("Event handler (%s::%s) not ' 'implemented yet")); //notify the user ' 'that he hasn\'t implemented the event handler yet\n' % \ (code_obj.klass, handler)) swrite('}\n') already_there[handler] = 1 if is_new or prev_src is None: swrite('\n\n') swrite('// wxGlade: add %s event handlers\n' % code_obj.klass) if is_new or prev_src is None: swrite('\n') if prev_src is not None and not is_new: tag = '<%swxGlade add %s event handlers>' % \ (nonce, code_obj.klass) if prev_src.source_content.find(tag) < 0: # no constructor tag found, issue a warning and do nothing common.message("WARNING", "wxGlade %s event handlers " \ "marker not found, relative code NOT generated" \ % (code_obj.klass)) else: prev_src.source_content = prev_src.source_content.\ replace(tag, "".join(source_buffer)) source_buffer = [] swrite = source_buffer.append # set_properties ## props_builder = obj_properties.get(code_obj.base) ## #write_body = len(classes[code_obj.klass].props) ## if props_builder: ## obj_p = props_builder(code_obj)#obj_properties[code_obj.base](code_obj) ## #if not write_body: write_body = len(obj_p) ## else: obj_p = [] if hasattr(builder, 'get_properties_code'): obj_p = builder.get_properties_code(code_obj) else: obj_p = generate_common_properties(code_obj) # set_properties if is_new: swrite('\nvoid %s::set_properties()\n{\n' % code_obj.klass) swrite(tab + '// begin wxGlade: %s::set_properties\n' % code_obj.klass) for l in obj_p: swrite(tab + l) for l in classes[code_obj.klass].props: swrite(tab + l) swrite(tab + '// end wxGlade\n') if is_new: swrite('}\n\n') if prev_src is not None and not is_new: # replace the lines inside the constructor wxGlade block # with the new ones tag = '<%swxGlade replace %s set_properties>' % (nonce, code_obj.klass) if prev_src.source_content.find(tag) < 0: # no set_properties tag found, issue a warning and do nothing common.message("WARNING", "wxGlade %s::set_properties block "\ "not found, relative code NOT generated" % \ (code_obj.klass)) else: prev_src.source_content = prev_src.source_content.\ replace(tag, "".join(source_buffer)) source_buffer = [] swrite = source_buffer.append # do_layout if is_new: swrite('\nvoid %s::do_layout()\n{\n' % code_obj.klass) layout_lines = classes[code_obj.klass].layout sizers_init_lines = classes[code_obj.klass].sizers_init swrite(tab + '// begin wxGlade: %s::do_layout\n' % code_obj.klass) sizers_init_lines.reverse() for l in sizers_init_lines: swrite(tab + l) for l in layout_lines: swrite(tab + l) #if sizers_init_lines or layout_lines: swrite(tab + 'Layout();\n') # now, check if there are extra layout lines to add if hasattr(builder, 'get_layout_code'): for l in builder.get_layout_code(code_obj): swrite(tab + l) swrite(tab + '// end wxGlade\n') if is_new: swrite('}\n\n') if prev_src is not None and not is_new: # replace the lines inside the constructor wxGlade block # with the new ones tag = '<%swxGlade replace %s do_layout>' % (nonce, code_obj.klass) if prev_src.source_content.find(tag) < 0: # no do_layout tag found, issue a warning and do nothing common.message("WARNING", "wxGlade %s::do_layout block "\ "not found, relative code NOT generated" % (code_obj.klass)) else: prev_src.source_content = prev_src.source_content.\ replace(tag, "".join(source_buffer)) source_buffer = [] swrite = source_buffer.append # the code has been generated classes[code_obj.klass].done = True if not multiple_files and prev_src is not None: # if this is a new class, add its code to the new_classes list of the # SourceFileContent instance if is_new: prev_src.new_classes.append( ("".join(header_buffer), "".join(source_buffer)) ) return if multiple_files: if code_obj.base in obj_builders: classes[code_obj.klass].dependencies.extend( getattr(obj_builders[code_obj.base], 'extra_headers', [])) if prev_src is not None: tag = '<%swxGlade insert new_classes>' % nonce prev_src.header_content = prev_src.header_content.replace(tag, "") # insert the module dependencies of this class extra_modules = classes[code_obj.klass].dependencies #print 'extra_modules:', extra_modules, code_obj.base deps = ['// begin wxGlade: ::dependencies\n'] for module in _unique(extra_modules): if module and ('"' != module[0] != '<'): deps.append('#include "%s.h"\n' % module) else: deps.append('#include %s\n' % module) deps.append('// end wxGlade\n') # WARNING: there's a double space ' ' between 'replace' and # 'dependencies' in the tag below, because there is no class name # (see SourceFileContent, line ~147) tag = '<%swxGlade replace dependencies>' % nonce prev_src.header_content = prev_src.header_content.\ replace(tag, "".join(deps)) # insert the extra code of this class extra_code_h = "".join(classes[code_obj.klass].extra_code_h[::-1]) extra_code_cpp = \ "".join(classes[code_obj.klass].extra_code_cpp[::-1]) # if there's extra code but we are not overwriting existing # sources, warn the user if extra_code_h or extra_code_cpp: common.message('WARNING', '%s (or one of its chilren) has ' 'extra code classes, but you are ' 'not overwriting existing sources: please check ' 'that the resulting code is correct!' % \ code_obj.name) extra_code_h = '// begin wxGlade: ::extracode\n%s\n' \ '// end wxGlade\n' % extra_code_h extra_code_cpp = '// begin wxGlade: ::extracode\n%s\n' \ '// end wxGlade\n' % extra_code_cpp tag = '<%swxGlade replace extracode>' % nonce prev_src.header_content = prev_src.header_content.replace( tag, extra_code_h) prev_src.source_content = prev_src.source_content.replace( tag, extra_code_cpp) # store the new file contents to disk name = os.path.join(out_dir, code_obj.klass) common.save_file(name + '.h', prev_src.header_content, 'codegen') common.save_file(name + '.cpp', prev_src.source_content, 'codegen') return # create the new source file header_file = os.path.join(out_dir, code_obj.klass + '.h') source_file = os.path.join(out_dir, code_obj.klass + '.cpp') hout = cStringIO.StringIO() sout = cStringIO.StringIO() # header file hwrite = hout.write # write the common lines for line in header_lines: hwrite(line) # isolation directives hn = os.path.basename(header_file).upper().replace('.', '_') hwrite('\n#ifndef %s\n#define %s\n' % (hn, hn)) # write the module dependecies for this class #extra_headers = classes[code_obj.klass].dependencies hwrite('\n// begin wxGlade: ::dependencies\n') extra_modules = classes[code_obj.klass].dependencies for module in _unique(extra_modules): if module and ('"' != module[0] != '<'): hwrite('#include "%s.h"\n' % module) else: hwrite('#include %s\n' % module) hwrite('// end wxGlade\n') hwrite('\n') # insert the extra code of this class extra_code_h = "".join(classes[code_obj.klass].extra_code_h[::-1]) extra_code_h = '// begin wxGlade: ::extracode\n%s\n// end wxGlade\n' % \ extra_code_h hwrite(extra_code_h) hwrite('\n') # write the class body for line in header_buffer: hwrite(line) hwrite('\n#endif // %s\n' % hn) # source file swrite = sout.write # write the common lines #for line in header_lines: swrite(line) swrite(header_lines[0]) swrite('#include "%s"\n\n' % os.path.basename(header_file)) # insert the extra code of this class extra_code_cpp = "".join(classes[code_obj.klass].extra_code_cpp[::-1]) extra_code_cpp = '// begin wxGlade: ::extracode\n%s\n' \ '// end wxGlade\n' % extra_code_cpp swrite(extra_code_cpp) swrite('\n') # write the class implementation for line in source_buffer: swrite(line) # store source to disk common.save_file(header_file, hout.getvalue(), 'codegen') common.save_file(source_file, sout.getvalue(), 'codegen') hout.close() sout.close() else: # not multiple_files # write the class body onto the single source file hwrite = output_header.write for line in header_buffer: hwrite(line) swrite = output_source.write for line in source_buffer: swrite(line) # extra code if classes[code_obj.klass].extra_code_h: _current_extra_code_h.extend( classes[code_obj.klass].extra_code_h[::-1]) if classes[code_obj.klass].extra_code_cpp: _current_extra_code_cpp.extend( classes[code_obj.klass].extra_code_h[::-1]) def add_app(app_attrs, top_win_class): """\ Generates the code for a wxApp instance. if the 'class' property has no value, the function does nothing """ if not multiple_files: prev_src = previous_source else: filename = os.path.join(out_dir, 'main.cpp') if not os.path.exists(filename): prev_src = None elif _overwrite: prev_src = None else: # prev_src doesn't need to be a SourceFileContent instance in this # case, as we do nothing if it is not None prev_src = 1 if prev_src is not None: return # do nothing if the file existed klass = app_attrs.get('class') top_win = app_attrs.get('top_window') if not klass or not top_win: return # do nothing in these cases lines = [] append = lines.append tab = tabs(1) append('\n\nclass %s: public wxApp {\n' % klass) append('public:\n') append(tab + 'bool OnInit();\n') append('};\n\n') append('IMPLEMENT_APP(%s)\n\n' % klass) append('bool %s::OnInit()\n{\n' % klass) append(tab + 'wxInitAllImageHandlers();\n') # we add this to avoid troubles append(tab + '%s* %s = new %s(NULL, wxID_ANY, wxEmptyString);\n' % \ (top_win_class, top_win, top_win_class)) append(tab + 'SetTopWindow(%s);\n' % top_win) append(tab + '%s->Show();\n' % top_win) append(tab + 'return true;\n}\n') if multiple_files: filename = os.path.join(out_dir, 'main.cpp') out = cStringIO.StringIO() write = out.write # write the common lines for line in header_lines: write(line) # import the top window module write('#include "%s.h"\n\n' % top_win_class) # write the wxApp code for line in lines: write(line) common.save_file(filename, out.getvalue(), 'codegen') else: write = output_source.write for line in lines: write(line) def generate_code_size(obj): """\ returns the code fragment that sets the size of the given object. """ if obj.is_toplevel: name1 = ''; name2 = 'this' else: name1 = '%s->' % obj.name; name2 = obj.name size = obj.properties.get('size', '').strip() use_dialog_units = (size[-1] == 'd') if for_version < (2, 5) or obj.parent is None: method = 'SetSize' else: method = 'SetMinSize' if use_dialog_units: return name1 + method + '(wxDLG_UNIT(%s, wxSize(%s)));\n' % \ (name2, size[:-1]) else: return name1 + method + '(wxSize(%s));\n' % size def _string_to_colour(s): return '%d, %d, %d' % (int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16)) def generate_code_foreground(obj): """\ returns the code fragment that sets the foreground colour of the given object. """ if not obj.is_toplevel: intro = '%s->' % obj.name else: intro = '' try: color = 'wxColour(%s)' % \ _string_to_colour(obj.properties['foreground']) except (IndexError, ValueError): # the color is from system settings color = 'wxSystemSettings::GetColour(%s)' % \ obj.properties['foreground'] return intro + 'SetForegroundColour(%s);\n' % color def generate_code_background(obj): """\ returns the code fragment that sets the background colour of the given object. """ if not obj.is_toplevel: intro = '%s->' % obj.name else: intro = '' try: color = 'wxColour(%s)' % \ _string_to_colour(obj.properties['background']) except (IndexError, ValueError): # the color is from system settings color = 'wxSystemSettings::GetColour(%s)' % \ obj.properties['background'] return intro + 'SetBackgroundColour(%s);\n' % color def generate_code_font(obj): """\ returns the code fragment that sets the font the given object. """ font = obj.properties['font'] size = font['size']; family = font['family'] underlined = font['underlined'] style = font['style']; weight = font['weight'] face = '"%s"' % font['face'].replace('"', r'\"') if obj.is_toplevel: intro = '' else: intro = '%s->' % obj.name return intro + 'SetFont(wxFont(%s, %s, %s, %s, %s, wxT(%s)));\n' % \ (size, family, style, weight, underlined, face) _last_generated_id = 1000 def generate_code_id(obj, id=None): """\ returns a 2-tuple of strings representing the LOC that sets the id of the given object: the first line is the declaration of the variable, and is empty if the object's id is a constant, and the second line is the value of the id """ global _last_generated_id if id is None: id = obj.properties.get('id') if not id: return '', 'wxID_ANY' tokens = id.split('=') if len(tokens) > 1: name, val = tokens[:2] else: return '', tokens[0] # we assume name is declared elsewhere if not name: return '', val if val.strip() == '?': val = 'wxID_HIGHEST + ' + str(_last_generated_id) _last_generated_id += 1 return '%s = %s' % (name, val), name def generate_code_tooltip(obj): """\ returns the code fragment that sets the tooltip of the given object. """ if not obj.is_toplevel: intro = '%s->' % obj.name else: intro = '' return intro + 'SetToolTip(%s);\n' % quote_str(obj.properties['tooltip']) def _get_code_name(obj): if not obj.is_toplevel: return '%s->' % obj.name else: return '' def generate_code_disabled(obj): self = _get_code_name(obj) try: disabled = int(obj.properties['disabled']) except: disabled = False if disabled: return self + 'Enable(false);\n' def generate_code_focused(obj): self = _get_code_name(obj) try: focused = int(obj.properties['focused']) except: focused = False if focused: return self + 'SetFocus();\n' def generate_code_hidden(obj): self = _get_code_name(obj) try: hidden = int(obj.properties['hidden']) except: hidden = False if hidden: return self + 'Hide();\n' def generate_code_extraproperties(obj): self = _get_code_name(obj) prop = obj.properties['extraproperties'] ret = [] for name in sorted(prop): ret.append(self + 'Set%s(%s);\n' % (name, prop[name])) return ret def generate_common_properties(widget): """\ generates the code for various properties common to all widgets (background and foreground colors, font, ...) Returns a list of strings containing the generated code """ prop = widget.properties out = [] if prop.get('size', '').strip(): out.append(generate_code_size(widget)) if prop.get('background'): out.append(generate_code_background(widget)) if prop.get('foreground'): out.append(generate_code_foreground(widget)) if prop.get('font'): out.append(generate_code_font(widget)) if prop.get('tooltip'): out.append(generate_code_tooltip(widget)) # trivial boolean properties if prop.get('disabled'): out.append(generate_code_disabled(widget)) if prop.get('focused'): out.append(generate_code_focused(widget)) if prop.get('hidden'): out.append(generate_code_hidden(widget)) # ALB 2007-09-01 extra properties if prop.get('extraproperties') and not widget.preview: out.extend(generate_code_extraproperties(widget)) return out # custom property handlers class FontPropertyHandler: """Handler for font properties""" font_families = { 'default': 'wxDEFAULT', 'decorative': 'wxDECORATIVE', 'roman': 'wxROMAN', 'swiss': 'wxSWISS', 'script': 'wxSCRIPT', 'modern': 'wxMODERN', 'teletype': 'wxTELETYPE' } font_styles = { 'normal': 'wxNORMAL', 'slant': 'wxSLANT', 'italic': 'wxITALIC' } font_weights = { 'normal': 'wxNORMAL', 'light': 'wxLIGHT', 'bold': 'wxBOLD' } def __init__(self): self.dicts = { 'family': self.font_families, 'style': self.font_styles, 'weight': self.font_weights } self.attrs = { 'size': '0', 'style': '0', 'weight': '0', 'family': '0', 'underlined': '0', 'face': '' } self.current = None self.curr_data = [] def start_elem(self, name, attrs): self.curr_data = [] if name != 'font' and name in self.attrs: self.current = name else: self.current = None def end_elem(self, name, code_obj): if name == 'font': code_obj.properties['font'] = self.attrs return True elif self.current is not None: decode = self.dicts.get(self.current) if decode: val = decode.get("".join(self.curr_data), '0') else: val = "".join(self.curr_data) self.attrs[self.current] = val def char_data(self, data): self.curr_data.append(data) # end of class FontPropertyHandler class DummyPropertyHandler: """Empty handler for properties that do not need code""" def start_elem(self, name, attrs): pass def end_elem(self, name, code_obj): return True def char_data(self, data): pass # end of class DummyPropertyHandler class EventsPropertyHandler(object): def __init__(self): self.handlers = {} self.event_name = None self.curr_handler = [] def start_elem(self, name, attrs): if name == 'handler': self.event_name = attrs['event'] def end_elem(self, name, code_obj): if name == 'handler': if self.event_name and self.curr_handler: self.handlers[self.event_name] = ''.join(self.curr_handler) self.event_name = None self.curr_handler = [] elif name == 'events': code_obj.properties['events'] = self.handlers return True def char_data(self, data): data = data.strip() if data: self.curr_handler.append(data) # end of class EventsPropertyHandler class ExtraPropertiesPropertyHandler(object): def __init__(self): self.props = {} self.prop_name = None self.curr_prop = [] def start_elem(self, name, attrs): if name == 'property': name = attrs['name'] if name and name[0].islower(): name = name[0].upper() + name[1:] self.prop_name = name def end_elem(self, name, code_obj): if name == 'property': if self.prop_name and self.curr_prop: self.props[self.prop_name] = ''.join(self.curr_prop) self.prop_name = None self.curr_prop = [] elif name == 'extraproperties': code_obj.properties['extraproperties'] = self.props return True # to remove this handler def char_data(self, data): data = data.strip() if data: self.curr_prop.append(data) # end of class ExtraPropertiesPropertyHandler # dictionary whose items are custom handlers for widget properties _global_property_writers = { 'font': FontPropertyHandler, 'events': EventsPropertyHandler, 'extraproperties': ExtraPropertiesPropertyHandler, } # dictionary of dictionaries of property handlers specific for a widget # the keys are the class names of the widgets # Ex: _property_writers['wxRadioBox'] = {'choices', choices_handler} _property_writers = {} # dictionary of additional headers for objects _obj_headers = {} def get_property_handler(property_name, widget_name): try: cls = _property_writers[widget_name][property_name] except KeyError: cls = _global_property_writers.get(property_name, None) if cls: return cls() return None def add_property_handler(property_name, handler, widget_name=None): """\ sets a function to parse a portion of XML to get the value of the property property_name. If widget_name is not None, the function is called only if the property in inside a widget whose class is widget_name """ if widget_name is None: _global_property_writers[property_name] = handler else: try: _property_writers[widget_name][property_name] = handler except KeyError: _property_writers[widget_name] = { property_name: handler } class WidgetHandler: """\ Interface the various code generators for the widgets must implement """ """``signature'' of the widget's constructor""" constructor = [] """ if not None, list of extra header file, in the form or "header.h" """ extra_headers = [] def get_code(self, obj): """\ Handler for normal widgets (non-toplevel): returns 4 lists of strings, init, ids, properties and layout, that contain the code for the corresponding parts/methods of the class to generate """ return [], [], [], [] def get_properties_code(self, obj): """\ Handler for the code of the set_properties method of toplevel objects. Returns a list of strings containing the code to generate """ return [] def get_init_code(self, obj): """\ Handler for the code of the constructor of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add). The generated lines are appended at the end of the constructor """ return [] def get_ids_code(self, obj): """\ Handler for the code of the ids enum of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add) """ return [] def get_layout_code(self, obj): """\ Handler for the code of the do_layout method of toplevel objects. Returns a list of strings containing the code to generate. Usually the default implementation is ok (i.e. there are no extra lines to add) """ return [] # end of class WidgetHandler def add_widget_handler(widget_name, handler): obj_builders[widget_name] = handler def _unique(sequence): """\ Strips all duplicates from sequence. Works only if items of sequence are hashable """ tmp = {} for item in sequence: tmp[item] = 1 return tmp.keys() def get_events_with_type(obj, evt_type): """\ Returns the list of event handlers defined for `obj', setting the type of the argument of the handlers (i.e. the event parameter) to `evt_type' """ ret = [] if 'events' not in obj.properties: return ret id_name, id = generate_code_id(obj) for event, handler in obj.properties['events'].iteritems(): ret.append((id, event, handler, evt_type)) return ret spe-0.8.4.h/_spe/plugins/kiki/history.txt0000644000175000017500000000235110272471120017353 0ustar stanistaniKIKI 0.5.6 - regexes made nifty Copyright (C) 2003, 2004 Project 5 (http://come.to/project5) Licence: GPL (free) Requires: Python, wxPython System: any, provided (wx)Python runs on it History ======= 0.5.6 (8-4-2004, 32.5 kB) - changed code to support wxPython 2.5.1.5 - saves settings before evaluating the regex 0.5.5 (29-9-2003, 32.5kB) - fixed bug which caused the selected regex to disappear to the history when Evalute was activated - fixed Linux bug which caused warning messages to be displayed when a different doc was selected in the Help tab - small changes in code and docs - first public release outside Spe 0.5 (28-9-2003, 32.8kB) = added really nifty colors = added docs and about screen = added ferrety Easter Egg :) = added __init__.py so that Kiki can be used as package in Spe - fixed bug that meant flags were actually not used when compiling the regex - locale used to be after multiline - restored alphabetical order 0.2 (26-9-2003, 25.7kB) - fixed a bug with caused empty regex results to lead to an infinite loop = added pretty icons :) - added support for integration in Spe - misc changes 0.1: - first version, only available in Spe 0.1.8.a spe-0.8.4.h/_spe/plugins/kiki/__init__.py0000644000175000017500000000000010272471120017207 0ustar stanistanispe-0.8.4.h/_spe/plugins/kiki/kiki.ico0000644000175000017500000002635610272471120016547 0ustar stanistanih6  00F( @a`b~ttp840\`Zrqqdcb000|ur65Gʊ21Kȍa`a`ba000VR|SSc#$!0/1 hdZ`NTm&120%%(666{<8SJEe999,+\a]!c``VVV)* ̺*)*e\Pw1>4445KRS" G7mcdg\:ĤFSH`efppp|HEHZPĥAfY%ľK=' ^\\?NNMKKaRͪFn[*s{pno~~IA9;) e\QX[^"&"jklUVVfgeWYXSQVGJKfggdpo GGGttt&43FFFppp( @ +03MSRDEA   }~tqi svg)18 ! @@L594  TWvΑA>kMSNkod/0'cYY+':*&O¿ꟙ깳~t{QQK!200㭦寪he~ ,3&_]]kgm  gal6♘蓓峫 -eftSSS&>>AAA2ԣ옞ކͩD, ruLeg  ª3&ɨ;J61x&/*3-$'XVV%#"Ǭ4Ƥ,˨:M>5 !%*58= 4NN ,, {%Դ[ЫYTKW[0-/ !+_G^A@*?63pzzENA%$&ù 'EJ]_"0-,)   , 6 ; 6 " 0@A<@? -(Ar'F%K&L}&@q)T (,,DST "8.I@K H&E.D#7i ";   g}} +3G|%C#H$G#C%C)J#I|E  3GG&2Y4K&E'E!AABI0H!4[%  !&:f+G(E#A&F$F"F%F,K,H{>NY\9+G(E+H*G+F,G%IF#D1E#@... ";#E)K%G%F#D'G'G$D)I#B)[ ]^] $P5L(H#H$H&F%E$D)I*J%C})D {|{%% &O,G E!E(I(H&F'G'G(I&G'I /CA .W+I%F%F&F(H&F$D"C"C/H}; pppE[Y%"Hb_|w_}5RN1Y,F&E#C'G(H%E(F+D-I!;q.###vJ\Yz$.A A+>x,G#F"H%G-I4E%B,K#9k *77 3+@v!EG F-I,E)F+G2F!@ SV[ h}c)H)D!A&G'F#D"F#C/G%<]  "& wFYM  0Bx*B*G"DCE$F%=~,F  NYW xWg\&1Q2E)F%G%G!G&D#Y%'  RfbKij'./FHM 0V.K A'G(_'S `ab!!-38pno  0W%F%C%F #L&=# DEF?LK|?ML /Z(C(ESQ62-    (00+?=j2.. =966BB"!=RO# hleRY`AFWMM^dgc*,)Odb >:VUNsPLjɯ]]bBBB ,1/ NOY"#*mmm000_=>@ᥨB:(%$$///j YZVڷ읝---Z[_E6v/~l3DDE666   NLB@;2RKN~ijgQͨ?;fgh=<<&250'+ R?;eM!vVI)~i2aR'A9;BVXTSU (¢7B_]>ƿVK< gdj򌌌-%(KWXihh ~*ʨ?K\U;w~QVYa\]1GEB< Kiki 1 640, 480 wxHORIZONTAL wxEXPAND 0 wxSPLIT_HORIZONTAL 120 BottomPane TopPane 0 5 1 3 0 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 1 0 2 0 wxEXPAND 0 0 0 1 ID_EVALUATE wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 1 2 0 wxEXPAND 0 0 1 Find all returns all matches, find first only the first one Find all Find first 0 wxHORIZONTAL wxEXPAND 0 15 4 3 7 wxEXPAND 0 2 7 wxEXPAND 0 2 7 wxEXPAND 0 2 7 0 Perform case-insensitive matching\nExpressions like [A-Z] will match lowercase letters too. This is not affected by the current locale. 0 Make \w, \W, \\b, and \B dependent on the current locale. 0 When specified, the pattern characters "^" and "$" match at the beginning respectively end of the string and at the beginning respectively end of each line (immediately following respectively preceding each newline).\nOtherwise "^" matches only at the beginning of the string, and "$" only at the end of the string and immediately before the newline (if any) at the end of the string. 0 Make the "." special character match any character at all, including a newline. Without this flag, "." will match anything except a newline. 0 Make \w, \W, \\b, and \B dependent on the Unicode character properties database. 0 This flag allows you to write regular expressions that look nicer.\nWhitespace within the pattern is ignored, except when in a character class or preceded by an unescaped backslash, and, when a line contains a "#" neither in a character class or preceded by an unescaped backslash, all characters from the leftmost such "#" through the end of the line are ignored. wxEXPAND 0 2 7 wxEXPAND 0 2 7 wxEXPAND 0 2 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 wxEXPAND 0 7 7 623, 324 wxHORIZONTAL wxEXPAND 0 Matches Sample text Help ID_NOTEBOOK wxHORIZONTAL wxEXPAND 0 $parent $id wxHORIZONTAL wxEXPAND 0 7 2 3 0 1 7 wxEXPAND 0 1 1 wxEXPAND 0 0 Working with Kiki Re - syntax Re - special characters: |, (, +, etc. Re - extensions, groups and lookahead/lookbehind: (?...) Re - special sequences: \... Re - flags About Kiki ID_HELPCOMBOBOX wxEXPAND 0 $parent $id spe-0.8.4.h/_spe/plugins/kiki/kiki.py0000644000175000017500000010137410763606567016443 0ustar stanistani"""Kiki 0.5.6 - A Free Environment for Regular Expression Testing (ferret) Copyright (C) 2003, 2004 Project 5 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Contact info web: http://come.to/project5 mail/msn: project5@wanadoo.nl icq: 84243714 """ import wx import wx.html __version__ = "0.5.6" import re, os, os.path, cgi, sys # string constants WINDOWSIZE = "MainWindowSize" WINDOWPOSITION = "MainWindowPosition" SASHPOSITION = "SashPosition" SEARCHTYPE = "SearchType" MATCHINDEX = "MatchIndex" MATCHTEMPLATE = "MatchTemplate" FORMATTEDMATCH = "FormattedMatch" STARTTEMPLATE = "StartTemplate" ENDTEMPLATE = "EndTemplate" GROUPCOLOR = "GroupColor" GROUPNUMBER = "GroupNumber" SAMPLETEXT = "SampleText" REGEX = "Regex" RESULTS_SHOWMATCHES = "ShowMatchesGroups" RESULTS_SHOWNAMEDGROUPS = "ShowNamedGroups" RESULTS_SHOWSAMPLE = "ShowSampleTextInResults" # flags below are used in settings and in eval() function, so do NOT change! FLAGIGNORE = "re.IGNORECASE" FLAGMULTILINE = "re.MULTILINE" FLAGLOCALE = "re.LOCALE" FLAGDOTALL = "re.DOTALL" FLAGUNICODE = "re.UNICODE" FLAGVERBOSE = "re.VERBOSE" # constants required by the GUI ni = wx.NewId ID_EVALUATE = ni() ID_NOTEBOOK = ni() ID_HELPCOMBOBOX = ni() # global variable settings = None # templates t_error = """Error:
    %s
""" t_nomatch = """No match found""" # colors used to highlight matches colors = ["0000AA" , "00AA00" , "FFAA55" , "AA0000" , "00AAAA" , "AA00AA" , "AAAAAA" , "0000FF" , "00FF00" , "00FFFF" , "FF0000" , "DDDD00" , "FF00FF" , "AAAAFF" , "FF55AA" , "AAFF55" , "FFAAAA" , "55AAFF" , "FFAAFF" , "000077" , "007700" , "770000" , "007777" , "770077" , "777700" ] class Settings(object): """Stores and retrieves settings to a file as Python data structures which are eval()-ed. This is not by definition safe, but since the user has access to source code anyway and hence the ability to screw up anything, the danger seems quite limited.""" def __init__(self, savedir=None, dirname="", filename="settings.py", debugfile=""): """Initializes the object Arguments: savedir -- directory where to store data For more info, see the docs of Settings.setSaveDir() dirname -- if savedir=None, dirname is used to determine which subdirectory of $HOME data is stored it. filename -- name of file containing stored data debugfile -- used to allow the user to manually override the default storage dir. Mor info in the docs of Settings.setSaveDir() """ self.__setSaveDir(savedir, dirname, debugfile) self.savefilename = filename self.__load() def shutdown(self): """Must be called before the program ends.""" self.save() def __setSaveDir(self, savedir=None, dirname="", debugfile=""): """Sets self.savedir Arguments: savedir -- directory where to store data if savedir==None, $HOME/dirname is used. If necessary, the directory is created. dirname -- if savedir==None, dirname determines which subdirectory of the home dir data is stored in debugfile -- this file may be a filename which is imported and may contain a variable called savedir If the debugfile is specified, imported successfully and savedir exists, it is used to override any other parameters. This allows users to override the directory, bypassing the application which needs the settings. In some Windows installations (seems to be mainly a Win2k problem), $HOME points to the root directory. In this case, this function will try to use $USERPROFILE/dirname instead. Overriding this default behaviour is possible by supplying the savedir variable in pearsdebug.py.""" if savedir==None: try: # try to override using debugfile if present and contains savedir debugmodule = __import__(debugfile, globals()) savedir = debugmodule.savedir except: # if no override, then perform default actions if savedir == None: # use $HOME/dirname savedir = os.path.expanduser(os.path.join('~',dirname)) if len(savedir)<=len("c:\\/"+dirname): # sometimes $HOME points to root # if this is the case, try using $USERPROFILE (see docstring) temp = os.path.join(os.path.expandvars('$USERPROFILE'), dirname) # if this is a different location, use it! if temp > len("C:\\/"+dirname): savedir = temp # create dir if it doesn't exist if not os.path.exists(savedir): os.makedirs(savedir) self.savedir = savedir def __load(self): """Loads the settings from a file. These settings are saved in Python code format which is eval()-ed, so it's not trustworthy.""" try: settingsfile = file(os.path.join(self.savedir, self.savefilename), "r") self.settings = eval(settingsfile.read()) settingsfile.close() except: # if file doesn't exist self.settings= {} def save(self): """Saves the settings to a file.""" settingsfile = file(os.path.join(self.savedir, self.savefilename), "w") settingsfile.write(str(self.settings)) settingsfile.close() def set(self, settingname, value): """Changes the value of a setting with settingname to value.""" self.settings[settingname] = value def get(self, settingname, defaultval=None): """Returns the setting with settingname if present, otherwise returns defaultval and saves settingname with defaultval.""" if self.settings.has_key(settingname): return self.settings[settingname] else: self.set(settingname, defaultval) return defaultval class MyHtmlWindow(wx.html.HtmlWindow): """Adds OnLinkClicked""" def __init__(self, parent, id): wx.html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE) def OnLinkClicked(self, linkinfo): # there's a problem in KDE: the browser is not recognized properly # circumvent this problem import os if os.environ.has_key("BROWSER") and \ os.environ["BROWSER"]=='kfmclient openProfile webbrowsing': print "Invalid browser detected : %s\nResetting to konqueror." % os.environ["BROWSER"] os.environ["BROWSER"] = 'konqueror' # set it to konqueror import webbrowser # MUST be imported only AFTER os.environ has been modified webbrowser.open(linkinfo.GetHref(), 1) class MyFrame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.SplitterWindow = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_LIVE_UPDATE) self.BottomPane = wx.Panel(self.SplitterWindow, -1) self.Notebook = wx.Notebook(self.BottomPane, ID_NOTEBOOK, style=0) self.HelpPane = wx.Panel(self.Notebook, -1) self.SampleTextPane = wx.Panel(self.Notebook, -1) self.MatchesPane = wx.Panel(self.Notebook, -1, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL) self.TopPane = wx.Panel(self.SplitterWindow, -1, style=wx.RAISED_BORDER|wx.TAB_TRAVERSAL) self.RegexBox = wx.ComboBox(self.TopPane, -1, choices=["", "", "", "", "", "", ""], style=wx.CB_DROPDOWN) self.EvaluateButton = wx.Button(self.TopPane, ID_EVALUATE, "Evaluate") self.MethodBox = wx.RadioBox(self.TopPane, -1, "Methods", choices=["Find all", "Find first"], majorDimension=1, style=wx.RA_SPECIFY_COLS) self.IgnoreCheckBox = wx.CheckBox(self.TopPane, -1, "IGNORECASE (I)") self.LocaleCheckBox = wx.CheckBox(self.TopPane, -1, "LOCALE (L)") self.MultilineCheckBox = wx.CheckBox(self.TopPane, -1, "MULTILINE (M)") self.DotAllCheckBox = wx.CheckBox(self.TopPane, -1, "DOTALL (S)") self.UnicodeCheckBox = wx.CheckBox(self.TopPane, -1, "UNICODE (U)") self.VerboseCheckBox = wx.CheckBox(self.TopPane, -1, "VERBOSE (X)") self.MatchesWindow = wx.html.HtmlWindow(self.MatchesPane, -1) self.SampleText = wx.TextCtrl(self.SampleTextPane, -1, "", style=wx.TE_PROCESS_TAB|wx.TE_MULTILINE|wx.TE_RICH) self.HelpSelection = wx.ComboBox(self.HelpPane, ID_HELPCOMBOBOX, choices=["Working with Kiki", "Re - syntax", "Re - special characters: |, (, +, etc.", "Re - extensions, groups and lookahead/lookbehind: (?...)", "Re - special sequences: \...", "Re - flags", "About Kiki"], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.HelpWindow = MyHtmlWindow(self.HelpPane, -1) self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: MyFrame.__set_properties self.SetTitle("Kiki") self.SetSize((640, 480)) self.RegexBox.SetSelection(0) self.EvaluateButton.SetDefault() self.MethodBox.SetToolTipString("Find all returns all matches, find first only the first one") self.MethodBox.SetSelection(0) self.IgnoreCheckBox.SetToolTipString("Perform case-insensitive matching\nExpressions like [A-Z] will match lowercase letters too. This is not affected by the current locale.") self.LocaleCheckBox.SetToolTipString("Make \w, \W, \\b, and \B dependent on the current locale.") self.MultilineCheckBox.SetToolTipString("When specified, the pattern characters \"^\" and \"$\" match at the beginning respectively end of the string and at the beginning respectively end of each line (immediately following respectively preceding each newline).\nOtherwise \"^\" matches only at the beginning of the string, and \"$\" only at the end of the string and immediately before the newline (if any) at the end of the string.") self.DotAllCheckBox.SetToolTipString("Make the \".\" special character match any character at all, including a newline. Without this flag, \".\" will match anything except a newline.") self.UnicodeCheckBox.SetToolTipString("Make \w, \W, \\b, and \B dependent on the Unicode character properties database.") self.VerboseCheckBox.SetToolTipString("This flag allows you to write regular expressions that look nicer.\nWhitespace within the pattern is ignored, except when in a character class or preceded by an unescaped backslash, and, when a line contains a \"#\" neither in a character class or preceded by an unescaped backslash, all characters from the leftmost such \"#\" through the end of the line are ignored. ") self.HelpSelection.SetSelection(0) self.BottomPane.SetSize((623, 324)) self.SplitterWindow.SplitHorizontally(self.TopPane, self.BottomPane, 120) # end wxGlade def __do_layout(self): # begin wxGlade: MyFrame.__do_layout MainSizer = wx.BoxSizer(wx.HORIZONTAL) TopPaneSizer = wx.BoxSizer(wx.HORIZONTAL) HelpPaneSizer = wx.FlexGridSizer(3, 1, 7, 7) SampleTextSizer = wx.BoxSizer(wx.HORIZONTAL) MatchesPaneSizer = wx.BoxSizer(wx.HORIZONTAL) BottomPaneSizer = wx.FlexGridSizer(5, 3, 0, 0) OptionsSizer = wx.FlexGridSizer(1, 2, 0, 7) FlagsSizer = wx.StaticBoxSizer(wx.StaticBox(self.TopPane, -1, "Flags"), wx.HORIZONTAL) FlagCheckSizer = wx.FlexGridSizer(4, 3, 7, 15) RegexSizer = wx.FlexGridSizer(1, 2, 0, 7) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) RegexSizer.Add(self.RegexBox, 0, wx.EXPAND, 0) RegexSizer.Add(self.EvaluateButton, 0, 0, 0) RegexSizer.AddGrowableCol(0) BottomPaneSizer.Add(RegexSizer, 1, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) OptionsSizer.Add(self.MethodBox, 0, wx.EXPAND, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagCheckSizer.Add(self.IgnoreCheckBox, 0, 0, 0) FlagCheckSizer.Add(self.LocaleCheckBox, 0, 0, 0) FlagCheckSizer.Add(self.MultilineCheckBox, 0, 0, 0) FlagCheckSizer.Add(self.DotAllCheckBox, 0, 0, 0) FlagCheckSizer.Add(self.UnicodeCheckBox, 0, 0, 0) FlagCheckSizer.Add(self.VerboseCheckBox, 0, 0, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0) FlagsSizer.Add(FlagCheckSizer, 1, wx.EXPAND, 0) OptionsSizer.Add(FlagsSizer, 1, 0, 0) BottomPaneSizer.Add(OptionsSizer, 1, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0) self.TopPane.SetAutoLayout(1) self.TopPane.SetSizer(BottomPaneSizer) BottomPaneSizer.Fit(self.TopPane) BottomPaneSizer.SetSizeHints(self.TopPane) BottomPaneSizer.AddGrowableCol(1) MatchesPaneSizer.Add(self.MatchesWindow, 1, wx.EXPAND, 0) self.MatchesPane.SetAutoLayout(1) self.MatchesPane.SetSizer(MatchesPaneSizer) MatchesPaneSizer.Fit(self.MatchesPane) MatchesPaneSizer.SetSizeHints(self.MatchesPane) SampleTextSizer.Add(self.SampleText, 1, wx.EXPAND, 0) self.SampleTextPane.SetAutoLayout(1) self.SampleTextPane.SetSizer(SampleTextSizer) SampleTextSizer.Fit(self.SampleTextPane) SampleTextSizer.SetSizeHints(self.SampleTextPane) HelpPaneSizer.Add((1, 1), 0, wx.EXPAND, 0) HelpPaneSizer.Add(self.HelpSelection, 0, wx.EXPAND, 0) HelpPaneSizer.Add(self.HelpWindow, 1, wx.EXPAND, 0) self.HelpPane.SetAutoLayout(1) self.HelpPane.SetSizer(HelpPaneSizer) HelpPaneSizer.Fit(self.HelpPane) HelpPaneSizer.SetSizeHints(self.HelpPane) HelpPaneSizer.AddGrowableRow(2) HelpPaneSizer.AddGrowableCol(0) self.Notebook.AddPage(self.MatchesPane, "Matches") self.Notebook.AddPage(self.SampleTextPane, "Sample text") self.Notebook.AddPage(self.HelpPane, "Help") TopPaneSizer.Add(self.Notebook, 1, wx.EXPAND, 0) self.BottomPane.SetAutoLayout(1) self.BottomPane.SetSizer(TopPaneSizer) MainSizer.Add(self.SplitterWindow, 1, wx.EXPAND, 0) self.SetAutoLayout(1) self.SetSizer(MainSizer) self.Layout() self.Centre() # end wxGlade # end of class MyFrame class MyFrameWithEvents(MyFrame): """Subclasses MyFrame - generated by wxGlade - and adds events.""" def __init__(self, *args, **kwargs): MyFrame.__init__(self, *args, **kwargs) # map option flags to checkboxes self.flagmapper = {FLAGIGNORE: self.IgnoreCheckBox, FLAGMULTILINE: self.MultilineCheckBox, FLAGLOCALE: self.LocaleCheckBox, FLAGDOTALL: self.DotAllCheckBox, FLAGUNICODE: self.UnicodeCheckBox, FLAGVERBOSE: self.VerboseCheckBox} self.SetTitle(" " + self.GetTitle() + " " + __version__) # set empty pages for HTML windows self.MatchesWindow.SetPage("") self.HelpWindow.SetPage("") self.HelpWindow.SetWindowStyleFlag(wx.SUNKEN_BORDER) self.Notebook.SetSelection(0) self.RegexBox.Clear() # bind events wx.EVT_BUTTON(self, ID_EVALUATE, self.evaluate) wx.EVT_CLOSE(self, self.close) wx.EVT_NOTEBOOK_PAGE_CHANGED(self, ID_NOTEBOOK, self.changePage) wx.EVT_COMBOBOX(self, ID_HELPCOMBOBOX, self.showhelp) # apply settings self.loadSettings() # move focus to regex input field self.RegexBox.SetFocus() # initialize needed attribs self.matches = [] # list of found matches self.path = os.path.split(sys.argv[0])[0] or os.getcwd() # remembers where Kiki is located def icon(self, path=None): """Load and assign the icon Arguments: path -- path where kiki.ico is located. If path==None, the current directory is used """ import sys if path==None: self.path = os.path.split(sys.argv[0])[0] or os.getcwd() # *MUST* be the directory where everything, including About data and the likes are located else: self.path = path iconfile = os.path.join(self.path, "kiki.ico") theicon = wx.Icon(iconfile, wx.BITMAP_TYPE_ICO) self.SetIcon(theicon) def changePage(self, event): """Handles notebook page changes""" if event.GetSelection()==2 and not self.HelpWindow.GetOpenedPageTitle().strip(): self.HelpWindow.SetPage(file(os.path.join(self.path, "docs", "index.html"),"r").read()) def showhelp(self, event): """Handles help combo box events""" sel = self.HelpSelection.GetStringSelection().lower() # must lower-case for comparisons id = self.HelpSelection.GetSelection() filename, anchor = "", "" simpleload = True if id==0: # show main help filename = "index.html" elif sel.find("syntax")>-1: filename, anchor = "re.html", "syntax" elif sel.find("special characters")>-1: filename, anchor = "re.html", "specialcharacters" elif sel.find("extensions")>-1: filename, anchor = "re.html", "extensions" elif sel.find("special sequences")>-1: filename, anchor = "re.html", "specialsequences" elif sel.find("flags")>-1: filename, anchor = "re.html", "flags" else: simpleload = False if simpleload: filename = os.path.join(self.path, "docs", filename) if anchor.strip(): anchor = "#" + anchor else: anchor = "" self.HelpWindow.LoadPage(filename+anchor) else: # build about-screen f = file(os.path.join(self.path, "docs", "about.html"), "r") about = f.read() f.close() # build the dictionary needed to format the string if self.GetTitle().lower().find("spe")>-1: spe = "active" else: spe = "inactive (Kiki running standalone)" d = {"version": __version__, "kikidir": self.path, "datadir": settings.savedir, "pythonversion": sys.version.split()[0], "wxpythonversion": wx.__version__, "spe": spe, "website": "http://come.to/project5", "mail": "project5@wanadoo.nl", "icq": "84243714" } about = about % d self.HelpWindow.SetPage(about) def evaluate(self, event): """Actual functionality, triggered by Evaluate button press. The regex is compiled if possible. If compilation is successful, the regex is added to the history and it's matched against the sample text. If compilation is unsuccessful, the error message is displayed. """ self.saveSettings() self.Notebook.SetSelection(0) # display output pane # STEP 1: try to compile the regex # get flags to use in the compilation flags = 0 for flag in self.flagmapper.keys(): if self.flagmapper[flag].IsChecked(): flags = flags|eval(flag) # compile the regex and stop with error message if invalid try: self.MatchesWindow.SetPage("") regex = re.compile(self.RegexBox.GetValue(), flags) except re.error, e: self.MatchesWindow.SetPage(t_error % e) return False # stop execution if error if self.RegexBox.GetValue().strip(): # append to history if non-empty # get current history items currentitems = [self.RegexBox.GetValue()] for i in range(self.RegexBox.GetCount()): t = self.RegexBox.GetString(0) if not t in currentitems: # no duplicates currentitems.append(t) self.RegexBox.Delete(0) for item in currentitems: self.RegexBox.Append(item) self.RegexBox.SetSelection(0) # set selection again rawtext = self.SampleText.GetValue() # insider joke for the Sluggy fans if rawtext.strip()=="INSTANT FERRET-SHOCK!": import random shock = [""] #blinkychars = """+*-/\:;][{}|tyqfghjkl?>ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%""" rc = random.choice c = colors sa = shock.append t = """KIKI""" [ sa(t % (rc(c))) for i in xrange(10000) ] shock.append("") self.MatchesWindow.SetPage("".join(shock)) return None self.matches = [] # empty the list of match objects output = [] while 1: if len(self.matches)==0: start = 0 else: start = self.matches[-1].end() if len(self.matches[-1].group(0))==0: # in case of expressions which return empty matches # Without this condition, an endless loop would occur. start += 1 match = regex.search(rawtext, start) if (not match) or \ (len(self.matches)>=1 and self.MethodBox.GetSelection()==1) or \ start>=len(rawtext): # this last condition is also to prevent an endless loop break # stop execution else: self.matches.append(match) if not self.matches: # if no matches found output.append(t_nomatch) else: # matches found # show matches with parentheses if settings.get(RESULTS_SHOWMATCHES, True): output.append(self.showmatches()) output.append("""

""") # show tabular overview of named groups if settings.get(RESULTS_SHOWNAMEDGROUPS, True): # TODO: self.shownamedgroups() pass if settings.get(RESULTS_SHOWSAMPLE, True): output.append("""
Sample text matched against:
""") output.append(self.htmlize(rawtext) or " ") # something must be in there, so if no raw text, at least force a space output.append("""
""") self.MatchesWindow.SetPage("".join(output)) def htmlize(self, text): """Converts the text to html (escapes HTML entities and tags, converts spaces to  's and enters to
's.""" result = cgi.escape(text) result = result.replace("\t", "    ") result = result.replace(" ", "  ") result = result.replace("\r\n", "
") result = result.replace("\r", "
") result = result.replace("\n", "
") return result def formatmatch(self, match, index, matchtemplate, starttemplate, endtemplate): """Pretty-prints a match as HTML, with colors for groups, etc.""" # first, make a dictionary of start and end positions # (each char number in the match may be mapped to zero, one or more # group numbers which start/end there) # Groups function according to first-to-open, last-to-close. starts, ends = {}, {} # populate the dictionaries with empty lists # A -1 key is necessary for groups which do not participate in the match. for pos in range(-1, len(match.string)+1): starts[pos], ends[pos] = [], [] # now populate them with real values: each position key will contain # none or more group numbers #print match.groups() for groupnr in range(1+len(match.groups())): #print groupnr #print starts, ends starts[match.start(groupnr)].append(groupnr) ends[match.end(groupnr)].append(groupnr) # prepare result result = [] # now, loop through the string matched and build the layout string = match.string opengroups = [] # keeps track of open groups for pos in range(match.start(), match.end()+1): while 1: # first, try to shut down any open groups if opengroups and opengroups[-1] in ends[pos]: # if opengroups available and the last one must be closed now # shut down open group and remove it from the opengroups list result.append(endtemplate % {GROUPCOLOR: colors[opengroups[-1] % len(colors)], GROUPNUMBER: opengroups.pop(-1)}) # secondly, try to open any new groups elif starts[pos]: # if any new groups must be opened now result.append(starttemplate % {GROUPCOLOR: colors[starts[pos][0] % len(colors)], GROUPNUMBER: starts[pos][0]}) opengroups.append(starts[pos].pop(0)) else: # if no groups must be opened or closed, nothing special going on if pos""") # load match layout templates starttemplate = settings.get(STARTTEMPLATE, """(""" % GROUPCOLOR) endtemplate = settings.get(ENDTEMPLATE, """)%%(%s)s""" % (GROUPCOLOR, GROUPNUMBER)) matchtemplate = settings.get(MATCHTEMPLATE, """%%(%s)s:%%(%s)s""" % (MATCHINDEX, FORMATTEDMATCH)) # loop through matches and create output for match in self.matches: index += 1 # determine what part of the string we're looking at if index>0: prevmatchend = self.matches[index-1].end() else: prevmatchend = 0 if index+1 < len(self.matches): nextmatchstart = self.matches[index+1].start() else: nextmatchstart = -1 # append piece in between matches html.append(self.htmlize(match.string[prevmatchend:match.start()])) # append current match #html.append(self.htmlize(match.string[match.start():match.end()])) html.append(self.formatmatch(match, index, matchtemplate, starttemplate, endtemplate)) # append end piece if necessary if index+1 >= len(self.matches): # if last match, print rest of string html.append(self.htmlize(match.string[match.end():])) html.append("""""") res = "".join(html) return res def loadSettings(self): """Loads GUI settings from the settings system.""" # load some size settings # set window size and position; make sure it's on screen # and has a reasonable size system = wx.SystemSettings_GetMetric pos = list(settings.get(WINDOWPOSITION, (-1,-1))) x = system(wx.SYS_SCREEN_X) y = system(wx.SYS_SCREEN_Y) if pos[0]<=-1: pos[0] = (x/2)-320 if pos[1]<=-1: pos[1] = (y/2)-240 if pos[0]>system(wx.SYS_SCREEN_X)-50: pos[0] = 0 if pos[1]>system(wx.SYS_SCREEN_Y)-50: pos[1] = 0 self.SetPosition(pos) size = list(settings.get(WINDOWSIZE, (-1, -1))) if size[0]>system(wx.SYS_SCREEN_X): size[0] = 640 if size[1]>system(wx.SYS_SCREEN_Y): size[1] = 480 size[0] = max(size[0], 640) size[1] = max(size[1], 480) self.SetSize(size) # load the sample text and regex last used self.SampleText.SetValue(settings.get(SAMPLETEXT, "")) self.RegexBox.SetValue(settings.get(REGEX, "")) # load the flags and desired type of re functionality for flag in self.flagmapper.keys(): self.flagmapper[flag].SetValue(settings.get(flag, False)) self.MethodBox.SetSelection(settings.get(SEARCHTYPE, 0)) # other settings self.SplitterWindow.SetSashPosition(settings.get(SASHPOSITION, 100)) def saveSettings(self, dosave=True): """Puts all GUI settings in the settings system. Arguments: dosave -- if True, the save() method of Settings is called when done """ # put all stuff that needs saving in the settings settings.set(WINDOWSIZE, self.GetSize()) settings.set(WINDOWPOSITION, self.GetPosition()) settings.set(SASHPOSITION, self.SplitterWindow.GetSashPosition()) settings.set(SAMPLETEXT, self.SampleText.GetValue()) settings.set(REGEX, self.RegexBox.GetValue()) # save the selected flags for flag in self.flagmapper.keys(): settings.set(flag, self.flagmapper[flag].GetValue()) settings.set(SEARCHTYPE, self.MethodBox.GetSelection()) if dosave: settings.save() def close(self, event): """Prepares for shutdown and then closes the app.""" self.saveSettings() # shut down the settings system settings.shutdown() # shut down the app self.Destroy() def speCreate(parent, info=None): """Integration of Kiki into spe (http://spe.pycs.net)""" global settings settings = Settings(dirname=".spe", filename="kikicfg.py", debugfile="kikidebug") Kiki = MyFrameWithEvents(parent, -1, "") Kiki.SetTitle(Kiki.GetTitle() + " - the ferret in your Spe") if info and info.has_key('kikiPath'): kikipath = info['kikiPath'] else: kikipath = os.path.join(os.path.dirname(sys.argv[0]), "framework/contributions") Kiki.icon(kikipath) Kiki.Show(1) return Kiki def main(): global settings settings = Settings(dirname=".kiki", filename="kikicfg.py", debugfile="kikidebug") Kiki = wx.PySimpleApp() wx.InitAllImageHandlers() mw = MyFrameWithEvents(None, -1, "") mw.icon() Kiki.SetTopWindow(mw) mw.Show(1) Kiki.MainLoop() if __name__ == "__main__": main() spe-0.8.4.h/_spe/plugins/kiki/readme.txt0000644000175000017500000000541210272471120017110 0ustar stanistaniKIKI 0.5.6 - regexes made nifty Copyright (C) 2003, 2004 Project 5 (http://come.to/project5) Licence: GPL (free) Requires: Python, wxPython System: any, provided (wx)Python runs on it Installation ============ Make sure you install first (if not already present on your system): - Python (2.3.x or newer) from: http://python.org - wxPython (2.4.2.4 or later - preferably 2.5.1.5 or later) from: http://wxpython.org Then unpack this archive to some directory and run "kiki.py" either by double-clicking on it or by entering at the command line prompt "python kiki.py". Windows users might want to use "Kiki.bat" to run it instead. You might want to add it to your start menu too. Windows users should open the Kiki directory in the explorer. Right-click on "Kiki.bat" and, keeping the right mouse button pressed, drag and drop the file on the Start button. If you want the icon in there too, proceed as follows: - go to the Start menu and right-click on "Kiki", then choose "Properties" - go to the "Shortcut" tab and click on "Other icon" (not sure what it is on English systems). You will get a warning message, ignore it. - click on the Browse button and go to the Kiki directory. Select the "kiki.ico" file and then click on the "Open" button. Linux users should use whatever facilities their distro provides to manipulate the menu. Integration with Spe ==================== Spe is a very good Python editor, also written in Python/wxPython. It is available at http://spe.pycs.net. The distribution includes an unmodified version of Kiki. You can access it from the Tools menu. Uninstalling ============ - remove the folder where you unpacked kiki.py You can also remove the folder in your $HOME directory called ".kiki". This is where Pears stores its stuff. Under WinXP, the $HOME folder can be located at: C:\Documents and Settings\ Help ==== For help, see the Help tab in the program. Credits ======= Once upon a time, there was a Tkinter-based application called "Recon - Regular expression test console", written by Brent Burley, which I found quite useful for writing regexes. I decided that I needed something with more features and better looks. Kiki and Recon share no code at all, but they share the design philosophy. I decided to call my program "Ferret" (short for "Free Environment for Regular Expression Testing"). On second thought, I thought it would be better to name it after the most famous (in fact after the *only* famous) ferret I know: Kiki from the very funny Sluggy online comic (http://sluggy.com). Plans for future versions ========================= - overview of named groups History ======= The project history is present in "history.txt".spe-0.8.4.h/_spe/plugins/kiki/Kiki.bat0000644000175000017500000000015510272471120016470 0ustar stanistani@ECHO OFF @ECHO Use this file to start the program under Windows. SET PATH start pythonw -OO kiki.py exitspe-0.8.4.h/_spe/plugins/kiki/docs/0000755000175000017500000000000011004131465016037 5ustar stanistanispe-0.8.4.h/_spe/plugins/kiki/docs/re.html0000644000175000017500000012425710272471120017347 0ustar stanistani Regular expression docs
Syntax
A regular expression (or RE) specifies a set of strings that matches it. Kiki helps you find out if a certain regular expression matches a particular string.

Regular expressions can be concatenated to form new regular expressions: if A and B are both regular expressions, then AB is also a regular expression.
If a string p matches A and another string q matches B, the string pq will match AB (presuming the two RE's don't specify boundary conditions that are no longer satisfied by pq.
This means that complex expressions can easily be constructed from simpler primitive expressions.

Regular expressions can contain both special and ordinary characters. Most ordinary characters, like A, a, or 0, are the simplest regular expressions: they simply match themselves. You can concatenate ordinary characters, so last matches the string last.
Note the color coding used throughout these docs: this is a regex while this is a string.

Some characters, like | or (, are special. Special characters, when used in regular expressions, either stand for classes of ordinary characters, or affect how the regular expressions around them are interpreted.

Special characters
. (dot) In the default mode, this matches any character except a newline. If the DOTALL flag has been specified, this matches any character including a newline.
^ (caret) Matches the start of the string, and in MULTILINE mode also matches immediately after each newline.
$ Matches the end of the string or just before the newline at the end of the string, and in MULTILINE mode also matches before a newline.
foo matches both foo and foobar, while the regular expression foo$ matches only foo. More interestingly, searching for foo.$ in foo1\nfoo2\n matches foo2 normally, but foo1 in MULTILINE mode.
* Causes the resulting RE to match 0 or more repetitions of the preceding RE, as many repetitions as are possible.ab* will match a, ab, or a followed by any number of b's.
+ Causes the resulting RE to match 1 or more repetitions of the preceding RE. ab+ will match a followed by any non-zero number of b's. It will not match just a.
? Causes the resulting RE to match 0 or 1 repetitions of the preceding RE. ab? will match either a or ab.
*?, +?, ?? The *, +, and ? qualifiers are all greedy: they match as much text as possible. Sometimes this behaviour isn't desired. If the RE <.*> is matched against <H1>title</H1>, it will match the entire string, and not just <H1>. Adding ? after the qualifier makes it perform the match in non-greedy or minimal fashion: as few characters as possible will be matched. Using .*? in the previous expression will match only <H1>.
{m} Specifies that exactly m copies of the previous RE should be matched; fewer matches cause the entire RE not to match. For example, a{6} will match exactly six a characters, but not five.
{m,n} Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as many repetitions as possible. For example, a{3,5} will match from 3 to 5 a characters. Omitting m specifies a lower bound of zero, and omitting n specifies an infinite upper bound. As an example, a{4,}b will match aaaab or a thousand a characters followed by a b, but not aaab. The comma may not be omitted or the modifier would be confused with the previously described form.
{m,n}? Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as few repetitions as possible. This is the non-greedy version of the previous qualifier. For example, on the 6-character string aaaaaa, a{3,5} will match 5 a characters, while a{3,5}? will only match 3 characters.
\ Either escapes special characters (permitting you to match characters like *, ?, and so forth), or signals a special sequence; special sequences are discussed below.

If you're not using a raw string to express the pattern, remember that Python also uses the backslash as an escape sequence in string literals; if the escape sequence isn't recognized by Python's parser, the backslash and subsequent character are included in the resulting string. However, if Python would recognize the resulting sequence, the backslash should be repeated twice. This is complicated and hard to understand, so it's highly recommended that you use raw strings for all but the simplest expressions.
[] Used to indicate a set of characters. Characters can be listed individually, or a range of characters can be indicated by giving two characters and separating them by a -. Special characters are not active inside sets. For example, [akm$] will match any of the characters a, k, m, or $. [a-z] will match any lowercase letter, and [a-zA-Z0-9] matches any letter or digit. Character classes such as \w or \S (defined below) are also acceptable inside a range. If you want to include a ] or a - inside a set, precede it with a backslash, or place it as the first character. The pattern []] will match ], for example.

You can match the characters not within a range by complementing the set. This is indicated by including a ^ as the first character of the set. ^ elsewhere will simply match the ^ character. For example, [^5] will match any character except 5, and [^^] will match any character except ^.
| A|B, where A and B can be arbitrary REs, creates a regular expression that will match either A or B. An arbitrary number of REs can be separated by the | in this way. This can be used inside groups (see below) as well. REs separated by | are tried from left to right, and the first one that allows the complete pattern to match is considered the accepted branch. This means that if A matches, B will never be tested, even if it would produce a longer overall match. In other words, the | operator is never greedy. To match a literal |, use \|, or enclose it inside a character class, as in [|].
(...) Matches whatever regular expression is inside the parentheses, and indicates the start and end of a group; the contents of a group can be retrieved after a match has been performed, and can be matched later in the string with the \number special sequence, described below. To match the literals ( or ), use \( or \), or enclose them inside a character class: [(] [)].
(?...) This is an extension notation (a ? following a ( is not meaningful otherwise). The first character after the ? determines what the meaning and further syntax of the construct is. Extensions usually do not create a new group; (?P<name>...) is the only exception to this rule. The supported extensions are listed below.

Extensions
(?iLmsux) (One or more letters from the set i, L, m, s, u, x.) The group matches the empty string and the letters set the corresponding flags (re.I, re.L, re.M, re.S, re.U, re.X) for the entire regular expression. This is useful if you wish to include the flags as part of the regular expression, instead of passing a flag argument to the compile() function.

Note that the (?x) flag changes how the expression is parsed. It should be used first in the expression string, or after one or more whitespace characters. If there are non-whitespace characters before the flag, the results are undefined.
(?:...) A non-grouping version of regular parentheses. Matches whatever regular expression is inside the parentheses, but the substring matched by the group cannot be retrieved after performing a match or referenced later in the pattern.
(?P<name>...) Similar to regular parentheses, but the substring matched by the group is accessible via the symbolic group name name. Group names must be valid Python identifiers, and each group name must be defined only once within a regular expression. A symbolic group is also a numbered group, just as if the group were not named. So the group named id in the example above can also be referenced as the numbered group 1.

For example, if the pattern is (?P<id>[a-zA-Z_]\w*), the group can be referenced by its name in arguments to methods of match objects, such as m.group('id') or m.end('id'), and also by name in pattern text (for example, (?P=id)) and replacement text (such as \g<id>).
(?P=name) Matches whatever text was matched by the earlier group named name.
(?#...) A comment; the contents of the parentheses are simply ignored.
(?=...) Matches if ... matches next, but doesn't consume any of the string. This is called a lookahead assertion. For example, Isaac (?=Asimov) will match Isaac  only if it's followed by Asimov.
(?!...) Matches if ... doesn't match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match Isaac  only if it's not followed by Asimov.
(?<=...) Matches if the current position in the string is preceded by a match for ... that ends at the current position. This is called a positive lookbehind assertion. (?<=abc)def will find a match in abcdef, since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that abc or a|b are allowed, but a* and a{3,4} are not. Note that patterns which start with positive lookbehind assertions will never match at the beginning of the string being searched. You will most likely want to use the search() function rather than the match() function:
    >>> import re
    >>> m = re.search('(?<=abc)def', 'abcdef')
    >>> m.group(0)
    def
                    
This example looks for a word following a hyphen:
    >>> m = re.search('(?<=-)\w+', 'spam-egg')
    >>> m.group(0)
    egg
                    
(?<!...) Matches if the current position in the string is not preceded by a match for .... This is called a negative lookbehind assertion. Similar to positive lookbehind assertions, the contained pattern must only match strings of some fixed length. Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched.

Special sequences
The special sequences consist of \ and a character from the list below. If the ordinary character is not on the list, then the resulting RE will match the second character. For example, \$ matches the character $.
\\ matches a literal backslash character
\number Matches the contents of the group of the same number. Groups are numbered starting from 1. For example, (.+) \1 matches the the or 55 55, but not the end (note the space after the group). This special sequence can only be used to match one of the first 99 groups. If the first digit of number is 0, or number is 3 octal digits long, it will not be interpreted as a group match, but as the character with octal value number. Inside the [ and ] of a character class, all numeric escapes are treated as characters.
\a ASCII Bell (BEL)
\A Matches only at the start of the string.
\b Matches the empty string, but only at the beginning or end of a word. A word is defined as a sequence of alphanumeric or underscore characters, so the end of a word is indicated by whitespace or a non-alphanumeric, non-underscore character. Note that \b is defined as the boundary between \w and \W, so the precise set of characters deemed to be alphanumeric depends on the values of the LOCALE and UNICODE flags.
Inside a character range, \b represents the backspace character, for compatibility with Python's string literals.
\B Matches the empty string, but only when it is not at the beginning or end of a word. This is just the opposite of \b, so is also subject to the settings of LOCALE and UNICODE.
\d Matches any decimal digit. This is equivalent to the set [0-9].
\D Matches any non-digit character; this is equivalent to the set [^0-9].
\f ASCII Formfeed (FF)
\n ASCII Linefeed (LF)
\r ASCII Carriage Return (CR)
\s Matches any whitespace character. This is equivalent to the set [ \t\n\r\f\v].
\S Matches any non-whitespace character. This is equivalent to the set [^ \t\n\r\f\v].
\t ASCII Horizontal Tab (TAB)
\v ASCII Vertical Tab (VT)
\w When the LOCALE and UNICODE flags are not specified, matches any alphanumeric character and the underscore. This is equivalent to the set [a-zA-Z0-9_].
With LOCALE, it will match the set [0-9_] plus whatever characters are defined as alphanumeric for the current locale.
If UNICODE is set, this will match the characters [0-9_] plus whatever is classified as alphanumeric in the Unicode character properties database.
\W When the LOCALE and UNICODE flags are not specified, matches any non-alphanumeric character. This is equivalent to the set [^a-zA-Z0-9_].
With LOCALE, it will match any character not in the set [0-9_], and not defined as alphanumeric for the current locale.
If UNICODE is set, this will match anything other than [0-9_] and characters marked as alphanumeric in the Unicode character properties database.
\xhh ASCII character with hex value hh
\Z Matches only at the end of the string.

Flags
The RE's behaviour can be modified by specifying a flags value. Values can be any of the following variables, combined using bitwise or (the | operator).
IGNORECASE (I) Perform case-insensitive matching. Expressions like [A-Z] will match lowercase letters, too. This is not affected by the current locale.
LOCALE (L) Make \w, \W, \b, and \B dependent on the current locale.
MULTILINE (M) When specified, the pattern character ^ matches at the beginning of the string and at the beginning of each line (immediately following each newline) and the pattern character $ matches at the end of the string and at the end of each line (immediately preceding each newline).
By default, ^ matches only at the beginning of the string, and $ only at the end of the string and immediately before the newline (if any) at the end of the string.
DOTALL (S) Make the . special character match any character at all, including a newline. Without this flag, . will match anything except a newline.
UNICODE (U) Make \w, \W, \b, and \B dependent on the Unicode character properties database (since Python 2.0).
VERBOSE (X) This flag allows you to write regular expressions that look nicer. Whitespace within the pattern is ignored, except when in a character class or preceded by an unescaped backslash, and, when a line contains a # neither in a character class or preceded by an unescaped backslash, all characters from the leftmost such # through the end of the line are ignored.
spe-0.8.4.h/_spe/plugins/kiki/docs/about.html0000644000175000017500000001021410272471120020036 0ustar stanistani About Kiki
Kiki
Kiki is a free environment for regular expression testing (ferret).

Program info
Version: %(version)s
Program directory: %(kikidir)s
Data directory: %(datadir)s
Python version: %(pythonversion)s
wxPython version: %(wxpythonversion)s
Spe status: %(spe)s

Contact info
Web: %(website)s
e-mail/msn: %(mail)s
icq: %(icq)s

Credits
Kiki is built using a number of tools besides the extensive libraries of Python and wxPython:
  • the Spe Python editor
  • wxGlade for GUI design
  • the SciTE editor for Python and HTML coding
  • recon.py by Brent Burley for inspiration and correctness testing
  • part of the Python documentation is ripped and included in this distro
Of course I should also thank Pete Abrams for his Sluggy Freelance online comic which has kept me entertained for quite some time now and has also been the source of the name of this program. For those of you who don't know the comic: Kiki is a talking ferret which is very fond of bright colors and happy thoughts.

Licence
This program is © 2003, 2004 by Project 5
It is licenced under the GNU General Public Licence (GPL)

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

spe-0.8.4.h/_spe/plugins/kiki/docs/index.html0000644000175000017500000002411110272471120020034 0ustar stanistani Working with Kiki
Intro
Kiki is a free environment for regular expression testing (ferret). It allows you to write regexes and test them against your sample text, providing extensive output about the results. It is useful for several purposes:
  • exploring and understanding the structure of match objects generated by the re module, making Kiki a valuable tool for people new to regexes
  • testing regexes on sample text before deploying them in code
Kiki can function on its own or as plugin for the Spe Python editor.

Working with Kiki
Enter the regex in the combo box and hit Evaluate to run it against the text in the Sample text tab. The results appear in the Matches tab. You can use the list in the Help tab to view the built-in documentation about regular expressions. This documentation comes from the Python help files.

Kiki automatically stores its settings and the last used sample text/regex in between sessions. During a session, all regexes which have been evaluated and have returned matches, are also stored in the combo box where the regex is entered, so you may experiment with e.g. adapted versions without losing a more primitive regex that already kinda works.

Options
Methods
Use Find all to get all non-overlapping matches of the regex, or Find first to get only the first match (equivalent to the search method of regular expression objects).
Flags
Determines which flags the regex should be compiled with.

Understanding the output
Kiki's output is quite extensive and provides color-coded information on the results of the match. Let's assume you're trying to match the regex fer(re)*t against the sample text Kiki the ferret - as nifty as ferrets get. The results of a Find all evaluation by default looks something like this:

Kiki the 0:(fer(re)1t)0 - as nifty as 1:(fer(re)1t)0s get


Each match is prepended by a small, underlined number: this is the index of the corresponding match object in the list of match objects found in the sample text. In the example above, there are two match objects, with indexes 0 and 1.

Within each match, colored parentheses show where a match group starts and ends. Group ()0 represents the entire match. In this example we have also created an extra group because of the use of (re)*". This is made visible by the green parentheses bearing the index 1: ()1.

Pay attention to an interesting property of these groups: some of them might not contribute to the match and are then skipped in the output (in the match object, these groups start and end at position -1). An example: let's find all sentences talking about expecting the Spanish Inquisition in the text below:

Chapman: I didn't expect a kind of Spanish Inquisition.

(JARRING CHORD - the cardinals burst in)

Ximinez: NOBODY expects the Spanish Inquisition! Our chief weapon is surprise...surprise and fear...fear and surprise.... Our two weapons are fear and surprise...and ruthless efficiency.... Our *three* weapons are fear, surprise, and ruthless efficiency...and an almost fanatical devotion to the Pope.... Our *four*...no... *Amongst* our weapons.... Amongst our weaponry...are such elements as fear, surprise.... I'll come in again. (Exit and exeunt)


For this purpose, we can use e.g. the following regex:

([a-zA-Z']+\s)+?expect(.*?)(the )*Spanish Inquisition(!|.)

The result is:

Chapman: 0:(I (didn't )1expect( a kind of )2Spanish Inquisition(.)4)0

(JARRING CHORD - the cardinals burst in)

Ximinez: 1:((NOBODY )1expect(s )2(the )3Spanish Inquisition(!)4)0 Our chief weapon is surprise...surprise and fear...fear and surprise.... Our two weapons are fear and surprise...and ruthless efficiency.... Our *three* weapons are fear, surprise, and ruthless efficiency...and an almost fanatical devotion to the Pope.... Our *four*...no... *Amongst* our weapons.... Amongst our weaponry...are such elements as fear, surprise.... I'll come in again. (Exit and exeunt)


The interesting part is what's going on in the match with index 0: between the group with index 2 and the one with index 4, the group with index 3 has disappeared. This group matches an optional the which is not present in this case. In other words, the group exists, but does not contribute to the match and is therefore not displayed.

spe-0.8.4.h/_spe/doc/home.py0000644000175000017500000000011010275052655014552 0ustar stanistaniimport webbrowser webbrowser.open('http://www.stani.be/python/spe/blog')spe-0.8.4.h/_spe/doc/about.htm0000644000175000017500000000505710364527643015116 0ustar stanistaniSPE (Stani's Python Editor)

Spe is an Integrated Development Editor for the Python
programming language (fully compatible with Blender).


Copyright 2003 www.stani.be

Links

Homepage http://spe.pycs.net
Website http://projects.blender.org/projects/spe
Forums http://projects.blender.org/forum/?group_id=30

Program info

Spe version %(version)s
Python version %(pyVersionC)s  (%(pyVersion)s required)
wxPython version %(wxVersionC)s  (%(wxVersion)s required)
   
Spe location %(location)s
Sm location %(smLocation)s
User path %(userPath)s

Look up the manual for requirements (python/wxPython/Blender) and detailed credit information.
Spe is licenced under the GNU General Public Licence (GPL)

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.spe-0.8.4.h/_spe/doc/donate.html0000644000175000017500000000154010754704733015423 0ustar stanistani spe Get the manual and support SPE!!!
Please make a donation if you enjoy using SPE and would like to help support it. It will definitely help. Any donation starting from 5 euro/dollar is welcome. If you know any fund which would be helpful, please let me know. Large donations can be rewarded with a link on the SPE website or name mentioning in SPE documentation.

Payment method:
spe-0.8.4.h/_spe/view/__init__.py0000644000175000017500000000000010332317741015556 0ustar stanistanispe-0.8.4.h/_spe/view/documentation.py0000644000175000017500000001005010711105120016661 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Index as tab.""" __doc__=INFO['doc']%INFO ####Panel class----------------------------------------------------------------- def _(x): return x import wx, sm.wxp import os, nturl2path, sys import pydoc ERROR = "

"+_("Error")+"


"+\ _("SPE could not generate documentation for ")+\ _("%s:

%s") ERROR_UNNAMED = "

"+_("Error")+"


"+\ _("SPE can't generate documentation of unnamed files.
")+\ _("Please save your file first.") def my_import(name): mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod class Panel(sm.wxp.HtmlWindow): def __init__(self,parent,*args,**kwds): sm.wxp.HtmlWindow.__init__(self,parent=parent,id=-1) self.SetFonts(normal_face='helvetica',fixed_face='courier',sizes=[8,9,10,12,16,20,22]) self.childPanel = parent.childPanel self.open = self.childPanel.parentPanel.openList self.moduleName = None def main(self): if self.childPanel.confirmSave(_("""\ SPE will generate now documentation with pydoc. This implies importing the file. If some files, are not saved, it's recommended to press Cancel and save them first before generating any documentation. """)): try: fileName = self.childPanel.fileName if fileName == 'unnamed': self.SetPage(ERROR_UNNAMED) return path = os.path.dirname(fileName) moduleName = os.path.splitext(os.path.basename(fileName))[0] if path: os.chdir(path) self.loadDoc(moduleName,'') except Exception, message: self.error(moduleName,message) def OnLinkClicked(self, linkinfo): href = linkinfo.GetHref().split('.html') if len(href)==1: anchor = href[0] if anchor == '.': self.index() elif anchor[:5]== 'file:': self.open(nturl2path.url2pathname(anchor[5:])) else: self.loadDoc(self.moduleName,anchor) elif len(href)==2: moduleName, anchor = href self.loadDoc(moduleName,anchor) def loadDoc(self,moduleName,anchor): #generate html code if moduleName!= self.moduleName: try: module = my_import(moduleName) reload(module) doc = pydoc.html.page( moduleName, pydoc.html.document(module, moduleName) ) self.SetPage(doc) self.moduleName = moduleName except Exception, message: self.error(moduleName,message) #jump to anchor if anchor: self.LoadPage(anchor) def error(self,*args): self.SetPage(ERROR%tuple(args)) def index(self): heading = pydoc.html.heading( 'Python: Index of Modules', '#ffffff', '#7799ee') def bltinlink(name): return '%s' % (name, name) names = filter(lambda x: x != '__main__', sys.builtin_module_names) contents = pydoc.html.multicolumn(names, bltinlink) indices = ['

' + pydoc.html.bigsection( 'Built-in Modules', '#ffffff', '#ee77aa', contents)] seen = {} for dir in pydoc.pathdirs(): indices.append(pydoc.html.index(dir, seen)) contents = heading + pydoc.join(indices) + '''

pydoc by Ka-Ping Yee <ping@lfw.org>''' self.SetPage(contents) spe-0.8.4.h/_spe/sm/www.py0000644000175000017500000000647411003204334014322 0ustar stanistani#(c)www.stani.be (read __doc__ for more information) import sm INFO=sm.INFO.copy() INFO['description']=\ """Internet related """ __doc__=INFO['doc']%INFO #_______________________________________________________________________________ ####IMPORT---------------------------------------------------------------------- import cStringIO, htmllib, httplib, MimeWriter, urllib ####FUNCTIONS------------------------------------------------------------------- def createhtmlmail (html, text, subject): """Create a mime-message that will render HTML in popular MUAs, text in better ones""" out = cStringIO.StringIO() # output buffer for our message htmlin = cStringIO.StringIO(html) txtin = cStringIO.StringIO(text) writer = MimeWriter.MimeWriter(out) # # set up some basic headers... we put subject here # because smtplib.sendmail expects it to be in the # message body # writer.addheader("Subject", subject) writer.addheader("MIME-Version", "1.0") # # start the multipart section of the message # multipart/alternative seems to work better # on some MUAs than multipart/mixed # writer.startmultipartbody("alternative") writer.flushheaders() # # the plain text section # subpart = writer.nextpart() subpart.addheader("Content-Transfer-Encoding", "quoted-printable") pout = subpart.startbody("text/plain", [("charset", 'us-ascii')]) mimetools.encode(txtin, pout, 'quoted-printable') txtin.close() # # start the html subpart of the message # subpart = writer.nextpart() subpart.addheader("Content-Transfer-Encoding", "quoted-printable") # # returns us a file-ish object we can write to # pout = subpart.startbody("text/html", [("charset", 'us-ascii')]) mimetools.encode(htmlin, pout, 'quoted-printable') htmlin.close() # # Now that we're done, close our writer and # return the message body # writer.lastpart() msg = out.getvalue() out.close() print msg return msg def getSource(http, request='',**keywords): result = [] prevfirsturl = '' for c in range(0,maxr,10): h = httplib.HTTP(http) h.putrequest('GET', request+urllib.urlencode(keywords)) h.putheader('Accept', 'text/html') h.endheaders() errcode, errmsg, headers = h.getreply() if errcode == 200: f = h.getfile() source=f.read() f.close() return source else:return '' def htmlColor2rgb(c): "Converts htmlcolor in rgb tuple." if c[0]=='#':i=1 else:i=0 return (eval('0x'+c[i:i+2]),eval('0x'+c[i+2:i+4]),eval('0x'+c[i+4:i+6])) def main(): #createHtmlMail import smtplib f = open("newsletter.html", 'r') html = f.read() f.close() f = open("newsletter.txt", 'r') text = f.read() subject = "Today's Newsletter!" message = createhtmlmail(html, text, subject) server = smtplib.SMTP("localhost") server.sendmail('agillesp@i-noSPAMSUCKS.com', 'agillesp@i-noSPAMSUCKS.com', message) server.quit() #getSource getSource('www.google.com',request='/search?',q='Stani Michiels',start=0,filter=0) if __name__=="__main__":main() spe-0.8.4.h/_spe/sm/thread.py0000644000175000017500000001644110515765540014762 0ustar stanistani###(c)www.stani.be (read __doc__ for more information) ##import sm ##INFO=sm.INFO.copy() ## ##INFO['description']=\ ##"""Thread related.""" ## ##__doc__=INFO['doc']%INFO ###_______________________________________________________________________________ ####IMPORT---------------------------------------------------------------------- import Queue,threading,types,time ####CLASSES--------------------------------------------------------------------- class Thread(threading.Thread): def __init__(self,function,*arguments,**keywords): threading.Thread.__init__(self) self.function=function self.arguments=arguments self.keywords=keywords self.start() def run(self): apply(self.function,self.arguments,self.keywords) class _PoolThread(threading.Thread): """Private thread class used by the Pool class.""" def __init__(self, pool): threading.Thread.__init__(self) self.pool=pool self.id=len(self.pool._pool) def __exit__(self): pass def run(self): print 'Thread:\t starting thread %s'%self.id while not self.pool.isAborted(): self.process = self.pool._input.get() if self.process==SHUTDOWN or self.pool.isAborted(): break else: self._time=time.time() self._timeOut=0 function,arguments,keywords=self.process self.pool._current.put(self.process) self.pool._output.put(apply(function,arguments,keywords)) self.pool._current.get() self.__exit__() ## try: ## self.__exit__() ## except: ## pass #empty input, so that isalive is correct self.pool._input=Queue.Queue() print 'Thread:\t Exiting thread %s'%self.id def time(self): """Running time of the current process (not of thread).""" return time.time()-self._time def timeOut(self,seconds): """Returns true if a time out occured.""" if self.time()>seconds and not self._timeOut: self._timeOut=1 return 1 else: return 0 def noTimeOut(self): self._timeOut=0 class Pool: """Pool of reusable threads, without polling.""" def __init__(self, numThreads=5,timeOut=0,exit=None): """timeOut is only relevant for use together with the checkTimeOut method.""" self.timeOut=timeOut if exit:self.__exit__=exit self._aborted=0 self._current = Queue.Queue(numThreads) self._input = Queue.Queue() self._output = Queue.Queue() self._pool = [] self.add(numThreads) def __exit__(self): """Will be executed everytime EACH thread finishes.""" # TODO:Maybe it is better to do this only after ALL threads finish pass def __len__(self): """Returns how many threads are running.""" return len(self._pool) def abort(self): """Let the threads stop as fast as possible.""" self._aborted=1 def add(self,n): """Adds one thread to the pool.""" for i in range(n): t = _PoolThread(self) t.__exit__=self.__exit__ t.start() self._pool.append(t) def checkTimeOut(self,timeOut=0): """Adds a thread to the pool if one of the threads times out.""" if timeOut:self.timeOut=timeOut timeOuts=[] if self.timeOut: for t in self._pool: if t.timeOut(self.timeOut): timeOuts.append(t) self.add(1) def isAborted(self): """Returns true if the pool is trying to abort.""" return self._aborted def get(self): """Gets the last output value.""" return self._output.get() def getAll(self): """Gets all output values.""" l=[] while not self._output.empty():l.append(self._output.get()) return l def isAlive(self): """Returns true, if there are still processes scheduled or running.""" return not (self._input.empty() and self._current.empty()) def find(self,function,*arguments,**keywords): """Returns the thread which is executing this process.""" ## TODO:Replace function,arg,keyw with process!!!!!!! index=0 found=-1 process=(function,arguments,keywords) while indexY\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#+ self._max: return (x-self._min)%self._delta+self._min else: return x class ValueRangeInOut: """Class to convert between value ranges.""" def __init__(self,input,output): self.input = input self.output = output self.__call__ = self.i2o def i2f(self,x): """in2out float""" return self.output.f2f(self.input.r2f(x)) def i2o(self,x): """in2out""" return self.output.f2r(self.input.r2f(x)) def o2f(self,x): """out2in float""" return self.input.f2f(self.output.r2f(x)) def o2i(self,x): """out2in""" return self.input.f2r(self.output.r2f(x)) #---Stunt Class----------------------------------------------------------------- APPEND='__www.stani.be__'#just an unique value APPEND_METHODS=[] class _StuntControlMethod: """Call with arguments and keywords. See Stunt class for more information. """ def __init__(self,control,method,appendMethods=APPEND_METHODS): self.method=method self.appendMethods=appendMethods self.argKey=[] def __call__(self,*arguments,**keywords): try: appendArgument=(APPEND == arguments[-1]) except: appendArgument=0 if (self.method in self.appendMethods) or appendArgument: if appendArgument: arguments=arguments[:-1] self.argKey.append((arguments,keywords)) else:self.argKey=[(arguments,keywords)] class _StuntControl: """Buffer to register all calls to dialog control methods. Useful for threads. See Stunt class for more information. """ def __init__(self,control): self.control=control self.methods={} def __getattr__(self,method): if public(method): if method not in self.methods.keys(): self.methods[method]= _StuntControlMethod(self,method) return self.methods[method] else:return self.__dict__[method] def __call__(self,containerControl): for method,StuntMethod in self.methods.items(): for arguments,keywords in StuntMethod.argKey:apply(getattr(containerControl,method),arguments,keywords) self.methods.clear() class Stunt: """Buffer to register all calls to a dialog. Usefull for threads. These actions can be applied later through for example a dialog timer event. Example: >>> dialog=Stunt() >>> dialog.gauge.SetRange(100) >>> dialog.gauge.SetValue(25) >>> dialog.label.SetValue('Hello world') >>> dialog.controls {'gauge': , 'label': } >>> dialog.controls['gauge'].methods {'SetValue': , 'SetRange': } >>> dialog.controls['gauge'].methods['SetValue'].argKey [((25,), {})] #>> dialog(wxDialog) """ def __init__(self,container=None): self.controls={} self.__container=container def __getattr__(self,control): if public(control): if control not in self.controls.keys(): self.controls[control]= _StuntControl(control) return self.controls[control] else: return self.__dict__[control] def __call__(self): "Apply Stunted methods of self to container." self.busy=1 for control,StuntControl in self.controls.items(): StuntControl(getattr(self.__container,control)) self.controls.clear() self.busy=0 def __nonzero__(self): return 1 ####FUNCTIONS------------------------------------------------------------------- def arange(start=0,stop=1,step=1): """Arbitrary range with floats""" return [x*step+start for x in range((stop-start)/step)] def assertList(x): "Force x to a list." if type(x).__name__=='list': return x else: return [x] def cgd(x,y): "Calculates common greatest denominator." max = min(x,y) result = 1 d = 2 while d <= max: while x%d == 0 and y%d == 0: result *= d x /= d y /=d d +=1 return result def distance(p1,p2): "Calculates distance between two 2d points." px=math.fabs(p1[0]-p2[0])+1 py=math.fabs(p1[1]-p2[1])+1 return math.sqrt(px*px+py*py) def flat(seq): """Flattens a sequence of sequences""" return [x for subseq in seq for x in subseq] def flatten(s): "Flattens a list." result = [] for i in s: try: result = result + flatten(i) except TypeError: result.append(i) return result def fixHmsf(x,fps=25): """Make sure a number is in 'hh:mm:ss:ff' format.""" return index2hmsf(hmsf2index(x,fps),fps) def hmsf2index(x,fps=25): """Convert frame notation into frame number x='hh:mm:ss:ff' """ x=x.split(':') if x==['']:x=[] x=[0 for a in range(4-len(x))]+[int(b) for b in x] frame=((x[0]*60+x[1])*60+x[2])*fps+x[3] return frame def index2hmsf(x,fps=25): """Convert frame notation into frame number returns 'hh:mm:ss:ff' """ return '%02i:%02i:%02i:%02i'%(x/(3600*fps),x/(60*fps)%60,x/fps%60,x%fps) def irange(start=0,stop=1,step=1): """Arbitrary range with floats, inclusive endpoint""" return [x*step+start for x in range((stop-start)/step+1)] def lrange(x): return range(len(x)) def limitRange(x,n): if n and len(x)>n: step = len(x)/float(n-2) return [x[0]]+[x[int(round(i*step)) + 1] for i in range(n-2)]+[x[-1]] else: return x def minSec(seconds): "Converts seconds to minutes:seconds string." seconds=int(seconds) return str(seconds/60)+':'+str(seconds%60) def public(x): "Returns true if string x doesn't start with '__'." return x[:2]!='__' def ratio(x,y): d = cgd(x,y) return (x/d,y/d) def rstrip(x,char=' '): try: return x.rstrip('-') except: index=len(x) try: while x>0 and x[index-1]==char: index-=1 return x[:index] except: return x def strFill(s,n): "Fills a string with n times the substring s." return ''.ljust(n).replace(' ',s) def subtract(l,m): "Subtract list m from list l" def _notCommon(x): return not(x in m) return filter(_notCommon,l) def timePassed(x): "Returns the time as a string in min and sec since x." return minSec(time.time()-x) def transpose(x): return map(None,*x) def unique(s): """Return a list of the elements in s, but without duplicates. For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], unique("abcabc") some permutation of ["a", "b", "c"], and unique(([1, 2], [2, 3], [1, 2])) some permutation of [[2, 3], [1, 2]]. For best speed, all sequence elements should be hashable. Then unique() will usually work in linear time. If not possible, the sequence elements should enjoy a total ordering, and if list(s).sort() doesn't raise TypeError it's assumed that they do enjoy a total ordering. Then unique() will usually work in O(N*log2(N)) time. If that's not possible either, the sequence elements must support equality-testing. Then unique() will usually work in quadratic time. """ n = len(s) if n == 0: return [] # Try using a dict first, as that's the fastest and will usually # work. If it doesn't work, it will usually fail quickly, so it # usually doesn't cost much to *try* it. It requires that all the # sequence elements be hashable, and support equality comparison. u = {} try: for x in s: u[x] = 1 except TypeError: del u # move on to the next method else: return u.keys() # We can't hash all the elements. Second fastest is to sort, # which brings the equal elements together; then duplicates are # easy to weed out in a single pass. # NOTE: Python's list.sort() was designed to be efficient in the # presence of many duplicate elements. This isn't true of all # sort functions in all languages or libraries, so this approach # is more effective in Python than it may be elsewhere. try: t = list(s) t.sort() except TypeError: del t # move on to the next method else: assert n > 0 last = t[0] lasti = i = 1 while i < n: if t[i] != last: t[lasti] = last = t[i] lasti = lasti+1 i = i+1 return t[:lasti] # Brute force is all that's left. u = [] for x in s: if x not in u: u.append(x) return u def zfill(x,width): try: return string.zfill(x,width) except: x=str(x) l=len(x) if width>l: return ('%0'+str(width-l)+'d%s')%(0,x) else: return x ####CONSTANTS------------------------------------------------------------------- INCH2CM=2.54 CM2INCH=1/INCH2CM MM2INCH=1/(INCH2CM*10) MONTHS=('january','february','march','april','may','june','july','august','september','october','november','december') spe-0.8.4.h/_spe/sm/__init__.py0000644000175000017500000000466610274440257015255 0ustar stanistani#(c)www.stani.be INFO={ 'author' : "www.stani.be", 'title' : "SM general python library", 'date' : "13-9-2003", 'doc' : "%(titleFull)s by %(author)s\n\n%(description)s\n\n%(links)s\n\n%(requirements)s\n\n%(copyright)s", 'version' : "1.0", 'pyVersion' : "2.2", 'wxVersion' : "2.4.1.2.", } INFO['titleFull']="%(title)s %(version)s"%INFO INFO['description']=\ """Collection of python scripts I often use.""" INFO['links']=\ """Homepage : http://www.stani.be Contact : http://www.pycs.net/system/mailto.py?usernum=0000167""" INFO['requirements']=\ """Developped with Python v%(pyVersion)s"""%INFO INFO['copyright']=\ """Copyright (C)%(author)s (%(date)s) This library (sm.*) is NOT released under the GPL, but you may use it for free and adapt it to your own needs, provided you list my name and website in the copyright."""%INFO __doc__=INFO['doc']%INFO from python import * def initHtml(): """Initializes html and css components of the sm library. >>> import sm >>> sm.initHtml() >>> print sm.html >>> print sm.css """ global html, css ## try: from htmlCss.html import html from htmlCss.css import css ## except: ## print "Sm html library is not installed on this system." def ChangeDisplaySettings(xres=None, yres=None, BitsPerPixel=None): """Changes the display resolution and bit depth on Windows.""" import ctypes import struct DM_BITSPERPEL = 0x00040000 DM_PELSWIDTH = 0x00080000 DM_PELSHEIGHT = 0x00100000 CDS_FULLSCREEN = 0x00000004 SIZEOF_DEVMODE = 148 user32 = ctypes.WinDLL('user32.dll') DevModeData = struct.calcsize("32BHH") * '\x00' DevModeData += struct.pack("H", SIZEOF_DEVMODE) DevModeData += struct.calcsize("H") * '\x00' dwFields = (xres and DM_PELSWIDTH or 0) | (yres and DM_PELSHEIGHT or 0) | (BitsPerPixel and DM_BITSPERPEL or 0) DevModeData += struct.pack("L", dwFields) DevModeData += struct.calcsize("l9h32BHL") * '\x00' DevModeData += struct.pack("LLL", BitsPerPixel or 0, xres or 0, yres or 0) DevModeData += struct.calcsize("8L") * '\x00' print dir(user32) result = user32.ChangeDisplaySettingsA(DevModeData, CDS_FULLSCREEN) return result == 0 # success if zero, some failure otherwise spe-0.8.4.h/_spe/sm/spy.py0000644000175000017500000000071710331016126014306 0ustar stanistaniimport inspect def message(level=0): text = '' frames = inspect.getouterframes(inspect.currentframe())[2:] if level==0: text += '%s\n'% ('>'.join([x[3] for x in frames])) elif level == 1: i = 0 for f in frames: if i>0:text += ' ' text += '%s %s\n'%(':'.join([str(x) for x in f[1:3]]),f[4][0].strip()) i += 1 return text def frame(level=0): print message(level)spe-0.8.4.h/_spe/sm/uml.py0000644000175000017500000004205610577063353014312 0ustar stanistaniimport os, re import wx, wx.lib.ogl as ogl INITIALIZED = False BOTTOM = 9999 DEFAULT = '-' SEPARATOR = '+' RE_PARENT = re.compile("[^(]+[(]([^)]+)[)]") ####Utilities def htmlColour(c): return ('#%2s%2s%2s'%tuple([hex(x)[2:] for x in (c.Red(),c.Green(),c.Blue())])).replace(' ','0').upper() ####Generic class Class: def __init__(self,name='class',container=[],children=[],data=None): #passing values... self.name = name self.container = container[:] self.children = children self.data = data #initialize match = RE_PARENT.match(self.name) if match: self.parents = [x.strip() for x in match.group(1).split(',')] self.hierarchy = BOTTOM self.verified = False else: self.parents = [] self.hierarchy = 0 self.verified = True def __str__(self): self.width = max([len(x) for x in [self.name]+self.container]) self.height = len(self.container)+1 entry = '| %%-%ss |'%self.width line = '+'+'-'*(self.width+2)+'+' return '\n'.join([line]+[entry%x for x in self.container]+[line]) def append(self,x,t=DEFAULT): self.container.append('%s%s'%(t,x.replace(' ',''))) def extend(self,l,t=DEFAULT): for x in l: self.append(x,t=t) def getHierarchy(self,classes): if not self.verified: parents = [classes[parent].getHierarchy(classes) for parent in self.parents if classes.has_key(parent)] if parents: self.hierarchy = max(parents)+1 else: self.hierarchy = 1 self.verified = True return self.hierarchy #---wx def wx(self,dc,canvas): width = height = 10 for x in [self.name]+self.container: w, h = dc.GetTextExtent(x) width = max(width,w) height += h return _Class(width, height, canvas, self.name, self.container) ####WxPython #---Printing support ID_Setup = wx.NewId() ID_Preview = wx.NewId() ID_Print = wx.NewId() BITMAP_TYPE = { ".bmp": wx.BITMAP_TYPE_BMP, # Save a Windows bitmap file. ".eps": None, ".gif": wx.BITMAP_TYPE_GIF, # Save a GIF file. ".jpg": wx.BITMAP_TYPE_JPEG, # Save a JPG file. ".pcx": wx.BITMAP_TYPE_PCX, # Save a PCX file. ".png": wx.BITMAP_TYPE_PNM, # Save a PNG file. ".pnm": wx.BITMAP_TYPE_PNM, # Save a PNM file. ".tif": wx.BITMAP_TYPE_TIF, # Save a TIF file. ".xbm": wx.BITMAP_TYPE_XBM, # Save an X bitmap file. ".xpm": wx.BITMAP_TYPE_XPM, # Save an XPM bitmap file. } def wxTopLevelFrame(window): while not window.IsTopLevel(): window = window.GetParent() return window def doPrint(dc,canvas): # One possible method of setting scaling factors... maxX, maxY = canvas.GetVirtualSize() # Let's have at least 50 device units margin marginX = 50 marginY = 50 # Add the margin to the graphic size maxX = maxX + (2 * marginX) maxY = maxY + (2 * marginY) # Get the size of the DC in pixels (w, h) = dc.GetSizeTuple() # Calculate a suitable scaling factor scaleX = float(w) / maxX scaleY = float(h) / maxY # Use x or y scaling factor, whichever fits on the DC actualScale = min(scaleX, scaleY) # Calculate the position on the DC for centering the graphic posX = (w - (maxX * actualScale)) / 2.0 posY = (h - (maxY * actualScale)) / 2.0 # Set the scale and origin dc.SetUserScale(actualScale, actualScale) dc.SetDeviceOrigin(int(posX), int(posY)) canvas.Redraw(dc) dc.DrawText("Drawn by SPE [http://pythonide.stani.be]", marginX/2, maxY-marginY) class PrintCanvas(ogl.ShapeCanvas): def __init__(self, *args, **keyw): #initialize global INITIALIZED if not INITIALIZED: ogl.OGLInitialize() INITIALIZED = True maxWidth = 800 maxHeight = 800 #frame ogl.ShapeCanvas.__init__(self, size=(maxWidth,maxHeight), *args, **keyw) self.frame = wxTopLevelFrame(self) self.SetScrollbars(20, 20, maxWidth/20, maxHeight/20) #Print data self.printSetup = False self.printData = wx.PrintData() self.printData.SetPaperId(wx.PAPER_A4) self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER) #events self.Bind(wx.EVT_LEFT_DCLICK, self.OnPrintPreview) self.Bind(wx.EVT_MIDDLE_DCLICK, self.OnDoSave) self.Bind(wx.EVT_RIGHT_DCLICK, self.OnPrintSetup) def _checkPrintSetup(self): if not self.printSetup: self.OnPrintSetup() def OnPrintSetup(self, event=None): data = wx.PageSetupDialogData(self.printData) printerDialog = wx.PageSetupDialog(self, data) if printerDialog.ShowModal() == wx.ID_OK: self.printData = wx.PrintData( printerDialog.GetPageSetupData().GetPrintData() ) printerDialog.Destroy() self.pageSetup = True def OnPrintPreview(self, event=None): self._checkPrintSetup() data = wx.PrintDialogData(self.printData) printout = Printout(self) printout2 = Printout(self) self.preview = wx.PrintPreview(printout, printout2, data) if not self.preview.Ok(): return frame = wx.PreviewFrame(self.preview, self.frame, "SPE - Print Preview") frame.Initialize() frame.SetPosition(self.frame.GetPosition()) frame.SetSize(self.frame.GetSize()) frame.Show(True) def OnDoPrint(self, event=None): pdd = wx.PrintDialogData(self.printData) pdd.SetToPage(2) printer = wx.Printer(pdd) printout = Printout(self) if not printer.Print(self.frame, printout, True): wx.MessageBox("Printing was cancelled.\n\nIf you didn't cancel the print, perhaps\nyour current printer is not set correctly?", "Printing", wx.OK) else: self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() ) printout.Destroy() def OnDoSave(self, event=None): self.SaveFile()#"c:\\test.png") def SaveFile(self, fileName= ''): """Saves the file to the type specified in the extension. If no file name is specified a dialog box is provided. Returns True if sucessful, otherwise False. .bmp Save a Windows bitmap file. .xbm Save an X bitmap file. .xpm Save an XPM bitmap file. .png Save a Portable Network Graphics file. .jpg Save a Joint Photographic Experts Group file. """ fileTypes = BITMAP_TYPE.keys() fileTypes.sort() ext = fileName[-3:].lower() if ext not in fileTypes: dlg1 = wx.FileDialog( self, "Save image as", ".", "", "|".join(["%s files (*%s)|*%s"%(t.upper(),t,t) for t in fileTypes]), wx.SAVE|wx.OVERWRITE_PROMPT ) if dlg1.ShowModal() == wx.ID_OK: fileName = dlg1.GetPath() # Check for proper exension ext = os.path.splitext(fileName)[-1] if ext not in fileTypes: ext = fileTypes[dlg1.GetFilterIndex()] fileName+=ext dlg1.Destroy() else: # exit without saving dlg1.Destroy() return False tp = BITMAP_TYPE[ext] # Save... w, h = self.GetVirtualSize() if tp: #...as bitmap dc = wx.MemoryDC() bitmap = wx.EmptyBitmap(w+10,h+10) dc.SelectObject(bitmap) dc.SetBackground(wx.WHITE_BRUSH) dc.Clear() self.Redraw(dc) return bitmap.SaveFile(fileName, tp) else: #... as postscript printData = wx.PrintData() printData.SetFilename(fileName) dc = wx.PostScriptDC(printData) if dc.Ok(): dc.StartDoc('Saving as postscript') doPrint(dc,self) #self.Redraw(dc) dc.EndDoc() class Printout(wx.Printout): def __init__(self, canvas): wx.Printout.__init__(self) self.canvas = canvas def OnBeginDocument(self, start, end): return self.base_OnBeginDocument(start, end) def OnEndDocument(self): self.base_OnEndDocument() def OnBeginPrinting(self): self.base_OnBeginPrinting() def OnEndPrinting(self): self.base_OnEndPrinting() def OnPreparePrinting(self): self.base_OnPreparePrinting() def HasPage(self, page): if page <= 2: return True else: return False def GetPageInfo(self): return (1, 2, 1, 2) def OnPrintPage(self, page): dc = self.GetDC() doPrint(dc,self.canvas) return True #---General def wxAssertColour(c): name = htmlColour(c) wx.TheColourDatabase.AddColour(name,c) return name class _EvtHandler(ogl.ShapeEvtHandler): def __init__(self, frame): ogl.ShapeEvtHandler.__init__(self) self.statbarFrame = frame def OnLeftClick(self, x, y, keys=0, attachment=0): shape = self.GetShape() canvas = shape.GetCanvas() dc = wx.ClientDC(canvas) canvas.PrepareDC(dc) if shape.Selected(): shape.Select(False, dc) canvas.Redraw(dc) else: shapeList = canvas.GetDiagram().GetShapeList() toUnselect = [] for s in shapeList: if s.Selected(): # If we unselect it now then some of the objects in # shapeList will become invalid (the control points are # shapes too!) and bad things will happen... toUnselect.append(s) shape.Select(True, dc) if toUnselect: for s in toUnselect: s.Select(False, dc) canvas.Redraw(dc) def OnEndDragLeft(self, x, y, keys=0, attachment=0): shape = self.GetShape() ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment) if not shape.Selected(): self.OnLeftClick(x, y, keys, attachment) def OnSizingEndDragLeft(self, pt, x, y, keys, attch): ogl.ShapeEvtHandler.OnSizingEndDragLeft(self, pt, x, y, keys, attch) def OnMovePost(self, dc, x, y, oldX, oldY, display): ogl.ShapeEvtHandler.OnMovePost(self, dc, x, y, oldX, oldY, display) def OnRightClick(self, dc, *dontcare): pass class _Class(ogl.DividedShape): def __init__(self, width, height, canvas, name, container, lineColour=wx.Colour(80,80,80), textColour=wx.Colour(0,0,0), pen=wx.BLACK_PEN,brush=wx.LIGHT_GREY_BRUSH): #initialize ogl.DividedShape.__init__(self, width, height) self.lineColour = wxAssertColour(lineColour) self.textColour = wxAssertColour(textColour) self.width = width self.height = height self.SetPen(pen) self.SetBrush(brush) #generate contents total = float(len(container))+1 current = 0 text = '' self.AddText(name,prop=1/total, textColour=wx.RED,format=ogl.FORMAT_CENTRE_HORIZ) for entry in container: if entry[0] == SEPARATOR: self.AddText(text,prop=current/total) self.AddText(entry[1:],prop=1/total, textColour=wx.Colour(0,0,200),format=ogl.FORMAT_CENTRE_HORIZ) text = '' current = 0 else: text = '%s%s\n'%(text,entry[1:]) current +=1 self.AddText(text,prop=current/total) self.SetRegionSizes() self.ReformatRegions(canvas) def AddText(self,text,lineColour=None,textColour=None,prop=0.1,format=ogl.FORMAT_NONE): if text: region = ogl.ShapeRegion() if lineColour: region.SetPenColour(wxAssertColour(lineColour)) else: region.SetPenColour(self.lineColour) if textColour: region.SetColour(wxAssertColour(textColour)) else: region.SetColour(self.textColour) region.SetText(text) region.SetProportions(0.0, prop) region.SetFormatMode(format) self.AddRegion(region) def Goto(self,x,y): self.SetX(x+self.width/2) self.SetY(y+self.height/2) def OnSizingEndDragLeft(self, pt, x, y, keys, attch): ogl.DividedShape.OnSizingEndDragLeft(self, pt, x, y, keys, attch) self.SetRegionSizes() self.ReformatRegions() self.GetCanvas().Refresh() def ReformatRegions(self, canvas=None): rnum = 0 if canvas is None: canvas = self.GetCanvas() dc = wx.ClientDC(canvas) # used for measuring for region in self.GetRegions(): text = region.GetText() self.FormatText(dc, text, rnum) rnum += 1 #class Canvas(ogl.ShapeCanvas): class Canvas(PrintCanvas): def __init__(self, parent,**keyw): PrintCanvas.__init__(self, parent,**keyw) self.parent = parent self.SetBackgroundColour(wx.WHITE) self.diagram = ogl.Diagram() self.SetDiagram(self.diagram) self.diagram.SetCanvas(self) self.shapes = [] self.save_gdi = [] self.__test__() def __test__(self): u = Class() u.append('mmmm') u.append('test') u.append('test') u.append('test') u.append('haha',SEPARATOR) u.append('test') u.append('test') u.append('test') self.DrawUml(classes={'u':u,'v':u}) return True ## def OnDoPrint(self,event=None): ## self.GetParent().OnPrintPreview(None) ## def DrawUml(self,classes={},between=20): """Draws the uml diagram""" #verify all hierachies rows = [[] for x in range(len(classes)+2)] for name, u in classes.items(): if not u.verified: u.getHierarchy(classes) rows[u.hierarchy].append(u) #draw uml shapes = {} dc = wx.ClientDC(self) self.PrepareDC(dc) self.diagram.DeleteAllShapes() total_height = total_width = y = between for row in rows: if row: x = between height = 0 for u in row: shape = u.wx(dc,self) shapes[u.name.split('(')[0]] = shape self.__addShape(shape, x, y, '') x += between+shape.width height = max(height,shape.height) for parent in u.parents: if shapes.has_key(parent): line = ogl.LineShape() line.SetCanvas(self) line.SetPen(wx.BLACK_PEN) line.SetBrush(wx.BLACK_BRUSH) line.AddArrow(ogl.ARROW_ARROW) line.MakeLineControlPoints(2) shapes[parent].AddLine(line, shape) self.diagram.AddShape(line) line.Show(True) width = int(x+between) height = int(height+3*between) total_width = max(width,total_width) y += height total_height+= height total_height -= 3*between self.SetVirtualSize((total_width, total_height)) self.SetScrollRate(20,20) def __addShape(self, shape, x, y, text): if isinstance(shape, ogl.CompositeShape): dc = wx.ClientDC(self) self.PrepareDC(dc) shape.Move(dc, x, y) else: shape.SetDraggable(True, True) shape.SetCanvas(self) shape.Goto(x,y) if text: for line in text.split('\n'): shape.AddText(line) shape.SetShadowMode(ogl.SHADOW_RIGHT) self.diagram.AddShape(shape) shape.Show(True) evthandler = _EvtHandler(self) evthandler.SetShape(shape) evthandler.SetPreviousHandler(shape.GetEventHandler()) shape.SetEventHandler(evthandler) self.shapes.append(shape) return shape def OnBeginDragLeft(self, x, y, keys): pass def OnEndDragLeft(self, x, y, keys): pass if __name__=='__main__': import wxp wxp.panelApp(Canvas) spe-0.8.4.h/_spe/sm/osx.py0000644000175000017500000002653010707137672014326 0ustar stanistani#(c)www.stani.be (read __doc__ for more information) import os import sm INFO=sm.INFO.copy() INFO['description']=\ """eXtended os related scripts. Changes: - 2003/10/08: New userPath function by Greg Brunet - 2003/09/25: Added userPath function from Andrei (http://come.to/project5)""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________ ####IMPORT---------------------------------------------------------------------- import os,time,shutil,string, stat ####CLASSES--------------------------------------------------------------------- displayTitle=1 class TitleTimer: """Display the time left in mm:ss in the title of the console window.""" def __init__(self,total,refresh=1,title=0): self.total=total self.refresh=refresh self.current=0 self.alarm = self.start=time.time() self.alarm =self.alarm+refresh self.title=title def tick(self,current=None,comment=""): "" if current: self.current=current else: self.current= self.current+1 if time.time()>self.alarm: self.alarm=time.time() seconds=int((self.alarm-self.start)*(self.total-self.current)/self.current) self.alarm=self.alarm+self.refresh message=str(seconds/60)+':'+string.zfill(seconds%60,2)+comment if self.title: self.title.SetLabel(message) elif displayTitle: os.system('title "'+message+'"') else: print message ####FUNCTIONS------------------------------------------------------------------- def copydirs(base,to,ignore=[]): "Copy one level of empty directories." baseDirs=listdir(base,"folder") ignore.extend(listdir(to,"folder")) for dir in baseDirs: if not(dir in ignore): os.mkdir(to+"/"+dir) def copyPython(srcPy,dstPy): f=file(srcPy,'r') script='\n'.join([line.rstrip() for line in f.readlines()]) f.close() f=file(dstPy,'w') f.write(script) f.close() def copytree(src, dst, symlinks=0,extensions=None,excludePrefixFolders=''): """Recursively copy a directory tree using copy2(). The destination directory CAN ALREADY EXIST. Error are reported to standard output. If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic links are copied. XXX Consider this example code rather than the ultimate tool. """ names = os.listdir(src) try:os.mkdir(dst) except:pass ex=len(excludePrefixFolders) for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: if symlinks and os.path.islink(srcname): linkto = os.readlink(srcname) os.symlink(linkto, dstname) elif os.path.isdir(srcname): if not ex or (ex and name[:ex]!=excludePrefixFolders): copytree(srcname, dstname, symlinks, extensions, excludePrefixFolders) elif extensions: extension=os.path.splitext(name)[-1].lower() if extension in extensions: if extension in ['.py','.pyw']: copyPython(srcname, dstname) else: shutil.copy2(srcname, dstname) else: shutil.copy2(srcname, dstname) # XXX What about devices, sockets etc.? except (IOError, os.error), why: print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why)) def filterByExtension(fileList,extensions): "Filters file list by a list of lowercase extensions." extensions=sm.assertList(extensions) return [f for f in fileList if os.path.splitext(f)[1].lower() in extensions] def listdir(dir='', extensions=[],absPath=0,recursive=0, excludeFolders=[],excludePrefixFolders='',normcase=0): """Directory listings with options for extension and folder filtering. Parameter: - extensions: list of file extensions or 'folder' for folders only - ... """ folders= extensions=="folder" or extensions=="folders" try: fileList=os.listdir(dir) except: return [] if normcase:fileList = map(os.path.normcase,fileList) fileList.sort() if absPath or folders or recursive:fileList= [os.path.join(dir, f) for f in fileList] if folders or recursive: folderList=filter(os.path.isdir,fileList) if recursive and folderList: recursiveList=[] ex=len(excludePrefixFolders) for folder in folderList: baseFolder=os.path.basename(folder) if (baseFolder not in excludeFolders) or\ (ex and baseFolder[:ex]==excludePrefixFolders): recursiveList+=listdir(folder,extensions=extensions, absPath=absPath,recursive=recursive-1) else:recursiveList=[] if folders: if absPath: return folderList+recursiveList else: return map(os.path.basename,folderList)+recursiveList elif extensions==[]: return fileList+recursiveList else: return filterByExtension(fileList,extensions)+recursiveList def lastModified(fileName): return os.stat(fileName)[stat.ST_MTIME] def mkdir(x): try: os.mkdir(x) return 1 except: return 0 def newer(f1,f2): return os.path.exists(f2) and lastModified(f1) > lastModified(f2) def listdirR(folder,recursion=0,extensions=None,absolute=1): """List recursively all files with a certain extension and limited recursion depth.""" files=[os.path.join(folder,file) for file in os.listdir(folder)] result=[file for file in files if not os.path.isdir(file) and\ (not extensions or os.path.splitext(file)[-1].lower() in extensions)] if recursion: for folder in files: if os.path.isdir(folder): result.extend(listdirR(folder,recursion-1,extensions)) if not absolute:result=[os.path.basename(x) for x in result] return result def pathSplit(f): "Splits into path,basename,extension." s=os.path.split(f) t=string.split(s[1],".") return (s[0],t[0],t[1]) def dirSplit(f): """Splits its directory in a list of all subdirectories. Example: >>> dirSplit('d:\\hello\\world\\readme.txt') ['d:', 'hello', 'world'] """ return os.path.dirname(f).replace('\\','/').split('/') def title(t): "Set the title of the console window." if displayTitle: os.system('title '+t) def treeDir(path='',extensions=[],ignore=[],ignorePathPrefix='\\'): dir=[os.path.join(path,x) for x in os.listdir(path)] return (path, [treeDir(x,extensions,ignore,ignorePathPrefix) for x in dir if os.path.isdir(x) and not((os.path.basename(x) in ignore) or (os.path.basename(x)[:len(ignorePathPrefix)]==ignorePathPrefix)) ]+ [x for x in dir if (not os.path.isdir(x)) and (not extensions or os.path.splitext(x)[1].lower() in extensions)]) def rmtree(p,output=0): "Tries to remove a directory tree, otherwise print warning." try:shutil.rmtree(p) except: if output:print " - Can't remove path",p ##def userPath(dirname=''): ## """Improved function to get user path (c) Andrei http://come.to/project5""" ## savedir = os.path.expanduser(os.path.join('~',dirname)) ## if len(savedir)<=len("c:\\/"+dirname): # sometimes $HOME points to root ## # if this is the case, try using $USERPROFILE (see docstring) ## temp = os.path.join(os.path.expandvars('$USERPROFILE'), dirname) ## # if this is a different location, use it! ## if temp > len("C:\\/"+dirname): ## savedir = temp ## return savedir def userPath(dirname=''): """'safer' function to find user path.""" # 'safer' function to find user path: look for one of these directories try: path = os.path.expanduser("~") if os.path.isdir(path): return os.path.join(path, dirname) except: pass for evar in ('HOME', 'USERPROFILE', 'TMP'): try: path = os.environ[evar] if os.path.isdir(path): return os.path.join(path, dirname) except: pass #if no match found, use module directory return os.path.join(os.path.dirname(os.path.abspath(__file__)), dirname) def startAppleScript(commandList, activateFlag = True): """Start a list of commands in the terminal window. Each command is a list of program name, parameters. Handles the quoting properly through shell, applescript and shell again. """ def adjustParameter(parameter): """Adjust a parameter for the shell. Adds single quotes, unless the parameter consists of letters only (to make shell builtins work) or if the parameter is a list (to flag that it already is list a parameters). """ if isinstance(parameter, list): return parameter[0] if parameter.isalpha(): return parameter #the single quote proper is replaced by '\'' since #backslashing a single quote doesn't work inside a string return "'%s'"%parameter.replace("'",r"'\''") command = ';'.join([ ' '.join([ adjustParameter(parameter) for parameter in command ]) for command in commandList ]) #make Applescript string from this command line: #put backslashes before double quotes and backslashes command = command.replace('\\','\\\\').replace('"','\\"') #make complete Applescript command containing this string command = 'tell application "Terminal" to do script "%s"'%command #make a shell parameter (single quote handling as above) command = command.replace("'","'\\''") #make complete shell command command = "osascript -e '%s'"%command #prepend activate command if needed if activateFlag: command = "osascript -e 'tell application \"Terminal\" to activate';"+command #go! os.popen(command) #---registry-------------------------------------------------------------------- def registerFileCreate(label, action, fileType='Python.File'): try: import _winreg reload(_winreg) key='%s\\shell\\%s'%(fileType,label) key=_winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT,key) except: pass try: print (key,"command",_winreg.REG_SZ,action+' "%1"') _winreg.SetValue(key,"command",_winreg.REG_SZ,action+' "%1"') return 1 except: return None def registerPy(label, action, fileType='Python.File'): """action is a python file""" import sys action='"%s" "%s"'%(os.path.join(sys.exec_prefix,"pythonw.exe"),action) return registerFileCreate(label=label,action=action,fileType=fileType) def registerFileDelete(label, fileType='Python.File'): try: import _winreg reload(_winreg) key='%s\\shell\\%s'%(fileType,label) _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,key+'\\command') except: pass try: _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,key) return 1 except: return None ####CONSTANTS------------------------------------------------------------------ NOT_FILE_CHARS=['\\','/','<','>','"','|','?',':','*'] if __name__=='__main__': print treeDir('c:/temp','PACK') spe-0.8.4.h/_spe/sm/scriptutils.py0000644000175000017500000002157010573577416016106 0ustar stanistani#(c)www.stani.be (read __doc__ for more information) import sm INFO=sm.INFO.copy() INFO['author'] = 'Mark Hammond' INFO['copyright'] = '(c) Mark Hammond (See PythonWin distribution)' INFO['title'] = INFO['titleFull'] = 'scriptutils' INFO['description'] =\ """Changes: - may 2003: www.stani.be to make it platform and PythonWin independent. """ __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import string,os,sys,types import __main__ #---run: from pywin.framework.scriptutils (c)Mark Hammond----------------------- def run(fileName=None,source=None,mainDict=__main__.__dict__,profiling=0): import traceback print bWorked = 0 exitCode = 0 osPath=None try: if fileName: path, base = os.path.split(fileName) if path: if path not in sys.path:sys.path.insert(0,path) osPath = os.getcwd() os.chdir(path) if source: if type(source) == types.UnicodeType: source = source.encode(sys.getdefaultencoding(),'replace') source = '__name__="__main__"\n%s'%source fileName = base = '' else: f = open(fileName,'r') source = f.read() f.close() if type(source) == types.UnicodeType: source = source.encode(sys.getdefaultencoding(),'replace') codeObject = compile(source.replace('\r\n','\n')+"\n", fileName, "exec") if profiling: import profile, pstats prof = profile.Profile() mainDict['codeObject'] = codeObject prof = prof.runctx('exec codeObject in mainDict', locals(), mainDict) stats = pstats.Stats(prof) stats.sort_stats('cum','time').print_stats() else: exec codeObject in mainDict bWorked = 1 except SystemExit, code: exitCode = code bWorked = 1 except KeyboardInterrupt: traceback.print_exc() bWorked = 1 except: traceback.print_exc() try: sys.stdout.flush() except AttributeError: pass if bWorked: print "Script '%s' returned exit code %s" %(base, exitCode) else: print 'Exception raised while running script %s' % base if osPath: os.chdir(osPath) #---Import Module: from pywin.framework.scriptutils (c)Mark Hammond------------ def importMod(pathName,mainDict=None): import os,string,sys,__main__ print # If already imported, dont look for package path, modName = os.path.split(pathName) modName, modExt = os.path.splitext(modName) newPath = None for key, mod in sys.modules.items(): if hasattr(mod, '__file__'): fname = mod.__file__ base, ext = os.path.splitext(fname) if string.lower(ext) in ['.pyo', '.pyc']: ext = '.py' fname = base + ext if os.path.abspath(fname)==os.path.abspath(pathName): modName = key break else: # for not broken modName, newPath = GetPackageModuleName(pathName) if newPath and newPath not in sys.path: sys.path.insert(0,newPath) if sys.modules.has_key(modName): bNeedReload = 1 what = "reload" else: what = "import" bNeedReload = 0 try: # always do an import, as it is cheap is already loaded. This ensures # it is in our name space. if path not in sys.path:sys.path.append(path) codeObj = compile('import '+modName,'','exec') if not mainDict:mainDict=__main__.__dict__ exec codeObj in mainDict if bNeedReload: reload(sys.modules[modName]) print 'Successfully ' + what + 'ed module "'+modName+'"' except Exception,message: print 'Failed to ' + what + ' module "'+modName+'" (%s)'%message def GetPackageModuleName(fileName): """Given a filename, return (module name, new path). eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path. If no package found, will return ("my", "c:\a\b\c") """ import os,string path, fname = os.path.split(fileName) origPath=path fname = os.path.splitext(fname)[0] modBits = [] newPathReturn = None if not IsOnPythonPath(path): # Module not directly on the search path - see if under a package. while len(path)>3: # ie 'C:\' path, modBit = os.path.split(path) modBits.append(modBit) # If on path, _and_ existing package of that name loaded. if IsOnPythonPath(path) and sys.modules.has_key(modBit) and \ ( os.path.exists(os.path.join(path, '__init__.py')) or \ os.path.exists(os.path.join(path, '__init__.pyc')) or \ os.path.exists(os.path.join(path, '__init__.pyo')) \ ): modBits.reverse() return string.join(modBits, ".") + "." + fname, newPathReturn # Not found - look a level higher else: newPathReturn = origPath return fname, newPathReturn def IsOnPythonPath(path): "Given a path only, see if it is on the Pythonpath. Assumes path is a full path spec." # must check that the command line arg's path is in sys.path import os,sys for syspath in sys.path: try: # Python 1.5 and later allows an empty sys.path entry. if syspath:# and os.path.abspath(syspath)==os.path.normpath(path): return 1 except Exception, details: print "Warning: The sys.path entry '%s' is invalid\n%s" \ % (syspath, details) return 0 #---CheckFile: from pywin.framework.scriptutils (c)Mark Hammond---------------- import os,sys,traceback #some improvised helper functions to make it environment independent def smPrintStatus(x): print x def smJumpToPosition(fileName, lineno, col = 1): print '-> fileName = "%s", lineno = %s, col = %s'%(fileName, lineno, col) #adapted from pywin.framework def CheckFile(pathName,source=None,status=smPrintStatus,jump=smJumpToPosition): """ This code looks for the current window, and gets Python to check it without actually executing any code (ie, by compiling only) status: function to set statusbar, otherwise print jump: function(fileName, lineno, col = 1) """ what='check' status(what+'ing module...') if not source: try: f = open(pathName) except IOError, details: print "Can't open file '%s' - %s" % (pathName, details) return try: source = f.read() finally: f.close() code=source.replace('\r\n','\n') + "\n" try: codeObj = compile(code, pathName,'exec') if RunTabNanny(pathName,status=status,jump=jump): status("Python and the TabNanny successfully checked the file '"+ os.path.basename(pathName)+"'") return 1 except SyntaxError: _HandlePythonFailure(what, pathName,status=status,jump=jump) except: traceback.print_exc() _HandlePythonFailure(what,status=status,jump=jump) def RunTabNanny(filename,status=smPrintStatus,jump=smJumpToPosition): try: import cStringIO, tabnanny except Exception, message: print message # Capture the tab-nanny output newout = cStringIO.StringIO() old_out = sys.stderr, sys.stdout sys.stderr = sys.stdout = newout try: tabnanny.check(filename) finally: # Restore output sys.stderr, sys.stdout = old_out data = newout.getvalue() if data: try: lineno = string.split(data)[1] lineno = int(lineno) status("The TabNanny found trouble at line %d" % lineno) jump(filename, lineno) except (IndexError, TypeError, ValueError): print "The tab nanny complained, but I cant see where!" print data return 0 return 1 def _HandlePythonFailure(what, syntaxErrorPathName = None,status=smPrintStatus, jump=smJumpToPosition): typ, details, tb = sys.exc_info() if typ == SyntaxError: try: msg, (fileName, line, col, text) = details if (not fileName or fileName in ["",""]) \ and syntaxErrorPathName: fileName = syntaxErrorPathName jump(fileName, line, col) except (TypeError, ValueError): msg = str(details) status('Failed to ' + what + ' - syntax error - %s' % msg) else: traceback.print_exc() status('Failed to ' + what + ' - ' + str(details) ) tb = None # Clean up a cycle. spe-0.8.4.h/_spe/sm/wxp/0000755000175000017500000000000011004131463013732 5ustar stanistanispe-0.8.4.h/_spe/sm/wxp/pil.py0000644000175000017500000000262410515765540015113 0ustar stanistaniimport wx import Image # Only if you need and use the PIL library. def bitmap2pil(bitmap): return imageToPil(bitmap2image(bitmap)) def bitmap2image(bitmap): return wx.ImageFromBitmap(bitmap) def pil2bitmap(pil): return image2bitmap(pil2image(pil)) def pil2image(pil): image = wx.EmptyImage(pil.size[0], pil.size[1]) image.SetData(pil.convert('RGB').tostring()) return image def pil2dc(pil): dc = wx.MemoryDC() dc.SelectObject(pil2bitmap(pil)) return dc def image2pil(image): pil = Image.new('RGB', (image.GetWidth(), image.GetHeight())) pil.fromstring(image.GetData()) return pil def image2bitmap(image): return image.ConvertToBitmap() ## Conversions among wxImage, wxBitmap, wxCursor, wxIcon and DATA ## wxImage to wxBitmap -- myWxImage.ConvertToBitmap() or wxBitmapFromImage(myWxImage) ## wxImage to DATA -- myWxImage.GetData() returning a string in width * height * 3 format ## DATA to wxImage -- image = wxImage(); image.SetData( data ) where data is a Python string of length width * height * 3. ## DATA to wxBitmap -- Go through wxImage to get to wxBitmap. ## DATA to wxIcon -- Should be possible, but I don't see an overloaded-constructor name for it. ## wxIcon to wxBitmap -- bitmap = wxEmptyBitmap( icon.GetWidth(), icon.GetHeight()); bitmap.CopyFromIcon( icon ) spe-0.8.4.h/_spe/sm/wxp/__init__.py0000644000175000017500000003741310365020320016051 0ustar stanistani#(c)www.stani.be (read __doc__ for more information) import os, types, sys import sm INFO=sm.INFO.copy() INFO['author'] = 'www.wxpython.org' INFO['copyright'] = '(c) www.wxpython.org' INFO['title'] = INFO['titleFull'] = 'wxPython source code' INFO['description'] =\ """Changes: may 2003: adapted by www.stani.be for spe """ __doc__=INFO['doc']%INFO #_______________________________________________________________________________ try: True except NameError: True = 1==1 False = 1==0 #===Constants================================================================== MODULE_ERROR="Error: Module(s) %s required, but not installed (%s)!" WXPYTHON_URL="www.wxpython.org" #===wxPython: dirDialog======================================================== wx=crust=shell=filling=None#for the demo down import wx from wx.py import crust,shell, filling #---Dialogs class FileDir: def getFile(self,control, style = wx.OPEN|wx.DD_NEW_DIR_BUTTON): default = control.GetValue() if not default: default = "D:\\" defaultDir, defaultFile = os.path.split(default) dlg = wx.FileDialog(self,defaultDir = defaultDir, defaultFile = defaultFile, style = style) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() control.SetValue(path) dlg.Destroy() def getDir(self,control,style=wx.DD_NEW_DIR_BUTTON): path = control.GetValue() if not path: path = "D:\\" if not os.path.isfile(path): path = os.path.dirname(path) dlg = wx.DirDialog(self,defaultPath=os.path.dirname(path) ,style=style) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() control.SetValue(path) dlg.Destroy() def fileDialog(defaultPath='',defaultFile='',message='www.stani.be', wildcard = "*.*",open=1,readOnly=1,overwrite=0,multiple=0,changeDir=0): """Launchs file selector dialog.""" style=wx.OPEN ## if open: style|=wx.OPEN ## else: style|=wx.SAVE ## if not readOnly: style|=wx.HIDE_READONLY ## if not overwrite: style|=wx.OVERWRITE_PROMPT ## if multiple: style|=wx.MULTIPLE ## if changeDir: style|=wx.CHANGE_DIR dlg=wx.FileDialog(None, message = message, defaultDir = defaultPath, defaultFile = defaultFile, wildcard = wildcard, style = style) print dlg.ShowModal if dlg.ShowModal() == wx.ID_OK:path=dlg.GetFileName() else:path='' dlg.Destroy() return path def dirDialog(defaultPath='',message="www.stani.be",newDir=1): """Launchs a directory selector dialog (wxpython).""" style=wx.DEFAULT_DIALOG_STYLE if newDir:style|=wx.DD_NEW_DIR_BUTTON dlg = wx.DirDialog(None,message=message,defaultPath=defaultPath,style=style) if dlg.Show() == wx.ID_OK:path=dlg.GetPath() else:path='' dlg.Destroy() return path def browse(object,parent=None): """Browse object with pyfilling""" from wx.py.filling import FillingFrame filling=FillingFrame(parent=parent, id=-1, title='PyFilling', pos=wx.DefaultPosition, size=wx.Size(600,300), style=wx.DEFAULT_FRAME_STYLE, rootObject=object, rootLabel=str(object), rootIsNamespace=0, static=0) filling.Show(1) def message(message='',caption='www.stani.be'): dlg = wx.MessageDialog(None, message=message,caption=caption, style=wx.OK ) #wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() #---Bitmaps, Icons & Images def bitmap2Icon(bitmap): icon = wx.EmptyIcon() icon.CopyFromBitmap(bitmap) return icon #---PyCrust class SmFilling(filling.Filling): """Tweaked PyCrust Filling based on wxSplitterWindow.""" def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SP_3D, name='Filling Window', rootObject=None, rootLabel=None, rootIsNamespace=0, static=False,filling=filling,welcome=""): """Create a PyCrust Filling instance.""" wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name) self.tree = filling.FillingTree(parent=self, rootObject=rootObject, rootLabel=rootLabel, rootIsNamespace=rootIsNamespace, static=static) self.text = filling.FillingText(parent=self, static=static) self.SplitVertically(self.tree, self.text, 200) self.SetMinimumPaneSize(1) # Override the filling so that descriptions go to FillingText. self.tree.setText=self.setText #---custom--- self.welcome=welcome self._max=1000 self.rootObject=rootObject # Display the root item. ## self.tree.SelectItem(self.tree.root) #self.tree.display() def setText(self,text): obj = self.tree.GetPyData(self.tree.item) if obj==self.rootObject:self.text.SetText(self.welcome) else: if type(obj) in [types.DictionaryType,types.ListType,types.DictType]\ and len(text)>self._max: text=text[:self._max]+' ...\n\nExplore nodes to see more information.' self.text.SetText(text) class SmCrust(crust.Crust): """Crust Crust based on wxSplitterWindow.""" name = 'SmCrust Crust' revision = crust.__revision__ def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SP_3D, name='Crust Window', rootObject=None, rootLabel=None, rootIsNamespace=True, intro='', locals=None, InterpClass=None, crust=crust, tabs={},welcome="",*args, **kwds):#custom """Create a PyCrust Crust instance.""" wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name) self.shell = crust.Shell(parent=self, introText=intro, locals=locals, InterpClass=InterpClass, *args, **kwds) self.editor = self.shell self.notebook = wx.Notebook(parent=self, id=-1) ## self.shell.interp.locals['notebook'] = self.notebook #Namespace if rootObject is None: rootObject = self.shell.interp.locals self.filling = SmFilling(parent=self.notebook, rootObject=rootObject, rootLabel=rootLabel, rootIsNamespace=rootIsNamespace, welcome=welcome) self.notebook.AddPage(page=self.filling, text='Namespace', select=True) #custom start tabKeys=tabs.keys() tabKeys.sort() for tab in tabKeys: tabItem=tabs[tab] if type(tabs[tab]).__name__ in ['tuple','list']: tabObject=tabItem[0] tabWelcome=tabItem[1] if len(tabItem)>2:tabLabel=tabItem[2] else:tabLabel='Ingredients' else: tabObject=tabItem tabWelcome="" tabLabel='Ingredients' tabFilling=SmFilling(parent=self.notebook, rootObject=tabObject, rootLabel=tabLabel, rootIsNamespace=rootIsNamespace, welcome=tabWelcome ) self.notebook.AddPage(page=tabFilling, text=tab, select=False) #custom end--- #Display #self.display = crust.Display(parent=self.notebook) #self.notebook.AddPage(page=self.display, text='Display') #SessionListing self.sessionlisting = crust.SessionListing(parent=self.notebook) self.notebook.AddPage(page=self.sessionlisting, text='Session') #Calltip self.calltip = crust.Calltip(parent=self.notebook) self.notebook.AddPage(page=self.calltip, text='Calltip') self.dispatcherlisting = crust.DispatcherListing(parent=self.notebook) self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher') #This is not necessary--- ## from wxd import wx_ ## self.wxdocs = SmFilling(parent=self.notebook, ## rootObject=wx_, ## rootLabel='wx', ## rootIsNamespace=False, ## static=True) ## self.notebook.AddPage(page=self.wxdocs, text='wxPython Docs') ## from wxd import stc_ ## self.stcdocs = SmFilling(parent=self.notebook, ## rootObject=stc_.StyledTextCtrl, ## rootLabel='StyledTextCtrl', ## rootIsNamespace=False, ## static=True) ## self.notebook.AddPage(page=self.stcdocs, text='StyledTextCtrl Docs') self.SplitHorizontally(self.shell, self.notebook, 300) self.SetMinimumPaneSize(1) class SmCrustFrame(crust.CrustFrame): """Frame containing all the PyCrust components.""" name = 'PyCrust Frame' revision = crust.__revision__ def __init__(self, parent=None, id=-1, title='PyCrust tweaked by www.stani.be', pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, rootObject=None, rootLabel=None, rootIsNamespace=True, locals=None, InterpClass=None, crust=crust,tabs={},*args, **kwds):#custom """Create a PyCrust CrustFrame instance.""" wx.Frame.__init__(self, parent, id, title, pos, size, style) intro = 'PyCrust %s - The Flakiest Python Shell' % crust.VERSION intro += '\nSponsored by Orbtech - ' intro += 'Your source for Python programming expertise.' self.CreateStatusBar() self.SetStatusText(intro.replace('\n', ', ')) import images self.SetIcon(images.getPyCrustIcon()) self.crust = SmCrust(parent=self, intro=intro, rootObject=rootObject, rootLabel=rootLabel, rootIsNamespace=rootIsNamespace, locals=locals, InterpClass=InterpClass, tabs=tabs,*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.crust.shell.setStatusText = self.SetStatusText # Fix a problem with the sash shrinking to nothing. self.crust.filling.SetSashPosition(200) ## self.createMenus() ## wx.EVT_CLOSE(self, self.OnCloseWindow) # Set focus to the shell editor. self.crust.shell.SetFocus() def Browser(self): from wxPython.lib.activexwrapper import MakeActiveXClass import win32com.client.gencache try: browserModule = win32com.client.gencache.EnsureModule("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1) except: raise ImportError("IE4 or greater does not appear to be installed.") return MakeActiveXClass(browserModule.WebBrowser,eventObj = self) #---Frames class Motion: def __init__(self): wx.EVT_LEFT_DOWN(self,self.onLeftDown) wx.EVT_RIGHT_DOWN(self,self.onRightDown) wx.EVT_MOTION(self,self.onMotion) def onLeftDown(self,event): self.dragStartPos = event.GetPosition() def onRightDown(self,event): self.Close() def onMotion(self,event): if event.Dragging(): self.SetPosition(self.GetPosition() + event.GetPosition() - self.dragStartPos) class VideoFrame(wx.Frame): """(c)Doug Holton Based on the code samples above and code by Kevin Altis. Code from: http://wiki.wxpython.org/index.cgi/IntegratingPyGame""" def play(self, filename): import sys ##Note we call the GetHandle() method of a control in the window/frame, not the wxFrame itself self.hwnd = self.GetChildren()[0].GetHandle() if sys.platform == "win32": os.environ['SDL_VIDEODRIVER'] = 'windib' os.environ['SDL_WINDOWID'] = str(self.hwnd) #must be before init ## NOTE WE DON'T IMPORT PYGAME UNTIL NOW. Don't put "import pygame" at the top of the file. import pygame pygame.display.init() self.movie = pygame.movie.Movie(filename) if self.movie.has_video(): w,h = self.movie.get_size() if w<=0 or h<=0: w,h = 1,1 else: #? need something to display if audio only. #We can't have a 0,0 canvas, pygame/SDL doesn't like that. w,h = 1,1 self.display = pygame.display.set_mode((w,h)) #size no matter self.movie.set_display(self.display) self.movie.play() class FrameApp(wx.App): def __init__(self,Frame, **keyw): self.Frame = Frame self.keyw = keyw wx.App.__init__(self, redirect=0) def OnInit(self): wx.InitAllImageHandlers() frame = self.Frame(parent=None, id=-1, **self.keyw) frame.Show(True) self.SetTopWindow(frame) self.frame = frame return True def frameApp(Frame,**keyw): application = FrameApp(Frame,**keyw) application.MainLoop() #---Html import webbrowser try: 5/0 from wx.lib.iewin import IEHtmlWindow as _HtmlWindow IE = 1 except: from wx.html import HtmlWindow as _HtmlWindow IE = 0 class HtmlWindow(_HtmlWindow): """Customized wxHtmlwindow, so that the links are opened in an external webbrowser.""" def __init__(self, parent, id, **keyw): _HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE,**keyw) def OnLinkClicked(self, linkinfo): webbrowser.open(linkinfo.GetHref(), 1) def SetPage(self,code): if IE: _HtmlWindow.LoadString(self,code) else: _HtmlWindow.SetPage(self,code) def LoadPage(self,page): if IE: _HtmlWindow.LoadUrl(self,page) else: _HtmlWindow.LoadPage(self,page) #---Panels class PanelApp(wx.App): def __init__(self, Panel, title="www.stani.be", redirect=0, ToolBar = None, icon = None,**keyw): self.Panel = Panel self.title = title self.keyw = keyw self.ToolBar = ToolBar self.icon = icon wx.App.__init__(self, redirect=redirect) def OnInit(self): wx.InitAllImageHandlers() self.frame = frame = wx.Frame(None, -1, self.title, pos=(50,50), size=(300,300), style=wx.NO_FULL_REPAINT_ON_RESIZE|wx.DEFAULT_FRAME_STYLE) if self.icon: self.SetIcon(self.icon) if self.ToolBar: frame.toolBar = self.ToolBar(parent=frame,id=-1) frame.SetToolBar(frame.toolBar) try: self.panel = panel = self.Panel(frame,id=-1,**self.keyw) except: self.panel = panel = self.Panel(frame,**self.keyw) panel.Destroy=frame.Destroy if self.ToolBar: panel.toolBar = frame.toolBar panel.toolBar.panel = panel frame.Fit() frame.Move(panel.GetPosition()) self.SetTopWindow(frame) frame.Show(True) return True def SetIcon(self,icon): self.frame.SetIcon(wx.Icon(self.icon,wx.BITMAP_TYPE_ICO)) def panelApp(Panel,title='www.stani.be',**keyw): application = PanelApp(Panel,title,**keyw) application.MainLoop() def testPanelApp(): from sm.todo.wxPanelTodo import PanelTodo as todo panelApp(todo) #---main if __name__=='__main__': testPanelApp() spe-0.8.4.h/_spe/sm/wxp/singleApp.py0000644000175000017500000000670110276752257016256 0ustar stanistani#---------------------------------------------------------------------------- # Name: ucode.py # Purpose: Single Instance App with passing arguments # Usage: see bottom of file # Author: Peter Damoc # Licence: wxWindows license #---------------------------------------------------------------------------- import wx import thread import time import sys import wx.lib.newevent import SimpleXMLRPCServer import xmlrpclib (PostArgsEvent, EVT_POST_ARGS) = wx.lib.newevent.NewEvent() class PostAppServer: def __init__(self, app): self.app = app def PostArgs(self, args): evt = PostArgsEvent(data=args) wx.PostEvent(self.app, evt) return "OK" def Stop(self): return "OK" class ArgsPosterThread: def __init__(self, app): self.app = app def Start(self): self.keepGoing = self.running = True thread.start_new_thread(self.Run, ()) def Stop(self): self.keepGoing = False server = xmlrpclib.ServerProxy("http://localhost:%d"%self.app.port) server.Stop() def IsRunning(self): return self.running def Run(self): server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", self.app.port)) server.register_instance(PostAppServer(self.app)) while self.keepGoing: server.handle_request( ) self.running = False class SingleInstanceApp(wx.App): port = 50008 def __init__(self, name,*args, **kwargs): self.name = name self.instance = wx.SingleInstanceChecker(name+wx.GetUserId()) try: self.port = kwargs.pop("port") except: pass if self.instance.IsAnotherRunning(): self.active = True server = xmlrpclib.ServerProxy("http://localhost:%d"%self.port) server.PostArgs(sys.argv[1:]) wx.App.__init__(self, *args, **kwargs) else: self.active = False self.args = sys.argv[1:] wx.App.__init__(self, *args, **kwargs) self.argsPosterThread = ArgsPosterThread(self) self.argsPosterThread.Start() def OnExit(self): if not self.active: wx.Yield() self.argsPosterThread.Stop() running = 1 while running: running = 0 print "_spe/sm/wxp/singleApp.py:78: running" running = running + self.argsPosterThread.IsRunning() time.sleep(0.1) #-------------------------------- Usage --------------------------------------- if __name__ == "__main__": class TestApp(SingleInstanceApp): def OnArgs(self, evt): self.tf.AppendText(u"\nReceived args: "+unicode(evt.data)) self.GetTopWindow().Raise() self.GetTopWindow().Iconize(False)# thanks to Alexei for pointing it out def OnInit(self): if self.active: return False else: self.Bind(EVT_POST_ARGS, self.OnArgs) self.mainFrame = wx.Frame(None, title=self.name) self.tf = wx.TextCtrl(self.mainFrame, style=wx.TE_MULTILINE) self.tf.AppendText(u"Original args: "+unicode(self.args)) self.SetTopWindow(self.mainFrame) self.mainFrame.Show() return True app = TestApp("A_simple_TestApp",0, port= 50009) app.MainLoop()spe-0.8.4.h/_spe/sm/wxp/stc.py0000644000175000017500000007533510767547632015142 0ustar stanistani#(c)www.stani.be (read __doc__ for more information) import sm INFO=sm.INFO.copy() INFO['author'] = 'Robin Dunn' INFO['date'] = 'A long time ago, in a galaxy far, far away...' INFO['copyright'] ='(c) 1999 by Total Control Software' INFO['title'] = INFO['titleFull'] = 'wxPython stc control' INFO['description']=\ """Changes: - apr 2004: + wx namespace rewrite by SM - sep 2003: + Indent/dedent fix by SM + Autocompletion keyboard generic by GF (guillermo.fernandez@epfl.ch) - may 2003: + Adapted by SM (www.stani.be) for spe to include autocompletion and callbacks """ __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import re #Original header: #------------------------------------------------------------------------------- # Author: Robin Dunn # # Created: A long time ago, in a galaxy far, far away... # Copyright: (c) 1999 by Total Control Software # Licence: wxWindows license # #------------------------------------------------------------------------------- import wx import wx.stc as wx_stc import wx.gizmos as wx_gizmos import inspect,keyword,os,sys,types #------------------------------------------------------------------------------- WORDCHARS = "_.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" #------------------------------------------------------------------------------- try: True except NameError: True = 1==1 False = 1==0 #---------------------------------------------------------------------- class PythonBaseSTC(wx_stc.StyledTextCtrl): def __init__(self, parent, id=-1,namespace={},path=None,config=None, ignore=None,menu=None): wx_stc.StyledTextCtrl.__init__(self, parent, id, style = wx.FULL_REPAINT_ON_RESIZE|wx.NO_BORDER) #PASSING VALUES self.namespace=namespace self.config=config self.ignore=ignore if path and path not in sys.path: sys.path.append(path) #INITIALIZE self.calltip = 0 #calltip counter self.menu = menu self.SetLexer(wx_stc.STC_LEX_PYTHON) #KEYBOARD SHORTCUTS (what are they doing here?) self.CmdKeyAssign(ord('B'), wx_stc.STC_SCMOD_CTRL, wx_stc.STC_CMD_ZOOMIN) self.CmdKeyAssign(ord('N'), wx_stc.STC_SCMOD_CTRL, wx_stc.STC_CMD_ZOOMOUT) #KEYPAD DEFINITIONS self.CmdKeyAssign(wx.WXK_NUMPAD_UP, 0, wx_stc.STC_CMD_LINEUP) self.CmdKeyAssign(wx.WXK_NUMPAD_DOWN, 0, wx_stc.STC_CMD_LINEDOWN) self.CmdKeyAssign(wx.WXK_NUMPAD_LEFT, 0, wx_stc.STC_CMD_CHARLEFT) self.CmdKeyAssign(wx.WXK_NUMPAD_RIGHT, 0, wx_stc.STC_CMD_CHARRIGHT) self.CmdKeyAssign(wx.WXK_NUMPAD_HOME, 0, wx_stc.STC_CMD_HOME) self.CmdKeyAssign(wx.WXK_NUMPAD_END, 0, wx_stc.STC_CMD_LINEEND) self.CmdKeyAssign(wx.WXK_NUMPAD_HOME, wx_stc.STC_SCMOD_CTRL, wx_stc.STC_CMD_DOCUMENTSTART) self.CmdKeyAssign(wx.WXK_NUMPAD_END, wx_stc.STC_SCMOD_CTRL, wx_stc.STC_CMD_DOCUMENTEND) self.CmdKeyAssign(wx.WXK_NUMPAD_PAGEUP, 0, wx_stc.STC_CMD_PAGEUP) self.CmdKeyAssign(wx.WXK_NUMPAD_PAGEDOWN, 0, wx_stc.STC_CMD_PAGEDOWN) self.CmdKeyAssign(wx.WXK_NUMPAD_INSERT, 0, wx_stc.STC_CMD_EDITTOGGLEOVERTYPE) self.CmdKeyAssign(wx.WXK_NUMPAD_DELETE, 0, wx_stc.STC_CMD_CLEAR) #PYTHON self.SetLexer(wx_stc.STC_LEX_PYTHON) keywords=keyword.kwlist keywords.extend(['None','as','True','False']) self.SetKeyWords(0, " ".join(keywords)) #GENERAL self.AutoCompSetIgnoreCase(False) #FOLDING self.SetProperty("fold", "1") self.SetProperty("tab.timmy.whinge.level", "1") self.SetProperty("fold.comment.python", "0") self.SetProperty("fold.quotes.python", "0") #USER SETTINGS if self.config: self.update() else: self.SetViewWhiteSpace(0) self.SetTabWidth(4) self.SetIndentationGuides(1) self.SetUseTabs(0) self.SetEdgeMode(wx_stc.STC_EDGE_LINE) self.SetEdgeColumn(79) self.getDefaultFaces() self.SetWordChars(WORDCHARS) self.SetStyles() self.SetBackSpaceUnIndents(1) ## self.SetTabIndents(0) ## self.SetIndent(1) self.SetEdgeColumn(79) self.SetEdgeColour(wx.Colour(200,200,200)) #MARGINS self.SetMargins(0,0) #margin 1 for line numbers self.SetMarginType(1, wx_stc.STC_MARGIN_NUMBER) if self.getint('ViewLineNumbers'): self.SetMarginWidth(1, 50) else: self.SetMarginWidth(1, 0) #margin 2 for markers self.SetMarginType(2, wx_stc.STC_MARGIN_SYMBOL) self.SetMarginMask(2, wx_stc.STC_MASK_FOLDERS) self.SetMarginSensitive(2, True) self.SetMarginWidth(2, 12) if 0: # simple folder marks, like the old version self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDER, wx_stc.STC_MARK_ARROW, "navy", "navy") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDEROPEN, wx_stc.STC_MARK_ARROWDOWN, "navy", "navy") # Set these to an invisible mark self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDEROPENMID, wx_stc.STC_MARK_BACKGROUND, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERMIDTAIL, wx_stc.STC_MARK_BACKGROUND, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERSUB, wx_stc.STC_MARK_BACKGROUND, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERTAIL, wx_stc.STC_MARK_BACKGROUND, "white", "black") else: # more involved "outlining" folder marks self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDEREND, wx_stc.STC_MARK_BOXPLUSCONNECTED, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDEROPENMID, wx_stc.STC_MARK_BOXMINUSCONNECTED, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERMIDTAIL, wx_stc.STC_MARK_TCORNER, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERTAIL, wx_stc.STC_MARK_LCORNER, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDERSUB, wx_stc.STC_MARK_VLINE, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDER, wx_stc.STC_MARK_BOXPLUS, "white", "black") self.MarkerDefine(wx_stc.STC_MARKNUM_FOLDEROPEN, wx_stc.STC_MARK_BOXMINUS, "white", "black") wx_stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI) wx_stc.EVT_STC_MARGINCLICK(self, id, self.OnMarginClick) # STYLES # Make some styles, The lexer defines what each style is used for, we # just have to define what each style looks like. This set is adapted from # Scintilla sample property files. # Default style self.StyleSetSpec(wx_stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % \ self.faces) self.StyleSetBackground(wx_stc.STC_STYLE_BRACELIGHT,"#AAAAFF") self.SetCaretForeground("BLACK") self.SetSelBackground(1,'DARK TURQUOISE') #EVENTS self.Bind(wx_stc.EVT_STC_UPDATEUI, self.OnUpdateUI) self.Bind(wx_stc.EVT_STC_MARGINCLICK, self.OnMarginClick) self.Bind(wx.EVT_CHAR, self.OnChar) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown) if wx.Platform=='__WXMAC__': self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) if self.menu: self.UsePopUp(False) if wx.Platform=='__WXMAC__': self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) else: self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick) #---events def OnLeftDown(self,event): if not event.ShiftDown(): self.SetSelectionEnd(0) event.Skip() def OnMiddleDown(self,event): code = self.GetSelectedText() pos = self.PositionFromPointClose(event.GetX(),event.GetY()) event.Skip() if pos>-1 and code.strip(): self.SetSelection(pos,pos) self.ReplaceSelection(code) def OnKeyDown(self, event): """""" key = event.GetKeyCode() control = event.ControlDown() #shift=event.ShiftDown() alt = event.AltDown() if key == wx.WXK_RETURN and not control and not alt and not self.AutoCompActive(): #auto-indentation if self.CallTipActive(): self.CallTipCancel() self.calltip=0 line = self.GetCurrentLine() txt = self.GetLine(line) pos = self.GetCurrentPos() linePos = self.PositionFromLine(line) self.CmdKeyExecute(wx_stc.STC_CMD_NEWLINE) indent = self.GetLineIndentation(line) padding = self.indentation * (indent/max(1,self.tabWidth)) newpos = self.GetCurrentPos() # smart indentation stripped = txt[:pos-linePos].split('#')[0].strip() firstWord = stripped.split(" ")[0] if stripped and self.needsIndent(firstWord,lastChar=stripped[-1]): padding += self.indentation elif self.needsDedent(firstWord): padding = padding[:-self.tabWidth] self.InsertText(newpos, padding) newpos += len(padding) self.SetCurrentPos(newpos) self.SetSelection(newpos, newpos) else: event.Skip() def OnChar(self,event): key = event.GetKeyCode() control = event.ControlDown() alt = event.AltDown() # GF We avoid an error while evaluating chr(key), next line. if key > 255 or key < 0: event.Skip() # GF No keyboard needs control or alt to make '(', ')' or '.' # GF Shift is not included as it is needed in some keyboards. elif chr(key) in ['(',')','.'] and not control and not alt: CallTips = self.get('CallTips').lower() if key == ord('(') and CallTips!='disable': # ( start tips if self.CallTipActive(): self.calltip += 1 self.AddText('(') else: self.showCallTip('(') elif key == ord(')'): # ) end tips self.AddText(')') if self.calltip: self.calltip -=1 if not self.calltip: self.CallTipCancel() elif key == ord('.') and self.getint('AutoComplete'): # . Code completion self.autoComplete(object=1) else: event.Skip() else: event.Skip() def OnUpdateUI(self, evt): # check for matching braces 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 == wx_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 == wx_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) #pt = self.PointFromPosition(braceOpposite) #self.Refresh(True, wx.Rect(pt.x, pt.y, 5,5)) #print pt #self.Refresh(False) def OnMarginClick(self, evt): # fold and unfold as needed if evt.GetMargin() == 2: if evt.GetShift() and evt.GetControl(): self.FoldAll() else: lineClicked = self.LineFromPosition(evt.GetPosition()) if self.GetFoldLevel(lineClicked) & wx_stc.STC_FOLDLEVELHEADERFLAG: if evt.GetShift(): self.SetFoldExpanded(lineClicked, True) self.Expand(lineClicked, True, True, 1) elif evt.GetControl(): 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) def OnRightClick(self, event): self.PopupMenu(self.menu) def SetViewEdge(self,check): if check: self.SetEdgeMode(wx_stc.STC_EDGE_LINE) else: self.SetEdgeMode(wx_stc.STC_EDGE_NONE) def FoldAll(self): lineCount = self.GetLineCount() expanding = True # find out if we are folding or unfolding for lineNum in range(lineCount): if self.GetFoldLevel(lineNum) & wx_stc.STC_FOLDLEVELHEADERFLAG: expanding = not self.GetFoldExpanded(lineNum) break; lineNum = 0 while lineNum < lineCount: level = self.GetFoldLevel(lineNum) if level & wx_stc.STC_FOLDLEVELHEADERFLAG and \ (level & wx_stc.STC_FOLDLEVELNUMBERMASK) == wx_stc.STC_FOLDLEVELBASE: if expanding: self.SetFoldExpanded(lineNum, True) lineNum = self.Expand(lineNum, True) lineNum = lineNum - 1 else: lastChild = self.GetLastChild(lineNum, -1) self.SetFoldExpanded(lineNum, False) if lastChild > lineNum: self.HideLines(lineNum+1, lastChild) lineNum = lineNum + 1 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): lastChild = self.GetLastChild(line, level) line = line + 1 while line <= lastChild: if force: if visLevels > 0: self.ShowLines(line, line) else: self.HideLines(line, line) else: if doExpand: self.ShowLines(line, line) if level == -1: level = self.GetFoldLevel(line) if level & wx_stc.STC_FOLDLEVELHEADERFLAG: if force: if visLevels > 1: self.SetFoldExpanded(line, True) else: self.SetFoldExpanded(line, False) line = self.Expand(line, doExpand, force, visLevels-1) else: if doExpand and self.GetFoldExpanded(line): line = self.Expand(line, True, force, visLevels-1) else: line = self.Expand(line, False, force, visLevels-1) else: line = line + 1; return line #---preferences----------------------------------------------------------------- def get(self,name): return self.config.get('Default',name) def getint(self,name): try: return self.config.getint('Default',name) except:#True,False if eval(self.config.get('Default',name)): return 1 else: return 0 def update(self): #general try: font, size = self.get('Font').split(',') font = font.strip() size = eval(size.strip()) self.faces = { 'times': font, 'mono' : font, 'helv' : font, 'other': font, 'size' : size, 'size2': size} except: self.getDefaultFaces() self.SetStyles() #guides self.SetEdgeColumn(self.getint('EdgeColumn')) self.SetViewEdge(self.getint('ViewEdge')) self.SetIndentationGuides(self.getint('IndentationGuides')) #tabs & whitespaces self.tabWidth = self.getint('TabWidth') self.SetTabWidth(self.getint('TabWidth')) self.SetUseTabs(self.getint('UseTabs')) self.SetViewWhiteSpace(self.getint('ViewWhiteSpace')) #line numbers if self.getint('ViewLineNumbers'): self.SetMarginWidth(1, 50) else: self.SetMarginWidth(1, 0) if self.getint('UseTabs'): self.indentation = '\t' else: self.indentation = " " * self.tabWidth self.SetWordChars(self.get('WordChars')) def SetStyles(self): # anti-aliasing if hasattr(self,'SetUseAntiAliasing'): self.SetUseAntiAliasing(True) #INDICATOR STYLES FOR ERRORS (self.errorMark) self.IndicatorSetStyle(2, wx_stc.STC_INDIC_SQUIGGLE) self.IndicatorSetForeground(2, wx.RED) #import dialogs.stcStyleEditor if 1:#dialogs.stcStyleEditor.SetStyles(self, self.config): self.StyleSetSpec(wx_stc.STC_P_DEFAULT, "face:%(mono)s,size:%(size)d" % self.faces) self.StyleClearAll() # Global default styles for all languages self.StyleSetSpec(wx_stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % self.faces) self.StyleSetSpec(wx_stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(size)d" % self.faces) self.StyleSetSpec(wx_stc.STC_STYLE_CONTROLCHAR, "face:%(mono)s" % self.faces) self.StyleSetSpec(wx_stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") self.StyleSetSpec(wx_stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") # Python styles # White space self.StyleSetSpec(wx_stc.STC_P_DEFAULT, "face:%(mono)s,size:%(size)d" % self.faces) # Comment self.StyleSetSpec(wx_stc.STC_P_COMMENTLINE, "face:%(mono)s,fore:#007F00,back:#E8FFE8,italic,size:%(size)d" % self.faces) # Number self.StyleSetSpec(wx_stc.STC_P_NUMBER, "face:%(mono)s,fore:#007F7F,size:%(size)d" % self.faces) # String self.StyleSetSpec(wx_stc.STC_P_STRING, "face:%(mono)s,fore:#7F007F,size:%(size)d" % self.faces) # Single quoted string self.StyleSetSpec(wx_stc.STC_P_CHARACTER, "face:%(mono)s,fore:#7F007F,size:%(size)d" % self.faces) # Keyword self.StyleSetSpec(wx_stc.STC_P_WORD, "face:%(mono)s,fore:#00007F,bold,size:%(size)d" % self.faces) # Triple quotes self.StyleSetSpec(wx_stc.STC_P_TRIPLE, "face:%(mono)s,fore:#7F0000,size:%(size)d" % self.faces) # Triple double quotes self.StyleSetSpec(wx_stc.STC_P_TRIPLEDOUBLE, "face:%(mono)s,fore:#7F0000,size:%(size)d" % self.faces) # Class name definition self.StyleSetSpec(wx_stc.STC_P_CLASSNAME, "face:%(mono)s,fore:#0000FF,bold,underline,size:%(size)d" % self.faces) # Function or method name definition self.StyleSetSpec(wx_stc.STC_P_DEFNAME, "face:%(mono)s,fore:#007F7F,bold,size:%(size)d" % self.faces) # Operators self.StyleSetSpec(wx_stc.STC_P_OPERATOR, "face:%(mono)s,bold,size:%(size)d" % self.faces) # Identifiers self.StyleSetSpec(wx_stc.STC_P_IDENTIFIER, "") # Comment-blocks self.StyleSetSpec(wx_stc.STC_P_COMMENTBLOCK, "face:%(mono)s,fore:#990000,back:#C0C0C0,italic,size:%(size)d" % self.faces) # End of line where string is not closed self.StyleSetSpec(wx_stc.STC_P_STRINGEOL, "face:%(mono)s,fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % self.faces) #---get def getWord(self,whole=None): for delta in (0,-1,1): word = self._getWord(whole=whole,delta=delta) if word: return word return '' def _getWord(self,whole=None,delta=0): pos = self.GetCurrentPos()+delta line = self.GetCurrentLine() linePos = self.PositionFromLine(line) txt = self.GetLine(line) start = self.WordStartPosition(pos,1) if whole: end = self.WordEndPosition(pos,1) else: end = pos return txt[start-linePos:end-linePos] def getWords(self,word=None,whole=None): if not word: word = self.getWord(whole=whole) if not word: return [] else: return sm.unique([x for x in re.findall(r"\b" + word + r"\w*\b", self.GetText()) if x.find(',')==-1 and x[0]!= ' ']) def getWordObject(self,word=None,whole=None): if not word: word=self.getWord(whole=whole) try: obj = self.evaluate(word) return obj except: return None def getWordFileName(self,whole=None): wordList=self.getWord(whole=whole).split('.') wordList.append('') index=1 n=len(wordList) while index 0: if firstWord[-1] == ":": firstWord = firstWord[:-1] # control flow keywords if firstWord in ["for","if", "else", "def","class","elif", "try","except","finally","while"] and lastChar == ':': return True else: return False def needsDedent(self,firstWord): "Tests if a line needs extra dedenting, ie break, return, etc " # control flow keywords if firstWord in ["break","return","continue","yield","raise"]: return True else: return False def showCallTip(self,text=''): #prepare obj = self.getWordObject() self.AddText(text) if not obj: return #classes, methods & functions if type(obj) in [types.ClassType,types.TypeType] and hasattr(obj,'__init__'): init = obj.__init__ tip = getargspec(init).strip() if tip in ['(self, *args, **kwargs)','(*args, **kwargs)']: tip = "" else: tip = "%s\n"%tip doci = init.__doc__ if doci: doc = '%s\n'%(doci.strip()) else: doc = "" tip = getargspec(init) else: doc = "" tip = getargspec(obj) #normal docstring _doc = obj.__doc__ #compose if _doc: doc += _doc if doc: if self.get('CallTips').lower() == 'first paragraph only': tip += doc.split('\n')[0] else: tip += doc if tip: pos = self.GetCurrentPos() self.calltip = 1 tip+='\n(Press ESC to close)' self.CallTipSetBackground('#FFFFE1') self.CallTipShow(pos, tip.replace('\r\n','\n')) class PythonViewSTC(PythonBaseSTC): """Mutation for dynamic class""" def __init__(self,parent, child = None, *args,**kwds): PythonBaseSTC.__init__(self,parent,*args,**kwds) self.dyn_sash = parent self.child = child self._args = args self._kwds = kwds self.SetupScrollBars() wx_gizmos.EVT_DYNAMIC_SASH_SPLIT(self,-1,self.OnSplit) wx_gizmos.EVT_DYNAMIC_SASH_UNIFY(self,-1,self.OnUnify) wx.EVT_SET_FOCUS(self,self.OnSetFocus) wx.EVT_KILL_FOCUS(self,self.OnKillFocus) self.SetScrollbar(wx.HORIZONTAL, 0, 0, 0) self.SetScrollbar(wx.VERTICAL, 0, 0, 0) ## eventManager.Register(self.OnSplit,wx_gizmos.EVT_DYNAMIC_SASH_SPLIT,self) ## eventManager.Register(self.OnUnify,wx_gizmos.EVT_DYNAMIC_SASH_UNIFY,self) def SetupScrollBars(self): # hook the scrollbars provided by the wxDynamicSashWindow # to this view v_bar = self.dyn_sash.GetVScrollBar(self) h_bar = self.dyn_sash.GetHScrollBar(self) wx.EVT_SCROLL(v_bar,self.OnSBScroll) wx.EVT_SCROLL(h_bar,self.OnSBScroll) wx.EVT_SET_FOCUS(v_bar, self.OnSBFocus) wx.EVT_SET_FOCUS(h_bar, self.OnSBFocus) ## eventManager.Register(self.OnSBScroll, wx.EVT_SCROLL, v_bar) ## eventManager.Register(self.OnSBScroll, wx.EVT_SCROLL, h_bar) ## eventManager.Register(self.OnSBFocus, wx.EVT_SET_FOCUS, v_bar) ## eventManager.Register(self.OnSBFocus, wx.EVT_SET_FOCUS, h_bar) # And set the wxStyledText to use these scrollbars instead # of its built-in ones. self.SetVScrollBar(v_bar) self.SetHScrollBar(h_bar) def OnSetFocus(self,event): self.child.source = self event.Skip() def OnKillFocus(self,event): self.AutoCompCancel() event.Skip() def OnSplit(self, evt): newview = PythonViewSTC(self.dyn_sash, child = self.child, *self._args, **self._kwds) newview.SetDocPointer(self.GetDocPointer()) # use the same document self.SetupScrollBars() def OnUnify(self, evt): self.SetupScrollBars() children = self.dyn_sash.GetChildren()[-1].GetChildren() while children[-1].__class__!=PythonViewSTC: children = children[-1].GetChildren() source = self.child.source = self.dyn_sash.view = children[-1] def OnSBScroll(self, evt): # redirect the scroll events from the dyn_sash's scrollbars to the STC self.GetEventHandler().ProcessEvent(evt) def OnSBFocus(self, evt): # when the scrollbar gets the focus move it back to the STC self.SetFocus() class PythonSashSTC(wx_gizmos.DynamicSashWindow): def __init__(self,parent,*args,**kwds): wx_gizmos.DynamicSashWindow.__init__(self, parent,-1, style = wx.CLIP_CHILDREN | wx.FULL_REPAINT_ON_RESIZE #| wxDS_MANAGE_SCROLLBARS #| wxDS_DRAG_CORNER ) self.parent = parent self.view = PythonViewSTC(parent=self, id=-1, child = parent, *args, **kwds) #print dir(self) if wx.Platform == "__WXMAC__": #The dynamic sash currently fails on the Mac. The problem is being looked into... PythonSTC = PythonBaseSTC else: PythonSTC = PythonBaseSTC#PythonSashSTC #------------------------------------------------------------------------------- def getargspec(func): """Get argument specifications""" try: func=func.im_func except: pass try: return inspect.formatargspec(*inspect.getargspec(func)).replace('self, ','')+'\n\n' except: pass try: return inspect.formatargvalues(*inspect.getargvalues(func)).replace('self, ','')+'\n\n' except: return '' spe-0.8.4.h/_spe/sm/wxp/NotebookCtrl.py0000644000175000017500000065502110575625553016746 0ustar stanistani# --------------------------------------------------------------------------- # # NOTEBOOKCTRL Control wxPython IMPLEMENTATION # Python Code By: # # Andrea Gavana, @ 11 Nov 2005 # Latest Revision: 06 Oct 2006, 18.10 GMT # # # AKNOWLEDGEMENTS # # A big load of thanks goes to Julianne Sharer that has implemented the new # features of left/right tabs, rotated or horizontal, with the ability to # switch between the two views by a single mouse click. Moreover, all the # work done to refactor NotebookCtrl in a more readable way has been done # by Julianne Sharer. Thanks Julianne. # # # TODO List/Caveats # # 1. Ay Idea? # # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please # Write To Me At: # # andrea.gavana@gmail.com # gavana@kpo.kz # # Or, Obviously, To The wxPython Mailing List!!! # # # End Of Comments # --------------------------------------------------------------------------- # """ A full-featured notebook control, worked out by Andrea Gavana And Julianne Sharer. Description: NotebookCtrl Mimics The Behavior Of wx.Notebook, And Most Of Its Functionalities Are Implemented In NotebookCtrl. However, NotebookCtrl Has A Lot Of Options That wx.Notebook Does Not Have, And It Is Therefore Quite Customizable. wx.Notebook Styles Not Implemented in NotebookCtrl Are: - wx.NB_MULTILINE (But NotebookCtrl Has A SpinButton To Navigate Through Tabs). Supported Customizations For NotebookCtrl Include: - Setting Individual Tab Font And Text Colour; - Images On Tabs (Line wx.Notebook); - Setting Individual Tab Colours; - Disabling/Enabling Individual Tabs (Also Visually Effective); Now Supports Grayed Out Icons When A Page Is Disabled; - Drawing Of A Small Closing "X" At The Right Of Every Tab, That Enable The User To Close A Tab With A Mouse Click (Like eMule Tab Style); - Enabling Highlighted Tabs On Selection; - Drawing Focus Indicator In Each Tab (Like wx.Notebook); - Ctrl-Tab Keyboard Navigation Between Pages; - Tab With Animated Icons (Animation On Tabs); - Drag And Drop Tabs In NotebookCtrl (Plus A Visual Arrow Effect To Indicate Dropping Position); - Drag And Drop Event; - ToolTips On Individual Tabs, With Customizable ToolTip Time Popup And ToolTip Window Size For Individual Tabs; - Possibility To Hide The TabCtrl There Is Only One Tab (Thus Maximizing The Corresponding Window); - Possibility To Convert The Tab Image Into A Close Button While Mouse Is Hovering On The Tab Image; - Popup Menus On Tabs (Popup Menus Specific To Each Tab); - Showing Pages In "Column/Row Mode", Which Means That All Pages Will Be Shown In NotebookCtrl While The Tabs Are Hidden. They Can Be Shown In Columns (Default) Or In Rows; - Possibility To Hide Tabs On User Request, Thus Showing Only The Current Panel; - Multiple Tabs Selection (Hold Ctrl Key Down And Left Mouse Click), Useful When You Use The Show All The Panels In Columns/Rows. In This Case, Only The Selected Tabs Are Shown In Columns/Rows; - Events For Mouse Events (Left Double Click, Middle Click, Right Click); - Possibility To Reparent A NotebookCtrl Page To A Freshly Created Frame As A Simple Panel Or To A New NotebookCtrl Created Inside That New Frame. - Possibility To Add A Custom Panel To Show A Logo Or HTML Information Or Whatever You Like When There Are No Tabs In NotebookCtrl; - Possibility To Change The ToolTip Window Background Colour; - Possibility To Draw Vertical Or Horizontal Gradient Coloured Tabs (2 Colours); - Themes On Tabs: Built-In Themes Are KDE (Unix/Linux), Metal, Aqua Light And Aqua Dark (MacOS), Windows Silver (Windows) Or Generic Gradient Coloured Tabs. It's Also Possible To Define A Separate Theme For Selected Tabs And Control Background (The Last Two Are Work In Progress); - Contour Line Colour Around Tabs Is Customizable; - Highlight Colour Of Selected Tab Is Customizable; - Each Tab Can Have Its Own Gradient Colouring (2 Colours For Every Tab); - Custom Images May Be Drawn As A "X" Close Buttons On Tabs; - Possibility To Hide A Particular Tab Using A wx.PopupMenu That Is Shown If You Call EnableHiding(True). Look At The Top Right Of NotebookCtrl; - Allows Drag And Drop Of Tabs/Pages Between Different NotebookCtrls In The Same Application. - Draw tabs on the left or right side, rotated or horizontal - Allow user to switch between rotated and horizontal displays of tabs on the left or right side. Usage: NotebookCtrl Construction Is Quite Similar To wx.Notebook:: NotebookCtrl.__init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=style, sizer=nbsizer) See L{NotebookCtrl.__init__} Method For The Definition Of Non Standard (Non wxPython) Parameters. NotebookCtrl Control Is Freeware And Distributed Under The wxPython License. Latest Revision: Andrea Gavana @ 06 Oct 2006, 18.10 GMT @undocumented: NC_MAC*, topaqua*, botaqua*, distaqua*, disbaqua*, kdetheme, silvertheme*, wxEVT*, attrs, GetMenuButton*, NCDragInfo, NCDropTarget, TabbedPage, TabCtrl, TransientTipWindow, macPopupWindow, macTransientTipWindow, NCFrame, DEFAULT_SIZE, NotebookSpinButton, NotebookMenuButton """ __docformat__ = "epytext" #---------------------------------------------------------------------- # Beginning Of NOTEBOOKCTRL wxPython Code #---------------------------------------------------------------------- import wx from wx.lib.buttons import GenBitmapButton as BitmapButton import wx.xrc as xrc import cStringIO, zlib import cPickle import weakref # HitTest Results NC_HITTEST_NOWHERE = 0 # Not On Tab """Indicates mouse coordinates not on any tab of the notebook""" NC_HITTEST_ONICON = 1 # On Icon """Indicates mouse coordinates on an icon in a tab of the notebook""" NC_HITTEST_ONLABEL = 2 # On Label """Indicates mouse coordinates on a label in a tab of the notebook""" NC_HITTEST_ONITEM = 4 # Generic, On Item """Indicates mouse coordinates on a tab of the notebook""" NC_HITTEST_ONX = 8 # On Small Square On Every Page """Indicates mouse coordinates on the closing I{X} in a tab of the notebook""" # NotebookCtrl Styles # NotebookCtrl Placed On Top (Default) NC_TOP = 1 """Specify tabs at the top of the notebook control.""" # NotebookCtrl Placed At The Bottom NC_BOTTOM = 2 """Specify tabs at the bottom of the notebook control.""" # NotebookCtrl With Fixed Width Tabs NC_FIXED_WIDTH = 4 """Specify tabs of a fixed width in the notebook control.""" # NotebookCtrl Placed At The Left NC_LEFT = 8 """Specify tabs on the left side of the notebook control.""" # NotebookCtrl Placed At The Right NC_RIGHT = 16 """Specify tabs on the right side of the notebook control.""" # NotebookCtrl tab rotated NC_ROTATE = 32 """Specify rotated tabs (with vertical text) in the notebook control.""" # NotebookCtrl switchable between compact and expanded sizes NC_EXPANDABLE = 64 """Specify that the notebook control includes a toggle button to switch between compact tabs (rotated on the left or right side) expanded tabs (horizontal on the left or right side).""" NC_DEFAULT_STYLE = NC_TOP | wx.NO_BORDER """The default style for the notebook control (tabs on top with no border)""" # Also wx.STATIC_BORDER Is Supported # NotebookCtrl theme styles NC_GRADIENT_VERTICAL = 1 """Specify tabs rendered with a vertical gradient background.""" NC_GRADIENT_HORIZONTAL = 2 """Specify tabs rendered with a horizontal gradient background.""" NC_GRADIENT_SELECTION = 4 NC_AQUA_LIGHT = 8 """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" NC_AQUA_DARK = 16 """Specify tabs rendered with a Mac I{Dark Aqua}-like background.""" NC_AQUA = NC_AQUA_LIGHT """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" NC_METAL = 32 """Specify tabs rendered with a Mac I{Metal}-like background.""" NC_SILVER = 64 """Specify tabs rendered with a Windows I{Silver}-like background.""" NC_KDE = 128 """Specify tabs rendered with a KDE-style background.""" # Patch To Make NotebookCtrl Working Also On MacOS: Thanks To Stani ;-) if wx.Platform == '__WXMAC__': DEFAULT_SIZE = wx.Size(26, 26) else: DEFAULT_SIZE = wx.DefaultSize # Themes On Mac... This May Slow Down The Paint Event If You Turn It On! NC_MAC_LIGHT = (240, 236) NC_MAC_DARK = (232, 228) topaqua1 = [wx.Colour(106, 152, 231), wx.Colour(124, 173, 236)] botaqua1 = [wx.Colour(54, 128, 213), wx.Colour(130, 225, 249)] topaqua2 = [wx.Colour(176, 222, 251), wx.Colour(166, 211, 245)] botaqua2 = [wx.Colour(120, 182, 244), wx.Colour(162, 230, 245)] distaqua = [wx.Colour(248, 248, 248), wx.Colour(243, 243, 243)] disbaqua = [wx.Colour(219, 219, 219), wx.Colour(248, 248, 248)] # Themes On KDE... This May Slow Down The Paint Event If You Turn It On! kdetheme = [wx.Colour(0xf3,0xf7,0xf9), wx.Colour(0xf3,0xf7,0xf9), wx.Colour(0xee,0xf3,0xf7), wx.Colour(0xee,0xf3,0xf7), wx.Colour(0xea,0xf0,0xf4), wx.Colour(0xea,0xf0,0xf4), wx.Colour(0xe6,0xec,0xf1), wx.Colour(0xe6,0xec,0xf1), wx.Colour(0xe2,0xe9,0xef), wx.Colour(0xe2,0xe9,0xef), wx.Colour(0xdd,0xe5,0xec), wx.Colour(0xdd,0xe5,0xec), wx.Colour(0xd9,0xe2,0xea), wx.Colour(0xd9,0xe2,0xea)] # Themes On Windows... This May Slow Down The Paint Event If You Turn It On! silvertheme2 = [wx.Colour(255, 255, 255), wx.Colour(190, 190, 216), wx.Colour(180, 180, 200)] silvertheme1 = [wx.Colour(252, 252, 254), wx.Colour(252, 252, 254)] # NotebookCtrl Events: # wxEVT_NOTEBOOKCTRL_PAGE_CHANGED: Event Fired When You Switch Page; # wxEVT_NOTEBOOKCTRL_PAGE_CHANGING: Event Fired When You Are About To Switch # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call # event.Skip() In Your Event Handler; # wxEVT_NOTEBOOKCTRL_PAGE_CLOSING: Event Fired When A Page Is Closing, But # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip() # In Your Event Handler; # wxEVT_NOTEBOOKCTRL_PAGE_DND: Event Fired When A Drag And Drop Action On # Tabs Ends. wxEVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_DND = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.NewEventType() #-----------------------------------# # NotebookCtrlEvent #-----------------------------------# EVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED, 1) """Notify client objects when the active page in the notebook control has changed.""" EVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, 1) """Notify client objects when the active page in the notebook control is changing.""" EVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, 1) """Notify client objects when a page in the notebook control is closing.""" EVT_NOTEBOOKCTRL_PAGE_DND = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DND, 1) """Enable client objects to override the behavior of the notebook control when a dragged tab is dropped onto it.""" EVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, 1) """Notify client objects when the user double-clicks a tab in the notebook control.""" EVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, 1) """Notify client objects when the user right-clicks a tab in the notebook control.""" EVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, 1) """Notify client objects when the user clicks with the middle mouse button on a tab in the notebook control.""" attrs = ["_backstyle", "_backtooltip", "_borderpen", "_convertimage", "_drawx", "_drawxstyle", "_enabledragging", "_focusindpen", "_hideonsingletab", "_highlight", "_padding", "_selectioncolour", "_selstyle", "_tabstyle", "_upperhigh", "_usefocus", "_usegradients"] # Check for the new method in 2.7 (not present in 2.6.3.3) if wx.VERSION_STRING < "2.7": wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point) # ---------------------------------------------------------------------------- # def GetMenuButtonData(): return zlib.decompress( "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x9c \xcc\xc1\ \x06$\x1fLd\x13\x00R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4[x\xba8\x86HL\xed\ \xbd`\xc8\xc7\xa0\xc0\xe1|q\xdb\x9d\xff'\xba\xb4\x1d\x05v\xff}\xe2\xab\x9a:c\ \x99\xc4\xbe\xe9\xfd+\x9a\xc5W%t\x1a\xe5\x08\xa6\xd6,\xe2\xf0\x9a\xc2\xc8\ \xf0\xe1\xf9r\xe6\xa3\xc9\x02b\xd9\x0c35\x80f0x\xba\xfa\xb9\xacsJh\x02\x00\ \xcd-%1") def GetMenuButtonBitmap(): return wx.BitmapFromImage(GetMenuButtonImage()) def GetMenuButtonImage(): stream = cStringIO.StringIO(GetMenuButtonData()) return wx.ImageFromStream(stream) # ---------------------------------------------------------------------------- # def GrayOut(anImage): """ Convert The Given Image (In Place) To A Grayed-Out Version, Appropriate For A 'Disabled' Appearance. """ factor = 0.7 # 0 < f < 1. Higher Is Grayer if anImage.HasMask(): maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue()) else: maskColor = None data = map(ord, list(anImage.GetData())) for i in range(0, len(data), 3): pixel = (data[i], data[i+1], data[i+2]) pixel = MakeGray(pixel, factor, maskColor) for x in range(3): data[i+x] = pixel[x] anImage.SetData(''.join(map(chr, data))) return anImage def MakeGray((r,g,b), factor, maskColor): """ Make A Pixel Grayed-Out. If The Pixel Matches The MaskColor, It Won't Be Changed. """ if (r,g,b) != maskColor: return map(lambda x: int((230 - x) * factor) + x, (r,g,b)) else: return (r,g,b) def GetDefaultTabStyle(): tabstyle = ThemeStyle() # Draw Mac Themes On Tabs? if wx.Platform == "__WXMAC__" or wx.Platform == "__WXCOCOA__": tabstyle.EnableAquaTheme(True, 2) # Draw Windows Silver Theme On Tabs? elif wx.Platform == "__WXMSW__": tabstyle.EnableSilverTheme(True) else: tabstyle.EnableKDETheme(True) return tabstyle # ---------------------------------------------------------------------------- # # Class NotebookCtrlEvent # ---------------------------------------------------------------------------- # class NotebookCtrlEvent(wx.PyCommandEvent): """ Represent details of the events that the L{NotebookCtrl} object sends. """ def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1): """ Default Class Constructor. """ wx.PyCommandEvent.__init__(self, eventType, id) self._eventType = eventType def SetSelection(self, nSel): """ Sets Event Selection. """ self._selection = nSel def SetOldSelection(self, nOldSel): """ Sets Old Event Selection. """ self._oldselection = nOldSel def GetSelection(self): """ Returns Event Selection. """ return self._selection def GetOldSelection(self): """ Returns Old Event Selection """ return self._oldselection def SetOldPosition(self, pos): """ Sets Old Event Position. """ self._oldposition = pos def SetNewPosition(self, pos): """ Sets New Event Position. """ self._newposition = pos def GetOldPosition(self): """ Returns Old Event Position. """ return self._oldposition def GetNewPosition(self): """ Returns New Event Position. """ return self._newposition # ---------------------------------------------------------------------------- # # Class NCDragInfo # Stores All The Information To Allow Drag And Drop Between Different # NotebookCtrls In The Same Application. # ---------------------------------------------------------------------------- # class NCDragInfo: _map = weakref.WeakValueDictionary() def __init__(self, container, pageindex): """ Default Class Constructor. """ self._id = id(container) NCDragInfo._map[self._id] = container self._pageindex = pageindex def GetContainer(self): """ Returns The NotebookCtrl Page (Usually A Panel). """ return NCDragInfo._map.get(self._id, None) def GetPageIndex(self): """ Returns The Page Index Associated With A Page. """ return self._pageindex # ---------------------------------------------------------------------------- # # Class NCDropTarget # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between # Different NotebookCtrls. # ---------------------------------------------------------------------------- # class NCDropTarget(wx.DropTarget): def __init__(self, parent): """ Default Class Constructor. """ wx.DropTarget.__init__(self) self._parent = parent self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) self.SetDataObject(self._dataobject) def OnData(self, x, y, dragres): """ Handles The OnData() Method TO Call The Real DnD Routine. """ if not self.GetData(): return wx.DragNone draginfo = self._dataobject.GetData() drginfo = cPickle.loads(draginfo) return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer()) # ---------------------------------------------------------------------------- # # Class ThemeStyle. Used To Define A Custom Style For Tabs And Control # Background Colour. # ---------------------------------------------------------------------------- # class ThemeStyle: """ Represent the style for rendering a notebook tab. """ GRADIENT_VERTICAL = 1 GRADIENT_HORIZONTAL = 2 DIFFERENT_GRADIENT_FOR_SELECTED = 4 def __init__(self): """ Default Constructor For This Class.""" self.ResetDefaults() def ResetDefaults(self): """ Resets Default Theme. """ self._normal = True self._aqua = False self._metal = False self._macstyle = False self._kdetheme = False self._silver = False self._gradient = False self._firstcolour = wx.WHITE self._secondcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._firstcolourselected = wx.WHITE self._secondcolourselected = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) def EnableMacTheme(self, enable=True, style=1): """ Enables/Disables Mac Themes. style=1 Is The Light Style, While style=2 Is The Dark Style. Mainly Used For Control Background Colour, Not For Tabs. """ if enable: self._normal = False self._macstyle = style self._kdetheme = False self._metal = False self._aqua = False self._silver = False self._gradient = False else: self._macstyle = 0 def EnableKDETheme(self, enable=True): """ Globally Enables/Disables Unix-Like KDE Theme For Tabs. """ self._kdetheme = enable if enable: self._normal = False self._macstyle = False self._metal = False self._aqua = False self._silver = False self._gradient = False def EnableMetalTheme(self, enable=True): """ Globally Enables/Disables Mac-Like Metal Theme For Tabs. """ self._metal = enable if enable: self._normal = False self._macstyle = False self._kdetheme = False self._aqua = False self._silver = False self._gradient = False def EnableAquaTheme(self, enable=True, style=1): """ Globally Enables/Disables Mac-Like Aqua Theme For Tabs. """ if enable: self._aqua = style self._normal = False self._macstyle = False self._kdetheme = False self._metal = False self._silver = False self._gradient = False else: self._aqua = 0 def EnableSilverTheme(self, enable=True): """ Globally Enables/Disables Windows Silver Theme For Tabs. """ self._silver = enable if enable: self._normal = False self._macstyle = False self._kdetheme = False self._metal = False self._aqua = False self._gradient = False def EnableGradientStyle(self, enable=True, style=1): """ Enables/Disables Gradient Drawing On Tabs. style=1 Is The Vertical Gradient, While style=2 Is The Horizontal Gradient. If style flag 4 is set, the style has a separate set of colors for the selected tab. """ if enable: self._normal = False if style & self.GRADIENT_VERTICAL == 0 and style & self.GRADIENT_HORIZONTAL == 0: style |= self.GRADIENT_VERTICAL self._gradient = style self._macstyle = False self._kdetheme = False self._metal = False self._aqua = False self._silver = False else: self._gradient = 0 def SetFirstGradientColour(self, colour=None): """ Sets The First Gradient Colour. """ if colour is None: colour = wx.WHITE self._firstcolour = colour def SetFirstGradientColourSelected(self, colour=None): """Sets The First Gradient Colour For The Selected Tab.""" if colour is None: colour = wx.WHITE self._firstcolourselected = colour def SetSecondGradientColour(self, colour=None): """ Sets The Second Gradient Colour. """ if colour is None: color = self.GetBackgroundColour() r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolour = colour def SetSecondGradientColourSelected(self, colour=None): """ Sets The Second Gradient Colour For The Selected Tab. """ if colour is None: color = self.GetBackgroundColour() r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolourselected = colour def GetFirstGradientColour(self, selected=False): """ Returns The First Gradient Colour. """ if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: return self._firstcolourselected else: return self._firstcolour def GetSecondGradientColour(self, selected=False): """ Returns The Second Gradient Colour. """ if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: return self._secondcolourselected else: return self._secondcolour # ---------------------------------------------------------------------------- # # Class TabbedPage # This Is Just A Container Class That Initialize All The Default Settings For # Every Tab. # ---------------------------------------------------------------------------- # class TabbedPage: def __init__(self, text="", image=-1, hidden=False): """ Default Class Constructor. """ self._text = text self._image = image self._font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._secondaryfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pagetextcolour = wx.BLACK self._pagecolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._enable = True self._animationimages = [] self._tooltip = "" self._tooltiptime = 500 self._winsize = 400 self._menu = None self._ishidden = hidden self._firstcolour = color = wx.WHITE r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolour = colour # ---------------------------------------------------------------------------- # # Class NotebookSpinButton # This SpinButton Is Created/Shown Only When The Total Tabs Size Exceed The # Client Size, Allowing The User To Navigate Between Tabs By Clicking On The # SpinButton. It Is Very Similar To The wx.Notebook SpinButton # ---------------------------------------------------------------------------- # class NotebookSpinButton(wx.SpinButton): def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SP_HORIZONTAL): """ Default Class Constructor. """ wx.SpinButton.__init__(self, parent, id, pos, size, style) self._nb = parent self._oldvalue = 0 self._style = style self.Bind(wx.EVT_SPIN, self.OnSpin) def GetValue(self): result = super(NotebookSpinButton, self).GetValue() if self._style & wx.SP_VERTICAL: result = -result return result def OnSpin(self, event): """ Handles The User's Clicks On The SpinButton. """ if type(event) != type(1): pos = event.GetPosition() else: pos = event if pos < self.GetMin(): self.SetValue(self.GetMin()) return if type(event) != type(1): if self._nb._enablehiding: if pos < self._oldvalue: incr = -1 else: incr = 1 while self._nb._pages[pos]._ishidden: pos = pos + incr self.SetValue(pos) if self._nb.IsLastVisible(): if (self._style & wx.SP_HORIZONTAL and self._oldvalue < pos) or \ (self._style & wx.SP_VERTICAL and self._oldvalue > pos): self.SetValue(self._oldvalue) return self._oldvalue = pos self._nb.Refresh() # ---------------------------------------------------------------------------- # # Class NotebookMenuButton # This MenuButton Is Created/Shown Only When You Activate The Option EnableHiding # Of NotebookCtrl. This Small Button Will Be Shown Right Above The Spin Button # (If Present), Or In The Position Of The Spin Button. # ---------------------------------------------------------------------------- # class NotebookMenuButton(BitmapButton): def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=(15, 11), style=0): """ Default Class Constructor. """ bmp = GetMenuButtonBitmap() BitmapButton.__init__(self, parent, id, bmp, pos, size, style) self.SetUseFocusIndicator(False) self.SetBezelWidth(1) self._originalcolour = self.GetBackgroundColour() self._nb = parent self.Bind(wx.EVT_BUTTON, self.OnButton) self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self.Bind(wx.EVT_MENU, self.OnMenu) def OnButton(self, event): """ Handles The wx.EVT_BUTTON For NotebookMenuButton (Opens The wx.PopupMenu) """ count = self._nb.GetPageCount() if count <= 0: return menu = wx.Menu() id = wx.NewId() myids = [] for ii in xrange(count): id = id + 1 myids.append(id) name = self._nb.GetPageText(ii) if self._nb._pages[ii]._ishidden: msg = "Page Hidden" check = False else: msg = "Page Shown" check = True item = wx.MenuItem(menu, id, name, msg, wx.ITEM_CHECK) menu.AppendItem(item) if not self._nb._pages[ii]._ishidden: item.Check() menu.SetHelpString(id, msg) self._myids = myids self.PopupMenu(menu) event.Skip() def OnMenu(self, event): """ Handles The wx.EVT_MENU For NotebookMenuButton. Calls HideTab(). """ indx = self._myids.index(event.GetId()) checked = not event.GetEventObject().IsChecked(event.GetId()) self._nb.HideTab(indx, not checked) event.Skip() def OnEnterWindow(self, event): """ Changes The NotebookMenuButton Background Colour When The Mouse Enters The Button Region. """ entercolour = self.GetBackgroundColour() firstcolour = entercolour.Red() secondcolour = entercolour.Green() thirdcolour = entercolour.Blue() if entercolour.Red() > 235: firstcolour = entercolour.Red() - 40 if entercolour.Green() > 235: secondcolour = entercolour.Green() - 40 if entercolour.Blue() > 235: thirdcolour = entercolour.Blue() - 40 entercolour = wx.Colour(firstcolour+20, secondcolour+20, thirdcolour+20) self.SetBackgroundColour(entercolour) self.Refresh() event.Skip() def OnLeaveWindow(self, event): """ Restore The NotebookMenuButton Background Colour When The Mouse Leaves The Button Region. """ self.SetBackgroundColour(self._originalcolour) self.Refresh() event.Skip() class _TabCtrlPaintTools(object): # Structure-like object for passing data among # private rendering methods def __init__(self, backBrush, backPen, borderPen, highlightPen, shadowPen, upperHighlightPen, selectionPen, selectionEdgePen, xPen, focusPen): self.BackBrush = backBrush self.BackPen = backPen self.BorderPen = borderPen self.HighlightPen = highlightPen self.ShadowPen = shadowPen self.UpperHighlightPen = upperHighlightPen self.SelectionPen = selectionPen self.SelectionEdgePen = selectionEdgePen self.XPen = xPen self.FocusPen = focusPen # ---------------------------------------------------------------------------- # # Class TabCtrl # This Class Handles The Drawing Of Every Tab In The NotebookCtrl, And Also # All Settings/Methods For Every Tab. # ---------------------------------------------------------------------------- # class TabCtrl(wx.PyControl): def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=DEFAULT_SIZE, style=NC_DEFAULT_STYLE, validator=wx.DefaultValidator, name="TabCtrl"): """ Default Class Constructor. Used Internally. Do Not Call It Explicitely! """ wx.PyControl.__init__(self, parent, id, pos, size, wx.NO_BORDER | wx.WANTS_CHARS, validator, name) # Set All The Default Parameters For TabCtrl self._selection = -1 self._imglist = 0 self._style = style self._expanded = False self._pages = [] self._enabledpages = [] self._padding = wx.Point(8, 4) self._spacetabs = 2 self._xrect = [] self._xrefreshed = False self._imageconverted = False self._convertimage = False self._disabledcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT) self._hover = False self._parent = parent self._firsttime = True self._somethingchanged = True self._isdragging = False self._tabID = -1 self._enabledragging = False self._olddragpos = -1 self._fromdnd = False self._isleaving = False self._highlight = False self._usefocus = True self._hideonsingletab = False self._selectioncolour = wx.Colour(255, 200, 60) self._selectionedgecolour = wx.Colour(230, 139, 44) self._tabstyle = ThemeStyle() self._backstyle = ThemeStyle() self._selstyle = ThemeStyle() self._usegradients = False self._insidetab = -1 self._showtooltip = False self._istooltipshown = False self._tipwindow = None self._tiptimer = wx.PyTimer(self.OnShowToolTip) self._backtooltip = wx.Colour(255, 255, 230) self._xvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) self._yvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) self._selectedtabs = [] self._timers = [] self._dragcursor = wx.StockCursor(wx.CURSOR_HAND) self._dragstartpos = wx.Point() self._drawx = False self._drawxstyle = 1 self._pmenu = None self._enablehiding = False if (style & NC_LEFT or style & NC_RIGHT) and style & NC_EXPANDABLE: self._InitExpandableStyles(style) self._InitExpandableTabStyles(self._style, self._expanded, self._tabstyle) self._CreateSizeToggleButton() else: self._sizeToggleButton = None self.SetDefaultPage() if style & NC_TOP or style & NC_BOTTOM: self.SetBestSize((-1, 28)) self._firsttabpos = wx.Point(3, 0) else: self.SetBestSize((28, -1)) self._firsttabpos = wx.Point(0, 3 + self._CalcSizeToggleBestSize()[1]) self._borderpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) self._highlightpen2 = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) self._highlightpen = wx.Pen((145, 167, 180)) self._upperhigh = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) self._shadowpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DDKSHADOW), 2) self._shadowpen.SetCap(wx.CAP_BUTT) self._highlightpen.SetCap(wx.CAP_BUTT) self._highlightpen2.SetCap(wx.CAP_BUTT) if wx.Platform == "__WXMAC__": self._focusindpen = wx.Pen(wx.BLACK, 1, wx.SOLID) else: self._focusindpen = wx.Pen(wx.BLACK, 1, wx.USER_DASH) self._focusindpen.SetDashes([1,1]) self._focusindpen.SetCap(wx.CAP_BUTT) self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseLeftDClick) self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) self.Bind(wx.EVT_RIGHT_UP, self.OnMouseRightUp) self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown) self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMouseMiddleDown) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) self.Bind(wx.EVT_TIMER, self.AnimateTab) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self._droptarget = NCDropTarget(self) self.SetDropTarget(self._droptarget) def Contract(self): if self._style & NC_EXPANDABLE and self._expanded: self._ToggleSize() def Expand(self): if self._style & NC_EXPANDABLE and not self._expanded: self._ToggleSize() def _ToggleSize(self, event=None): if self._style & NC_EXPANDABLE and not self._expanded: # contract self._style = self._expandedstyle self._tabstyle = self._expandedtabstyle self._expanded = True self._sizeToggleButton.SetLabel("<<") elif self._style & NC_EXPANDABLE and self._expanded: # expand self._style = self._contractedstyle self._tabstyle = self._contractedtabstyle self._expanded = False self._sizeToggleButton.SetLabel(">>") self._OnStyleChange() def OnDropTarget(self, x, y, nPage, oldcont): """ Handles The OnDrop Action For Drag And Drop Between Different NotebookCtrl. """ where = self.HitTest(wx.Point(x, y)) oldNotebook = oldcont.GetParent() newNotebook = self.GetParent() if oldNotebook == newNotebook: if where >= 0 and where != self._tabID: self._isdragging = False self._olddragpos = -1 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) eventOut.SetOldPosition(self._tabID) eventOut.SetNewPosition(where) eventOut.SetEventObject(self) if self.GetEventHandler().ProcessEvent(eventOut): self._tabID = -1 self._olddragpos = -1 self.SetCursor(wx.STANDARD_CURSOR) self.Refresh() return self._parent.Freeze() try: text = self.GetPageText(self._tabID) image = self.GetPageImage(self._tabID) font1 = self.GetPageTextFont(self._tabID) font2 = self.GetPageTextSecondaryFont(self._tabID) fontcolour = self.GetPageTextColour(self._tabID) pagecolour = self.GetPageColour(self._tabID) enabled = self.IsPageEnabled(self._tabID) tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) menu = self.GetPagePopupMenu(self._tabID) firstcol = self.GetPageFirstGradientColour(self._tabID) secondcol = self.GetPageSecondGradientColour(self._tabID) ishidden = self._pages[self._tabID]._ishidden except: self._parent.Thaw() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return isanimated = 0 if self._timers[self._tabID].IsRunning(): isanimated = 1 timer = self._timers[self._tabID].GetInterval() self.StopAnimation(self._tabID) animatedimages = self.GetAnimationImages(self._tabID) pagerange = range(self.GetPageCount()) newrange = pagerange[:] newrange.remove(self._tabID) newrange.insert(where, self._tabID) newpages = [] counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): newpages.append(self._parent.GetPage(ii)) self._parent.bsizer.Detach(counter-ii) cc = 0 self._parent._notebookpages = [] for jj in newrange: self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) self._parent.bsizer.Show(cc, False) self._parent._notebookpages.append(newpages[jj]) cc = cc + 1 self.DeletePage(self._tabID) if enabled: if id == self.GetPageCount(): self.AddPage(text, True, image) else: self.InsertPage(where, text, True, image) else: if id == self.GetPageCount(): self.AddPage(text, False, image) else: self.InsertPage(where, text, False, image) self.SetPageImage(where, image) self.SetPageText(where, text) self.SetPageTextFont(where, font1) self.SetPageTextSecondaryFont(where, font2) self.SetPageTextColour(where, fontcolour) self.SetPageColour(where, pagecolour) self.EnablePage(where, enabled) self.SetPageToolTip(where, tooltip, ontime, winsize) self.SetPagePopupMenu(where, menu) self.SetPageFirstGradientColour(where, firstcol) self.SetPageSecondGradientColour(where, secondcol) self._pages[where]._ishidden = ishidden if isanimated and len(animatedimages) > 1: self.SetAnimationImages(where, animatedimages) self.StartAnimation(where, timer) if enabled: self._parent.bsizer.Show(where, True) else: sel = self.GetSelection() if sel == -1: sel = 0 self._parent.bsizer.Show(where, False) self._parent.SetSelection(sel) self._parent.bsizer.Show(sel, True) self._parent.bsizer.Layout() self._parent.Thaw() self._isdragging = False self._olddragpos = -1 self._fromdnd = True self.Refresh() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return if nPage >= 0 and where >= 0: panel = oldNotebook.GetPage(nPage) if panel: eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, oldNotebook.GetId()) eventOut.SetOldPosition(nPage) eventOut.SetNewPosition(where) eventOut.SetEventObject(oldNotebook) if oldNotebook.GetEventHandler().ProcessEvent(eventOut): oldNotebook.nb._tabID = -1 oldNotebook.nb._olddragpos = -1 oldNotebook.SetCursor(wx.STANDARD_CURSOR) oldNotebook.Refresh() return oldNotebook.Freeze() infos = oldNotebook.GetPageInfo(nPage) text = infos["text"] image = infos["image"] hidden = infos["ishidden"] panel.Reparent(newNotebook) newNotebook.InsertPage(where, panel, text, True, image, hidden) newNotebook.SetPageInfo(where, infos) oldNotebook.nb.DeletePage(nPage) oldNotebook.bsizer.Detach(nPage) oldNotebook.bsizer.Layout() oldNotebook.sizer.Layout() oldNotebook._notebookpages.pop(nPage) oldNotebook.AdvanceSelection() if oldNotebook.GetPageCount() == 0: if oldNotebook._style & NC_TOP: oldNotebook.sizer.Show(0, False) oldNotebook.sizer.Show(1, False) else: oldNotebook.sizer.Show(1, False) oldNotebook.sizer.Show(2, False) oldNotebook.sizer.Layout() oldNotebook.Thaw() newNotebook.Refresh() return wx.DragMove def OnLeaveWindow(self, event): """ Handles The wx.EVT_LEAVE_WINDOW Events For TabCtrl. """ if self._enabledragging: if self._isdragging: page = self._parent.GetPage(self._tabID) draginfo = NCDragInfo(page, self._tabID) drginfo = cPickle.dumps(draginfo) dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) dataobject.SetData(drginfo) dragSource = wx.DropSource(self) dragSource.SetData(dataobject) dragSource.DoDragDrop(wx.Drag_DefaultMove) self._isleaving = True self.Refresh() if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() event.Skip() def OnKeyDown(self, event): """ Handles The wx.EVT_KEY_DOWN Event For TabCtrl. This Is Only Processed If The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. """ if event.GetKeyCode() == wx.WXK_TAB: if event.ControlDown(): sel = self.GetSelection() if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel): sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 self._parent.SetSelection(sel) event.Skip() def AddPage(self, text, select=False, img=-1, hidden=False): """ Add A Page To The Notebook. @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ self._pages.append(TabbedPage(text, img, hidden)) self._somethingchanged = True self._firsttime = True self._timers.append(wx.Timer(self)) # JS: The following two lines caused this control not to fire # the EVT_NOTEBOOKCTRL_PAGE_CHANGING/CHANGED events for the # first page. The NotebookCtrl sets the selection later anyway, # and without these two lines, the events fire. ## if select or self.GetSelection() == -1: ## self._selection = self.GetPageCount() - 1 if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self.Refresh() def InsertPage(self, nPage, text, select=False, img=-1, hidden=False): """ Insert A Page Into The Notebook. @param nPage: Specifies The Position For The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" oldselection = self.GetSelection() self._pages.insert(nPage, TabbedPage(text, img, hidden)) self._timers.insert(nPage, wx.Timer(self)) self._somethingchanged = True self._firsttime = True if select or self.GetSelection() == -1: self._selection = nPage self.SetSelection(nPage) else: if nPage <= oldselection: self._selection = self._selection + 1 if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self.Refresh() def DeleteAllPages(self): """ Deletes All NotebookCtrl Pages. """ for tims in self._timers: if tims.IsRunning(): tims.Stop() tims.Destroy() self._timers = [] self._pages = [] self._selection = -1 self._somethingchanged = True self._firsttime = True self.Refresh() def DeletePage(self, nPage, oncontinue=True): """ Deletes The Page nPage, And The Associated Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" oldselection = self.GetSelection() self._pages.pop(nPage) if self._timers[nPage].IsRunning(): self._timers[nPage].Stop() self._timers[nPage].Destroy() if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False if not oncontinue: self._somethingchanged = True self._firsttime = True self.Refresh() return if nPage < self._selection: self._selection = self._selection - 1 elif self._selection == nPage and self._selection == self.GetPageCount(): self._selection = self._selection - 1 else: self._selection = oldselection self._somethingchanged = True self._firsttime = True self.Refresh() def SetSelection(self, nPage): """ Sets The Current Tab Selection To The Given nPage. This Call Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" oldselection = self._selection if nPage != self._selection: if not self.IsPageEnabled(nPage): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) eventOut.SetSelection(nPage) eventOut.SetOldSelection(self._selection) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): # Prevent full paint unless never fully painted if hasattr(self, "_initrect"): self._firsttime = False # Program Allows The Page Change self._selection = nPage eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) eventOut.SetOldSelection(self._selection) self.GetEventHandler().ProcessEvent(eventOut) if oldselection != -1: self._parent.bsizer.Show(oldselection, False) self.EnsureVisible(self._selection) self._parent.bsizer.Show(self._selection, True) self._parent.bsizer.Layout() self.Refresh() self._shown = nPage def EnsureVisible(self, selection): if self.GetPageCount() < 2: return if not self.HasSpinButton(): return fullrect = self.GetClientSize() count = self._tabvisible[0:selection].count(0) #stani patch: correct for too big values, play safe sindex = selection-self._firstvisible-count if sindex >= len(self._tabrect): sindex = len(self._tabrect)-1 selection = sindex+self._firstvisible+count currect = self._tabrect[sindex] spinval = self._spinbutton.GetValue() firstrect = self._initrect[spinval] if self._style & NC_LEFT or self._style & NC_RIGHT: pos = currect.y size = currect.height posIndex = 1 else: pos = currect.x size = currect.width posIndex = 0 torefresh = 0 while pos + size > fullrect[posIndex] - self._spinbutton.GetSize()[posIndex]: if self._style & NC_LEFT or self._style & NC_RIGHT: pos -= firstrect.height else: pos -= firstrect.width if not self._enablehiding: spinval = spinval + 1 else: oldspinval = spinval spinval = spinval + self._tabvisible[0:selection].count(0) if spinval == oldspinval: spinval = spinval + 1 if spinval >= len(self._initrect): spinval = spinval - 1 firstrect = self._initrect[spinval] if self._style & NC_LEFT or self._style & NC_RIGHT: self._spinbutton.OnSpin(-spinval) self._spinbutton.SetValue(-spinval) else: self._spinbutton.OnSpin(spinval) self._spinbutton.SetValue(spinval) torefresh = 1 if torefresh: self.Refresh() def GetPageCount(self): """ Returns The Number Of Pages In NotebookCtrl. """ return len(self._pages) def GetSelection(self): """ Returns The Current Selection. """ return self._selection def GetImageList(self): """ Returns The Image List Associated With The NotebookCtrl. """ return self._imglist def SetImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self._imglist = imagelist self._grayedlist = wx.ImageList(16, 16, True, 0) for ii in xrange(imagelist.GetImageCount()): bmp = imagelist.GetBitmap(ii) image = wx.ImageFromBitmap(bmp) image = GrayOut(image) newbmp = wx.BitmapFromImage(image) self._grayedlist.Add(newbmp) def AssignImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self._imglist = imagelist self._grayedlist = wx.ImageList(16, 16, True, 0) for ii in xrange(imagelist.GetImageCount()): bmp = imagelist.GetBitmap(ii) image = wx.ImageFromBitmap(bmp) image = GrayOut(image) newbmp = wx.BitmapFromImage(image) self._grayedlist.Add(newbmp) def GetPadding(self): """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ return self._padding def SetPadding(self, padding): """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ self._padding = padding self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageText(self, nPage): """ Returns The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" return self._pages[nPage]._text def SetPageText(self, nPage, text): """ Sets The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" if self._pages[nPage]._text != text: self._pages[nPage]._text = text self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageImage(self, nPage): """ Returns The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" return self._pages[nPage]._image def SetPageImage(self, nPage, img): """ Sets The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" if self._pages[nPage]._image != img: self._pages[nPage]._image = img self._somethingchanged = True self._firsttime = True if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self.Refresh() def SetPageTextFont(self, nPage, font=None): """ Sets The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pages[nPage]._font = font if font == normalfont: self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() return dc = wx.ClientDC(self) dc.SetFont(font) w1, h1 = dc.GetTextExtent("Aq") dc.SetFont(normalfont) wn, hn = dc.GetTextExtent("Aq") w2, h2 = (0, 0) if hasattr(self._pages[nPage], "_secondaryfont"): dc.SetFont(self._pages[nPage]._secondaryfont) w2, h2 = dc.GetTextExtent("Aq") h = max(h1, h2) if h < hn: self._somethingchanged = True self._firsttime = True self.Refresh() return if h + 2*self._padding.y < 24: newheight = 24 else: newheight = h + 2*self._padding.y oldsize = self.GetSize() if newheight < oldsize[1]: newheight = oldsize[1] if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(dc), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def SetTabHeight(self, height=28): """ Sets The Tabs Height. """ if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, height)) self._bestsize = height def SetControlBackgroundColour(self, colour=None): """ Sets The TabCtrl Background Colour (Behind The Tabs). """ if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) self.SetBackgroundColour(colour) self.Refresh() def GetPageTextFont(self, nPage): """ Returns The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" return self._pages[nPage]._font def SetPageTextSecondaryFont(self, nPage, font=None): """ Sets The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pages[nPage]._secondaryfont = font if font == normalfont: self._somethingchanged = True self._firsttime = True self.Refresh() return dc = wx.ClientDC(self) dc.SetFont(font) w1, h1 = dc.GetTextExtent("Aq") dc.SetFont(normalfont) wn, hn = dc.GetTextExtent("Aq") w2, h2 = (0, 0) if hasattr(self._pages[nPage], "_font"): dc.SetFont(self._pages[nPage]._font) w2, h2 = dc.GetTextExtent("Aq") h = max(h1, h2) if h < hn: self._somethingchanged = True self._firsttime = True self.Refresh() return if h + 2*self._padding.y < 24: newheight = 24 else: newheight = h + 2*self._padding.y oldsize = self.GetSize() if newheight < oldsize[-1]: newheight = oldsize[-1] if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(dc), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageTextSecondaryFont(self, nPage): """ Returns The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" return self._pages[nPage]._secondaryfont def SetPageTextColour(self, nPage, colour=None): """ Sets The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" if colour is None: colour = wx.BLACK self._pages[nPage]._pagetextcolour = colour self._somethingchanged = True self.Refresh() def GetPageTextColour(self, nPage): """ Returns The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" return self._pages[nPage]._pagetextcolour def SetPageColour(self, nPage, colour=None): """ Sets The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._pages[nPage]._pagecolour = colour self._somethingchanged = True self.Refresh() def GetPageColour(self, nPage): """ Returns The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" if not self._tabstyle._normal or self._usegradients: if self._usegradients: return self._tabstyle._firstcolour else: return self._GetThemePageColour(nPage) else: return self._pages[nPage]._pagecolour def EnablePage(self, nPage, enable=True): """ Enable/Disable The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" self._pages[nPage]._enable = enable if not enable and self.GetSelection() == nPage: defpage = self.GetDefaultPage() if defpage < 0: self.AdvanceSelection() else: if defpage >= self.GetPageCount(): self.AdvanceSelection() else: if defpage == nPage: self.AdvanceSelection() else: self.SetSelection(defpage) self.Refresh() def IsPageEnabled(self, nPage): """ Returns Whether A Page Is Enabled Or Not. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" return self._pages[nPage]._enable def SetHighlightSelection(self, highlight=True): """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ self._highlight = highlight self.Refresh() def GetHighlightSelection(self): """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ return self._highlight def SetUseFocusIndicator(self, focus=True): """ Globally Enables/Disables Tab Focus Indicator. """ self._usefocus = focus self.Refresh() def GetUseFocusIndicator(self): """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ return self._usefocus def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): """ Sets A ToolTip For The Given Page nPage. @param nPage: The Given Page; @param tooltip: The ToolTip String; @param timer: The Timer After Which The Tip Window Is Popped Up; @param winsize: The Maximum Width Of The Tip Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" self._pages[nPage]._tooltip = tooltip self._pages[nPage]._tooltiptime = timer self._pages[nPage]._winsize = winsize def GetPageToolTip(self, nPage): """ Returns A Tuple With All Page ToolTip Parameters. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" return self._pages[nPage]._tooltip, self._pages[nPage]._tooltiptime, \ self._pages[nPage]._winsize def EnableToolTip(self, show=True): """ Globally Enables/Disables Tab ToolTips. """ self._showtooltip = show if show: try: wx.PopupWindow(self) self.TransientTipWindow = TransientTipWindow except NotImplementedError: self.TransientTipWindow = macTransientTipWindow else: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() if self._tiptimer.IsRunning(): self._tiptimer.Stop() def GetToolTipBackgroundColour(self): """ Returns The ToolTip Window Background Colour. """ return self._backtooltip def SetToolTipBackgroundColour(self, colour=None): """ Sets The ToolTip Window Background Colour. """ if colour is None: colour = wx.Colour(255, 255, 230) self._backtooltip = colour def EnableTabGradients(self, enable=True): """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ self._usegradients = enable if enable: self._tabstyle.ResetDefaults() self._selstyle.ResetDefaults() self.Refresh() def SetPageFirstGradientColour(self, nPage, colour=None): """ Sets The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" if colour is None: colour = wx.WHITE self._pages[nPage]._firstcolour = colour self.Refresh() def SetPageSecondGradientColour(self, nPage, colour=None): """ Sets The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" if colour is None: color = self._pages[nPage]._firstcolour r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._pages[nPage]._secondcolour = colour self.Refresh() def GetPageFirstGradientColour(self, nPage): """ Returns The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" return self._pages[nPage]._firstcolour def GetPageSecondGradientColour(self, nPage): """ Returns The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" return self._pages[nPage]._secondcolour def CancelTip(self): """ Destroys The Tip Window (Probably You Won't Need This One). """ if self._istooltipshown: self._istooltipshown = False self._tipwindow.Destroy() self.Refresh() def AdvanceSelection(self, forward=True): """ Cycles Through The Tabs. The Call To This Function Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if self.GetPageCount() <= 1: return sel = self.GetSelection() count = 0 if forward: if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel) or \ (self._enablehiding and self._pages[sel]._ishidden): count = count + 1 sel = sel + 1 if self._enablehiding and self._pages[sel]._ishidden: count = count + 1 sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 if count > self.GetPageCount() + 1: return None else: if sel == 0: sel = self.GetPageCount() - 1 else: sel = sel - 1 while not self.IsPageEnabled(sel): count = count + 1 sel = sel - 1 if sel == 0: sel = self.GetPageCount() - 1 if count > self.GetPageCount() + 1: return None self._parent.SetSelection(sel) def SetDefaultPage(self, defaultpage=-1): """ Sets The Default Page That Will Be Selected When An Active And Selected Tab Is Made Inactive. """ if defaultpage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" self._defaultpage = defaultpage def GetDefaultPage(self): """ Returns The Default Page. """ return self._defaultpage def UpdateSpinButton(self): """ Update The NotebookSpinButton. Used Internally. """ count = self.GetPageCount() if count == 0: return nbsize = [] nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) clsize = self.GetClientSize() if self._style & NC_TOP or self._style & NC_BOTTOM: spinstyle = wx.SP_HORIZONTAL showspin = nbsize[0] > clsize[0] else: spinstyle = wx.SP_VERTICAL showspin = nbsize[1] > clsize[1] if showspin: if not hasattr(self, "_spinbutton"): self._spinbutton = NotebookSpinButton(self, pos=(10000,10000), style=spinstyle) self._spinbutton.SetValue(0) self._originalspinsize = self._spinbutton.GetSize() sbsize = self._spinbutton.GetSize() if self._style & NC_LEFT or self._style & NC_RIGHT: ypos = clsize[1] - sbsize[1] if self._style & NC_LEFT: xpos = nbsize[0] - (2 + sbsize[0]) else: xpos = 2 else: xpos = clsize[0] - sbsize[0] if self._style & NC_BOTTOM: ypos = 2 else: ypos = clsize[1] - sbsize[1] if self.HasMenuButton(): self._spinbutton.SetSize((-1, 16)) else: self._spinbutton.SetSize(self._originalspinsize) self._spinbutton.Move((xpos, ypos)) self._spinbutton.Show() if self._style & NC_LEFT or self._style & NC_RIGHT: self._spinbutton.SetRange(-(count-1), 0) else: self._spinbutton.SetRange(0, count-1) else: if hasattr(self, "_spinbutton") and self._spinbutton.IsShown(): self._spinbutton.Hide() self._spinbutton.SetValue(0) def HasSpinButton(self): """ Returns Wheter The NotebookSpinButton Exists And Is Shown. """ return hasattr(self, "_spinbutton") and self._spinbutton.IsShown() def IsLastVisible(self): """ Returns Whether The Last Tab Is Visible Or Not. """ if self.HasSpinButton(): if self._style & NC_LEFT or self._style & NC_RIGHT: pos, size = (1, 3) else: pos, size = (0, 2) lastpos = self._tabrect[-1][pos] + self._tabrect[-1][size] if lastpos < self._spinbutton.GetPosition()[pos]: return True return False def UpdateMenuButton(self, show): """ Updates The Notebook Menu Button To Show/Hide Tabs. Used Internally. """ count = self.GetPageCount() if count == 0: return if not hasattr(self, "_initrect"): return if not show and not hasattr(self, "_menubutton"): return if not hasattr(self, "_menubutton"): self._menubutton = NotebookMenuButton(self, pos=(10000,10000)) sbsize = self._menubutton.GetSize() nbsize = [] nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) clsize = self.GetClientSize() xpos = clsize[0] - sbsize[0] ypos = clsize[1] - sbsize[1] if self.HasSpinButton(): self._menubutton.Move((xpos-1, ypos-16)) else: self._menubutton.Move((xpos-1, ypos-1)) self._menubutton.Show(show) def HasMenuButton(self): """ Returns Wheter The NotebookMenuButton Exists And Is Shown. """ return hasattr(self, "_menubutton") and self._menubutton.IsShown() def HideTab(self, nPage, hide=True): """ Hides A Tab In The NotebookCtrl. """ if hide: self._pages[nPage]._ishidden = True else: self._pages[nPage]._ishidden = False if nPage == self.GetSelection(): self.AdvanceSelection() self._firsttime = True self.Refresh() def HitTest(self, point, flags=0): """ Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It Returns The Page Clicked (If Any) And One Of These Flags: NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab NC_HITTEST_ONICON = 1 ==> Hit On Icon NC_HITTEST_ONLABEL = 2 ==> Hit On Label NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page """ mirror = self._style & NC_BOTTOM size = self.GetSize() dc = wx.ClientDC(self) height = self._tabrect[0].height if flags: flags = wx.NB_HITTEST_NOWHERE if point.x <= 0 or point.x >= size.x: if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND if not point.y >= self._tabrect[0].y and point.y < self._tabrect[0].y + height: if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND posx = self._firsttabpos.x posy = self._firsttabpos.y maxwidth = max(self._maxtabwidths) for ii in xrange(self._firstvisible, self.GetPageCount()): if not self._enablehiding or not self._pages[ii]._ishidden: width = self._CalcTabTextWidth(dc, ii) bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) tabrect = self._CalcTabRect(ii, posx, posy, width, bmpWidth, bmpHeight) if tabrect.Contains(point): if flags: flags = NC_HITTEST_ONITEM #onx attempt if self.GetDrawX()[0]: count = self._tabvisible[0:ii].count(0) if flags and self._xrect[ii-self._firstvisible-count].Contains(point): flags = NC_HITTEST_ONX #onicon attempt if flags and bmpWidth > 0 and \ wx.RectPS(wx.Point(*self._CalcTabBitmapPosition(ii, bmpWidth, bmpHeight, tabrect)), wx.Size(bmpWidth, bmpHeight)).Contains(point): flags = NC_HITTEST_ONICON #onlabel attempt elif flags and wx.RectPS(wx.Point(*self._CalcTabTextPosition(ii, tabrect, self._CalcTabBitmapSpace(bmpWidth, bmpHeight))), wx.Size(width, height)).Contains(point): flags = NC_HITTEST_ONLABEL if flags: return ii, flags else: return ii if self._style & NC_TOP or self._style & NC_BOTTOM: posx += tabrect.width else: posy += tabrect.height if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND def EnableDragAndDrop(self, enable=True): """ Globall Enables/Disables Tabs Drag And Drop. """ self._enabledragging = enable def EnableHiding(self, enable=True): """ Globally Enables/Disables Hiding On Tabs In Runtime. """ self._enablehiding = enable self.UpdateMenuButton(enable) wx.FutureCall(1000, self.UpdateMenuButton, enable) def SetAnimationImages(self, nPage, imgarray): """ Sets An Animation List Associated To The Given Page nPage. @param nPage: The Given Page @param imgarray: A List Of Image Indexes Of Images Inside The ImageList Associated To NotebookCtrl. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" if not imgarray: raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" if min(imgarray) < 0: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ str(min(imgarray)) + " < 0)" if max(imgarray) > self.GetImageList().GetImageCount() - 1: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" self._pages[nPage]._animationimages = imgarray def GetAnimationImages(self, nPage): """ Returns The Animation Images List Associated To The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" return self._pages[nPage]._animationimages def AnimateTab(self, event): """ Called When The Refreshing Animation Timer Expires. Used Internally""" obj = event.GetEventObject() nPage = self._timers.index(obj) if not self.IsPageEnabled(nPage): return indx = self.GetPageImage(nPage) images = self.GetAnimationImages(nPage) myindx = images.index(indx) if indx == images[-1]: myindx = -1 myindx = myindx + 1 self.SetPageImage(nPage, images[myindx]) def StartAnimation(self, nPage, timer=500): """ Starts The Animation On The Given Page, With Refreshing Time Rate "timer". """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" images = self.GetAnimationImages(nPage) if not images: raise "\nERROR: No Images Array Defined For Page: (" + str(nPage) + ")" if len(images) == 1: raise "\nERROR: Impossible To Animate Tab: " + str(nPage) + " With Only One Image" self._timers[nPage].Start(timer) def StopAnimation(self, nPage): """ Stops The Animation On The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" if self._timers[nPage].IsRunning(): self._timers[nPage].Stop() def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): """ Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. @param drawx: C{True} to enable drawing a closing "X"; C{False} to disable it @param style: the style of the X to draw when C{drawx} is C{True}; possible values are: - C{1}: Small "X" At The Top-Right Of The Tab; - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); - C{3}: Custom "X" Image Is Drawn On Tabs. @param image1: if C{style} is C{3}, the image to use when drawing the X on an unhighlighted tab @param image2: if C{style} is C{3}, the image to use when drawing the X on a highlighted tab """ self._drawx = drawx self._drawxstyle = style if style == 3: self._imglist2 = wx.ImageList(16, 16, True, 0) self._imglist2.Add(image1) self._imglist2.Add(image2) if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self.Refresh() def GetDrawX(self): """ Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of Every Page. """ return self._drawx, self._drawxstyle def GetInsideTab(self, pt): """ Returns The Tab On Which The Mouse Is Hovering On. """ count = 0 for tabs in self._tabrect: if tabs.Contains(pt): return count count = count + 1 return -1 def GetInsideX(self, pt): """ Returns The Tab On Which The Mouse Is Hovering On The "X" Button. """ count = 0 for rects in self._xrect: if rects.Contains(pt): return count count = count + 1 return -1 def SetImageToCloseButton(self, convert=True): """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ self._convertimage = convert def GetImageToCloseButton(self): """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ return self._convertimage def ConvertImageToCloseButton(self, page): """ Globally Converts The Page Image To The "Opera" Style Close Button. """ bmpindex = self.GetPageImage(page) if bmpindex < 0: return tabrect = self._tabrect[page] size = self.GetSize() maxfont = self._maxfont dc = wx.ClientDC(self) dc.SetFont(maxfont) pom, height = dc.GetTextExtent("Aq") bmp = self._imglist.GetBitmap(bmpindex) bmpposx = tabrect.x + self._padding.x bmpposy = size.y - (height + 2*self._padding.y + bmp.GetHeight())/2 - 1 ypos = size.y - height - self._padding.y*2 ysize = height + self._padding.y*2 + 3 if page == self.GetSelection(): bmpposx = bmpposx + 1 bmpposy = bmpposy - 1 ypos = ypos - 3 ysize = ysize + 2 colour = self.GetPageColour(page) bmprect = wx.Rect(bmpposx, bmpposy, bmp.GetWidth()+self._padding.x, bmp.GetHeight()) dc.SetBrush(wx.Brush(colour)) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangleRect(bmprect) colour = self.GetPageTextColour(page) r = colour.Red() g = colour.Green() b = colour.Blue() hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) colour = wx.Colour(hr, hg, hb) back_colour = wx.WHITE yypos = ypos+(ysize-height-self._padding.y/2)/2 xrect = wx.Rect(bmprect.x+(bmprect.width - self._padding.x - height)/2, yypos, height, height) # Opera Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.Brush(colour)) dc.DrawRoundedRectangleRect(xrect, 2) dc.SetPen(wx.Pen(back_colour, 2)) dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) def RedrawClosingX(self, pt, insidex, drawx, highlight=False): """ Redraw The Closing "X" Accordingly To The Mouse "Hovering" Position. """ colour = self.GetPageTextColour(insidex) back_colour = self.GetBackgroundColour() imagelist = 0 if highlight: r = colour.Red() g = colour.Green() b = colour.Blue() hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) colour = wx.Colour(hr, hg, hb) back_colour = wx.WHITE imagelist = 1 dc = wx.ClientDC(self) xrect = self._xrect[insidex] if drawx == 1: # Emule Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRectangleRect(xrect) elif drawx == 2: # Opera Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.Brush(colour)) dc.DrawRoundedRectangleRect(xrect, 2) dc.SetPen(wx.Pen(back_colour, 2)) dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) else: self._imglist2.Draw(imagelist, dc, xrect[0], xrect[1], wx.IMAGELIST_DRAW_TRANSPARENT, True) def HideOnSingleTab(self, hide=True): """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ self._hideonsingletab = hide def SetPagePopupMenu(self, nPage, menu): """ Sets A Popup Menu Specific To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" self._pages[nPage]._menu = menu def GetPagePopupMenu(self, nPage): """ Returns The Popup Menu Associated To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" return self._pages[nPage]._menu def DrawInsertionMark(self, dc, nPage): """ Draw An Insertion Arrow To Let The User Understand Where A Dragged Tab Will Be Dropped (Between Which Tabs). """ if not self._enablehiding: if nPage < 0 or nPage >= len(self._tabrect): return else: if nPage < 0 or nPage >= len(self._tabrect) + self._tabvisible.count(0): return colour = wx.BLACK somehidden = False if self._enablehiding: for ii in xrange(nPage): if self._pages[ii]._ishidden: nPage = nPage - 1 somehidden = True rect = self._tabrect[nPage] x1 = rect.x - 4 y1 = rect.y - 1 x2 = rect.x y2 = y1 + 5 x3 = rect.x + 3 y3 = y1 mybrush = wx.Brush(self.GetPageTextColour(nPage)) if not self._enablehiding: if nPage > self._tabID: x1 = x1 + rect.width x2 = x2 + rect.width x3 = x3 + rect.width else: mybrush = wx.Brush(self.GetPageTextColour(nPage)) if nPage >= self._tabID: x1 = x1 + rect.width x2 = x2 + rect.width x3 = x3 + rect.width dc.SetPen(wx.Pen(wx.BLACK, 1)) dc.SetBrush(mybrush) dc.DrawPolygon([(x1, y1), (x2, y2), (x3, y3)]) def OnMouseMotion(self, event): """ Handles The wx.EVT_MOTION Event For TabCtrl. """ pt = event.GetPosition() if self._enabledragging: if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): tolerance = 2 dx = abs(pt.x - self._dragstartpos.x) dy = abs(pt.y - self._dragstartpos.y) if dx <= tolerance and dy <= tolerance: self.SetCursor(wx.STANDARD_CURSOR) return self.SetCursor(self._dragcursor) self._isdragging = True self._isleaving = False newpos = self.HitTest(pt) if newpos >= 0 and newpos != self._olddragpos: self._olddragpos = newpos self.Refresh() else: self._isdragging = False self.SetCursor(wx.STANDARD_CURSOR) if not event.Dragging(): drawx = self.GetDrawX() if drawx[0]: insidex = self.GetInsideX(pt) if insidex >= 0: if self.IsPageEnabled(insidex): self.RedrawClosingX(pt, insidex, drawx[1], True) self._xrefreshed = False else: if not self._xrefreshed: insidetab = self.GetInsideTab(pt) if insidetab >= 0: if self.IsPageEnabled(insidetab): self.RedrawClosingX(pt, insidetab, drawx[1]) self._xrefreshed = True else: if self.GetImageToCloseButton(): page, flags = self.HitTest(pt, 1) if page >= 0: if self.IsPageEnabled(page): if flags == NC_HITTEST_ONICON: if not self._imageconverted: self.ConvertImageToCloseButton(page) self._imageconverted = True else: if self._imageconverted: self.Refresh() self._imageconverted = False if self._showtooltip: if not event.Dragging(): if not event.LeftDown(): oldinside = self._insidetab self._insidetab = self.GetInsideTab(pt) if self._insidetab >= 0: if oldinside != self._insidetab: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() if self._tiptimer.IsRunning(): self._tiptimer.Stop() tip, ontime, winsize= self.GetPageToolTip(self._insidetab) if tip.strip() != "": self._currenttip = tip self._currentwinsize = winsize self._tiptimer.Start(ontime, wx.TIMER_ONE_SHOT) else: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() self._mousepos = pt event.Skip() def OnShowToolTip(self): """ Called When The Timer For The ToolTip Expires. Used Internally. """ pt = self.ScreenToClient(wx.GetMousePosition()) oldinside = self._insidetab self._insidetab = self.GetInsideTab(pt) if self._insidetab != oldinside or self._insidetab < 0: return self._istooltipshown = True self._tipwindow = self.TransientTipWindow(self, self._currenttip, self._currentwinsize) xsize, ysize = self._tipwindow.GetSize() xpos, ypos = self.ClientToScreen(self._mousepos) if xpos + xsize > self._xvideo - 10: if ypos + ysize > self._yvideo - 10: # SW Tip Positioning posx = xpos - xsize posy = ypos - ysize else: # NE Tip Positioning posx = xpos - xsize posy = ypos else: if ypos + ysize > self._yvideo - 10: # SE Tip Positioning posx = xpos + 10 posy = ypos - ysize else: # NW Tip Positioning posx = xpos + 10 posy = ypos if posy < 0: posy = ypos if posx < 0: posx = xpos self._tipwindow.SetPosition((posx, posy)) self._tipwindow.Show() def OnMouseLeftDown(self, event): """ Handles The wx.EVT_LEFT_DOWN Event For TabCtrl. """ pos = event.GetPosition() page, flags = self.HitTest(pos, 1) self._dragstartpos = pos if page != wx.NOT_FOUND: if self.IsPageEnabled(page): if event.m_controlDown: if page in self._selectedtabs: self._selectedtabs.remove(page) else: self._selectedtabs.append(page) self.Refresh() else: self._selectedtabs = [] if flags == NC_HITTEST_ONX or (flags == NC_HITTEST_ONICON and self.GetImageToCloseButton()): eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): self._parent.DeletePage(page) self._parent.bsizer.Layout() else: self.SetSelection(page) self._tabID = page event.Skip() def OnMouseLeftDClick(self, event): """ Handles The wx.EVT_LEFT_DCLICK Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def OnMouseLeftUp(self, event): """ Handles The wx.EVT_LEFT_UP Event For TabCtrl. """ if not self._enabledragging: event.Skip() return if not self._isdragging: self.SetCursor(wx.STANDARD_CURSOR) event.Skip() return id = self.HitTest(wx.Point(event.GetX(), event.GetY())) if id >= 0 and id != self._tabID: self._isdragging = False self._olddragpos = -1 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) eventOut.SetOldPosition(self._tabID) eventOut.SetNewPosition(id) eventOut.SetEventObject(self) if self.GetEventHandler().ProcessEvent(eventOut): self._tabID = -1 self._olddragpos = -1 self.SetCursor(wx.STANDARD_CURSOR) self.Refresh() return self._parent.Freeze() try: text = self.GetPageText(self._tabID) image = self.GetPageImage(self._tabID) font1 = self.GetPageTextFont(self._tabID) font2 = self.GetPageTextSecondaryFont(self._tabID) fontcolour = self.GetPageTextColour(self._tabID) pagecolour = self.GetPageColour(self._tabID) enabled = self.IsPageEnabled(self._tabID) tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) menu = self.GetPagePopupMenu(self._tabID) firstcol = self.GetPageFirstGradientColour(self._tabID) secondcol = self.GetPageSecondGradientColour(self._tabID) ishidden = self._pages[self._tabID]._ishidden except: self._parent.Thaw() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return isanimated = 0 if self._timers[self._tabID].IsRunning(): isanimated = 1 timer = self._timers[self._tabID].GetInterval() self.StopAnimation(self._tabID) animatedimages = self.GetAnimationImages(self._tabID) pagerange = range(self.GetPageCount()) newrange = pagerange[:] newrange.remove(self._tabID) newrange.insert(id, self._tabID) newpages = [] counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): newpages.append(self._parent.GetPage(ii)) self._parent.bsizer.Detach(counter-ii) cc = 0 self._parent._notebookpages = [] for jj in newrange: self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) self._parent.bsizer.Show(cc, False) self._parent._notebookpages.append(newpages[jj]) cc = cc + 1 self.DeletePage(self._tabID) if enabled: if id == self.GetPageCount(): self.AddPage(text, True, image) else: self.InsertPage(id, text, True, image) else: if id == self.GetPageCount(): self.AddPage(text, False, image) else: self.InsertPage(id, text, False, image) self.SetPageImage(id, image) self.SetPageText(id, text) self.SetPageTextFont(id, font1) self.SetPageTextSecondaryFont(id, font2) self.SetPageTextColour(id, fontcolour) self.SetPageColour(id, pagecolour) self.EnablePage(id, enabled) self.SetPageToolTip(id, tooltip, ontime, winsize) self.SetPagePopupMenu(id, menu) self.SetPageFirstGradientColour(id, firstcol) self.SetPageSecondGradientColour(id, secondcol) self._pages[id]._ishidden = ishidden if isanimated and len(animatedimages) > 1: self.SetAnimationImages(id, animatedimages) self.StartAnimation(id, timer) if enabled: self._parent.bsizer.Show(id, True) else: sel = self.GetSelection() if sel == -1: sel = 0 self._parent.bsizer.Show(id, False) self._parent.SetSelection(sel) self._parent.bsizer.Show(sel, True) self._parent.bsizer.Layout() self._parent.Thaw() self._isdragging = False self._olddragpos = -1 self._fromdnd = True self.Refresh() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) event.Skip() def OnSize(self, event=None): """ Handles The wx.EVT_SIZE Event For TabCtrl. """ if self._sizeToggleButton: width = self.GetSize()[0] height = self._CalcSizeToggleBestSize()[1] self._sizeToggleButton.SetSize(wx.Size(width, height)) self.Refresh() if event is not None: event.Skip() def OnMouseRightUp(self, event): """ Handles The wx.EVT_RIGHT_UP Event For TabCtrl. """ pt = event.GetPosition() id = self.HitTest(pt) self._selectedtabs = [] if id >= 0: if self.IsPageEnabled(id): menu = self.GetPagePopupMenu(id) if menu: self.PopupMenu(menu) event.Skip() def OnMouseRightDown(self, event): """ Handles The wx.EVT_RIGHT_DOWN Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def OnMouseMiddleDown(self, event): """ Handles The wx.EVT_MIDDLE_DOWN Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def SetSelectionColour(self, colour=None): """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ if colour is None: colour = wx.Colour(255, 180, 0) self._selectioncolour = colour def SetContourLineColour(self, colour=None): """ Sets The Contour Line Colour (Controur Line Around Tabs). """ if colour is None: if not self._tabstyle._normal or self._usegradients: colour = wx.Colour(145, 167, 180) else: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) if not self._tabstyle._normal or self._usegradients: self._highlightpen = wx.Pen(colour) self._highlightpen.SetCap(wx.CAP_BUTT) else: self._highlightpen2 = wx.Pen(colour) self._highlightpen2.SetCap(wx.CAP_BUTT) self.Refresh() def ApplyTabTheme(self, theme=None): """ Applies A Particular Theme To Be Drawn On Tabs. """ if theme is None: theme = ThemeStyle() self._tabstyle = theme if self._style & NC_EXPANDABLE: self._InitExpandableTabStyles(self._style, self._expanded, theme) self.Refresh() def DrawMacTheme(self, dc, tabrect, theme): """ Draws The Mac Theme On Tabs, If It Is Enabled. """ if theme == 1: col1, col2 = NC_MAC_LIGHT else: col1, col2 = NC_MAC_DARK colour1 = wx.Colour(col1, col1, col1) colour2 = wx.Colour(col2, col2, col2) x, y, w, h = tabrect endrange = self._style & NC_ROTATE and w or h index = 0 for ii in xrange(0, endrange, 2): if index%2 == 0: colour = colour1 else: colour = colour2 dc.SetBrush(wx.Brush(colour)) dc.SetPen(wx.Pen(colour)) if self._style & NC_ROTATE: if ii > 3: dc.DrawRectangle(x+ii, y, 2, w) else: dc.DrawRoundedRectangle(x+ii, y, 3, 3) else: if ii > 3: dc.DrawRectangle(x, y+ii, w, 2) else: dc.DrawRoundedRectangle(x, y+ii, w, 3, 3) index = index + 1 self._lastcolour = colour def DrawKDETheme(self, dc, rect): """ Draws Unix-Style KDE Theme On Tabs. """ x, y, w, h = rect if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(13, -1, -1) self._lastcolour = kdetheme[13] brush = wx.Brush(kdetheme[0], wx.SOLID) else: bandrange = xrange(14) self._lastcolour = kdetheme[0] brush = wx.Brush(kdetheme[13], wx.SOLID) dc.SetBackground(brush) for band in bandrange: pen = wx.Pen(kdetheme[band]) dc.SetPen(pen) if self._style & NC_ROTATE: if self._style & NC_RIGHT: dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) dc.DrawLine(x+w-(1+band), y+1, x+w-(1+band), y+h-2) else: dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) dc.DrawLine(x+w-(2+band), y+1, x+w-(2+band), y+h-2) else: dc.DrawLine(x+1, y+band, x+w-1, y+band) dc.DrawLine(x+1, y+h-1-band, x+w-2, y+h-1-band) def DrawSilverTheme(self, dc, rect, selected): """ Draws Windows XP Silver-Like Theme. """ x, y, w, h = rect if selected: r1 = silvertheme1[0].Red() g1 = silvertheme1[0].Green() b1 = silvertheme1[0].Blue() r2 = silvertheme1[1].Red() g2 = silvertheme1[1].Green() b2 = silvertheme1[1].Blue() else: r1 = silvertheme2[0].Red() g1 = silvertheme2[0].Green() b1 = silvertheme2[0].Blue() r2 = silvertheme2[1].Red() g2 = silvertheme2[1].Green() b2 = silvertheme2[1].Blue() rend = silvertheme2[2].Red() gend = silvertheme2[2].Green() bend = silvertheme2[2].Blue() if self._style & NC_ROTATE: flrect = float(w-2) else: flrect = float(h-2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 if self._style & NC_ROTATE: if self._style & NC_RIGHT: bandrange = xrange(x+w-2, x, -1) else: bandrange = xrange(x+1, x+w-1) else: bandrange = xrange(y+1, y+h) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) dc.SetPen(wx.Pen(currCol)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 dc.DrawRectangle(band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol if not selected and self._style & NC_TOP: dc.SetBrush(wx.Brush((rend, gend, bend))) dc.SetPen(wx.Pen((rend, gend, bend))) if self._style & NC_ROTATE: if self._style & NC_LEFT: xpos = x + w - 4 else: xpos = x dc.DrawRectangle(xpos, ypos, 3, yend) else: dc.DrawRectangle(xpos, y+h-3, xend, 3) self._lastcolour = wx.Colour(rend, gend, bend) def DrawAquaTheme(self, dc, rect, style, selected): """ Draws Mac-Style Aqua Theme On Tabs. """ x, y, w, h = rect if selected: if style == 1: # Dark Aqua r1 = topaqua1[0].Red() g1 = topaqua1[0].Green() b1 = topaqua1[0].Blue() r2 = topaqua1[1].Red() g2 = topaqua1[1].Green() b2 = topaqua1[1].Blue() else: r1 = topaqua2[0].Red() g1 = topaqua2[0].Green() b1 = topaqua2[0].Blue() r2 = topaqua2[1].Red() g2 = topaqua2[1].Green() b2 = topaqua2[1].Blue() else: r1 = distaqua[0].Red() g1 = distaqua[0].Green() b1 = distaqua[0].Blue() r2 = distaqua[1].Red() g2 = distaqua[1].Green() b2 = distaqua[1].Blue() flrect = float((h-2)/2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 dc.SetPen(wx.TRANSPARENT_PEN) if self._style & NC_ROTATE: startrange, endrange = (x, w) else: startrange, endrange = (y, h) if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(startrange+endrange, startrange+endrange/2, -1) else: bandrange = xrange(startrange+1, startrange+endrange/2) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 dc.DrawRectangle(band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 rf = rf + rstep gf = gf + gstep bf = bf + bstep if selected: if style == 1: # Dark Aqua r1 = botaqua1[0].Red() g1 = botaqua1[0].Green() b1 = botaqua1[0].Blue() r2 = botaqua1[1].Red() g2 = botaqua1[1].Green() b2 = botaqua1[1].Blue() else: r1 = botaqua2[0].Red() g1 = botaqua2[0].Green() b1 = botaqua2[0].Blue() r2 = botaqua2[1].Red() g2 = botaqua2[1].Green() b2 = botaqua2[1].Blue() else: r1 = disbaqua[0].Red() g1 = disbaqua[0].Green() b1 = disbaqua[0].Blue() r2 = disbaqua[1].Red() g2 = disbaqua[1].Green() b2 = disbaqua[1].Blue() flrect = float((h-2)/2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(startrange+endrange/2, startrange+1, -1) else: bandrange = xrange(startrange+endrange/2, startrange+endrange) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if self._style & NC_ROTATE: dc.DrawRectangle(band, y + 1, 1, h-2) else: dc.DrawRectangle(x+1, band, w-2, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def DrawMetalTheme(self, dc, rect): """ Draws Mac-Style Metal Gradient On Tabs. """ x, y, w, h = rect dc.SetPen(wx.TRANSPARENT_PEN) counter = 0 if self._style & NC_ROTATE: bandrange = xrange(x+1, x+w) else: bandrange = xrange(y+1, h+y) for band in bandrange: if self._style & NC_ROTATE: intens = (230 + 80 * (x-band)/w) else: intens = (230 + 80 * (y-band)/h) colour = wx.Colour(intens, intens, intens) dc.SetBrush(wx.Brush(colour)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 if self._style & NC_RIGHT: dc.DrawRectangle(x+w-band, ypos, 1, yend) else: dc.DrawRectangle(x+band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 self._lastcolour = colour def DrawVerticalGradient(self, dc, rect, index): """ Gradient Fill From Colour 1 To Colour 2 From Top To Bottom. """ dc.SetPen(wx.TRANSPARENT_PEN) # calculate gradient coefficients col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.height) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 bandrange = xrange(rect.y+1, rect.y + rect.height-1) lenc = len(bandrange) for y in bandrange: currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) # adjust along x-axis to preserve the curved tab edge def GetXAdjust(counter): if counter >=2 or counter <=lenc-2: return 1 if self._style & NC_LEFT or self._style & NC_RIGHT and not self._style & NC_ROTATE: if counter == 0 and self._style & NC_RIGHT or \ counter == lenc - 1 and self._style & NC_LEFT: return 3 elif counter == 1 and self._style & NC_RIGHT or \ counter == lend - 2 and self._style & NC_LEFT: return 2 else: return 1 else: if counter == lenc - 2: return 2 elif counter == lenc - 1: return 3 else: return 1 xadjust = GetXAdjust(counter) xpos = rect.x + xadjust xend = rect.width - xadjust counter = counter + 1 dc.DrawRectangle(xpos, y, xend, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def DrawHorizontalGradient(self, dc, rect, index): """ Gradient Fill From Colour 1 To Colour 2 From Left To Right. """ dc.SetPen(wx.TRANSPARENT_PEN) # calculate gradient coefficients col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.width) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 bandrange = xrange(rect.x + 1, rect.x + rect.width - 1) lenc = len(bandrange) for x in bandrange: currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) # adjust along y-axis to preserve the curved tab edge def GetYAdjust(counter): if counter >=2 or counter <=lenc-2: return 1 if self._style & NC_TOP or self._style & NC_BOTTOM or \ (self._style & NC_LEFT and self._style & NC_ROTATE): if counter == 0 or counter == lenc - 1 and not self._style & NC_LEFT: return 3 elif counter == 1 or counter == lenc - 2 and not self._style & NC_LEFT: return 2 else: return 1 else: if counter == lenc - 2: return 2 elif counter == lenc - 1: return 3 else: return 1 yadjust = GetYAdjust(counter) ypos = rect.y + yadjust yend = rect.height - yadjust counter = counter + 1 dc.DrawRectangle(x, ypos, 1, yend) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def GetAllTextExtents(self, dc): """ Returns All Tabs Text Extents. Used Internally. """ self._mintabwidths = [] self._maxtabwidths = [] self._mintabheights = [] self._maxtabheights = [] self._incrtext = [] minheight = 0 for ii in xrange(self.GetPageCount()): txts = self.GetPageText(ii) font1 = self.GetPageTextFont(ii) dc.SetFont(font1) w1, h1 = dc.GetTextExtent(txts) minheight = max(minheight, h1) self._mintabwidths.append(w1) self._mintabheights.append(h1) font2 = self.GetPageTextSecondaryFont(ii) dc.SetFont(font2) w2, h2 = dc.GetTextExtent(txts) minheight = max(minheight, h2) self._maxtabwidths.append(w2) self._maxtabheights.append(h2) self._incrtext.append(abs(self._mintabwidths[ii] - self._maxtabwidths[ii])) mh1 = max(self._mintabheights) font1 = self.GetPageTextFont(self._mintabheights.index(mh1)) mh2 = max(self._maxtabheights) font2 = self.GetPageTextSecondaryFont(self._maxtabheights.index(mh2)) mhend = max(mh1, mh2) if mhend == mh1: maxfont = font1 else: maxfont = font2 minheight = self.GetSize()[1] return minheight, maxfont def DrawBuiltinStyle(self, dc, style, rect, index, selection): """ Methods That Holds All The Theme Styles. """ if style._aqua: if self._selstyle._normal: self.DrawAquaTheme(dc, rect, style._aqua, index==selection) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._metal: if self._selstyle._normal: self.DrawMetalTheme(dc, rect) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._kdetheme: if self._selstyle._normal: self.DrawKDETheme(dc, rect) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._macstyle: if self._selstyle._normal: self.DrawMacTheme(dc, rect, style._macstyle) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._gradient: if self._selstyle._normal: if style._gradient & ThemeStyle.GRADIENT_VERTICAL: self.DrawVerticalGradient(dc, rect, index) else: self.DrawHorizontalGradient(dc, rect, index) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._silver: if self._selstyle._normal: self.DrawSilverTheme(dc, rect, index==selection) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle def DrawGradientOnTab(self, dc, rect, col1, col2): """ Draw A Gradient Coloured Tab. """ dc.SetPen(wx.TRANSPARENT_PEN) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.height) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 for y in xrange(rect.y+1, rect.y + rect.height): currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if counter == 0: xpos = rect.x + 2 xend = rect.width - 4 elif counter == 1: xpos = rect.x + 1 xend = rect.width - 2 else: xpos = rect.x xend = rect.width counter = counter + 1 dc.DrawRectangle(xpos, y, xend, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def _CalcBestWidth(self, dc): return max(self._CalcMaxTabWidth(dc), self._CalcSizeToggleBestSize()[0]) def _CalcMaxTabWidth(self, dc): self._CalcMaxTextHeight(dc) textWidth = max(self._maxtabwidths) tabIndex = self._maxtabwidths.index(textWidth) bmpWidth, bmpHeight = self._CalcTabBitmapSize(tabIndex) tabrect = self._CalcTabRect(tabIndex, 0, 0, textWidth, bmpWidth, bmpHeight) # return the width based on the longest label, plus 3 for # the additional width of the selected tab return tabrect.width + 3 def _CalcMaxTextHeight(self, dc): if self._somethingchanged: minheight, maxfont = self.GetAllTextExtents(dc) self._minheight = minheight self._maxfont = maxfont else: minheight = self._minheight maxfont = self._maxfont dc.SetFont(maxfont) _, height = dc.GetTextExtent("Aq") self._maxtextheight = height def _CalcSizeToggleBestSize(self): if self._sizeToggleButton: return self._sizeToggleButton.GetBestSize() else: return wx.Size(0,0) def _CalcTabBitmapPosition(self, tabIndex, bmpWidth, bmpHeight, tabrect): if self._style & NC_ROTATE: bmpposx = tabrect.x + (tabrect.width - bmpWidth) / 2 yoffset = self._padding.x if self._style & NC_LEFT: bmpposx += 1 bmpposy = tabrect.y + tabrect.height - (yoffset + bmpHeight) else: bmpposy = tabrect.y + yoffset if tabIndex == self.GetSelection(): bmpposx += self._style & NC_LEFT and -1 or 1 else: bmpposx = tabrect.x + self._padding.x bmpposy = tabrect.y + (tabrect.height - bmpHeight) / 2 if tabIndex == self.GetSelection() and self._style & NC_TOP: bmpposy -= 1 return (bmpposx, bmpposy) def _CalcTabBitmapSize(self, tabIndex): result = (0, 0) bmp = self._GetTabBitmap(tabIndex) bmpOk = bmp.Ok() if bmpOk: result = (bmp.GetWidth(), bmp.GetHeight()) return result def _CalcTabBitmapSpace(self, bmpWidth, bmpHeight): space = self._padding.x bmpSpace = self._style & NC_ROTATE and bmpHeight or bmpWidth if bmpSpace: space = space + self._padding.x + bmpSpace return space def _CalcTabRect(self, tabIndex, posx, posy, textWidth, bmpWidth, bmpHeight): xpos = posx if self._style & NC_BOTTOM: ypos = 1 elif self._style & NC_TOP: ypos = self.GetSize().y - self._maxtextheight - self._padding.y*2 else: ypos = posy xsize = textWidth + self._CalcTabBitmapSpace(bmpWidth, bmpHeight) + \ self._padding.x + self._incrtext[tabIndex] + \ self._CalcXWidth() ysize = self._maxtextheight + self._padding.y*2 if self._style & NC_TOP: ysize += 3 if self._style & NC_ROTATE: xsize, ysize = (ysize, xsize) if tabIndex == self.GetSelection(): if self._style & NC_TOP or self._style & NC_BOTTOM: xsize = xsize + self._spacetabs if tabIndex > 0: xpos = xpos - self._spacetabs xsize = xsize + self._spacetabs if self._style & NC_TOP: ypos -= 3 ysize = ysize + 2 else: xsize += 3 if self._style & NC_LEFT: xpos = self.GetSize().width - xsize return wx.Rect(xpos, ypos, xsize, ysize) def _CalcTabTextPosition(self, tabIndex, tabrect, space): xtextpos = tabrect.x + space + self._incrtext[tabIndex]/2 if self._style & NC_BOTTOM: ytextpos = self._padding.y else: ytextpos = tabrect.y + self._padding.y + 1 if tabIndex == self.GetSelection(): if tabIndex == 0 and self._style & NC_TOP or self._style & NC_BOTTOM: xtextpos = xtextpos + self._spacetabs/2.0 + 1 if self._style & NC_BOTTOM: ytextpos += 2 elif self._style & NC_TOP: ytextpos -= 2 if self._style & NC_ROTATE: xoffset = ytextpos - tabrect.y yoffset = xtextpos - tabrect.x if self._style & NC_LEFT: xtextpos, ytextpos = (tabrect.x + xoffset - 1, tabrect.y + tabrect.height - yoffset) else: yoffset += self._CalcXWidth() xtextpos, ytextpos = (tabrect.x + tabrect.width - xoffset, tabrect.y + yoffset) return (xtextpos, ytextpos) def _CalcTabTextWidth(self, dc, tabIndex): if self._style & NC_FIXED_WIDTH: result = max(self._maxtabwidths) else: dc.SetFont(self.GetPageTextFont(tabIndex)) result, _ = dc.GetTextExtent(self.GetPageText(tabIndex)) return result def _CalcXRect(self, tabrect): result = None drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: mins = min(self._padding.x, self._padding.y) + 1 mins = min(mins, 6) xoffset = tabrect.width-mins-3 yoffset = 2 xsize = ysize = mins+1 else: if self._style & NC_ROTATE: xoffset = (tabrect.width-self._maxtextheight-self._padding.y/2)/2 yoffset = self._padding.x/2 else: xoffset = tabrect.width-self._maxtextheight-self._padding.x yoffset = (tabrect.height-self._maxtextheight-self._padding.y/2)/2 xsize = ysize = self._maxtextheight result = wx.Rect(tabrect.x+xoffset, tabrect.y+yoffset, xsize, ysize) return result def _CalcXWidth(self): drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: xxspace = self._padding.x/2 else: xxspace = self._padding.x + self._maxtextheight else: xxspace = 0 return xxspace def _ClipAtPaperEdge(self, dc, tabrect, tabIndex): selected = tabIndex == self.GetSelection() if self._style & NC_TOP: cliprect = (tabrect.x, tabrect.y, tabrect.width, selected and tabrect.height - 2 or tabrect.height-3) elif self._style & NC_LEFT: cliprect = (tabrect.x, tabrect.y, tabrect.width - 2, tabrect.height) elif self._style & NC_BOTTOM: cliprect = (tabrect.x, tabrect.y + 2, tabrect.width, tabrect.height - 2) else: cliprect = (tabrect.x + 2, tabrect.y, tabrect.width - 2, tabrect.height) dc.SetClippingRegion(*cliprect) def _CreateSizeToggleButton(self): buttonlabel = self._expanded and "<<" or ">>" self._sizeToggleButton = wx.Button(self, wx.NewId(), pos = wx.Point(0,0,), label = buttonlabel, style=wx.BU_EXACTFIT) font = self._sizeToggleButton.GetFont() if font.GetPointSize() > 6: font.SetPointSize(6) self._sizeToggleButton.SetFont(font) self.Bind(wx.EVT_BUTTON, self._ToggleSize, self._sizeToggleButton) def _DrawBackground(self, dc, paintTools): #background size = self.GetSize() dc.SetBrush(paintTools.BackBrush) if not (self._style & wx.NO_BORDER): # full border dc.SetPen(paintTools.BorderPen) dc.SetPen(paintTools.HighlightPen) dc.DrawRectangle(0, 0, size.x, size.y) else: dc.SetPen(paintTools.BackPen) dc.DrawRectangle(0, 0, size.x, size.y) self._DrawPageEdge(dc, paintTools) def _DrawFocusIndicator(self, dc, paintTools, tabrect): if self.GetUseFocusIndicator(): dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.FocusPen) dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2, tabrect.y+self._padding.y/2, tabrect.width-self._padding.x, tabrect.height-self._padding.y-2, 2) def _DrawPageEdge(self, dc, paintTools): if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(0, self.GetSize().y-1, self.GetSize().x, self.GetSize().y-1) else: if not self._tabstyle._normal or self._usegradients: dc.SetPen(paintTools.HighlightPen) else: dc.SetPen(paintTools.BorderPen) if self._style & NC_BOTTOM: dc.DrawLine(0, 1, self.GetSize().x, 1) elif self._style & NC_LEFT: dc.DrawLine(self.GetSize().width - 1, 0, self.GetSize().width - 1, self.GetSize().height) elif self._style & NC_RIGHT: dc.DrawLine(0, 0, 0, self.GetSize().height) def _DrawTab(self, dc, paintTools, tabrect, tabIndex): size = self.GetSize() self._DrawTabGradientOutline(dc, paintTools, tabrect, tabIndex) self._FillTab(dc, paintTools, tabrect, tabIndex) self._DrawTabOutline(dc, paintTools, tabrect, tabIndex) self._DrawTabPageEdge(dc, paintTools, tabrect, tabIndex) self._HighlightTabEdge(dc, paintTools, tabrect) self._ShadowTabEdge(dc, paintTools, tabrect) def _DrawTabBitmap(self, dc, tabIndex, bmpposx, bmpposy): bmpindex = self.GetPageImage(tabIndex) if self.IsPageEnabled(tabIndex): self._imglist.Draw(bmpindex, dc, bmpposx, bmpposy, wx.IMAGELIST_DRAW_TRANSPARENT, True) else: self._grayedlist.Draw(bmpindex, dc, bmpposx, bmpposy, wx.IMAGELIST_DRAW_TRANSPARENT, True) def _DrawTabGradientOutline(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: if tabIndex != self.GetSelection() and self._style & NC_TOP: dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.ShadowPen) dc.DrawRoundedRectangle(tabrect.x+1, tabrect.y+1, tabrect.width, tabrect.height-1, 3) def _DrawTabOutline(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.HighlightPen) else: dc.SetBrush(wx.Brush(self.GetPageColour(tabIndex))) if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) else: dc.SetPen(paintTools.BorderPen) self._ClipAtPaperEdge(dc, tabrect, tabIndex) dc.DrawRoundedRectangle(tabrect.x, tabrect.y, tabrect.width, tabrect.height, 3) dc.DestroyClippingRegion() def _DrawTabPageEdge(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: edgePen = paintTools.HighlightPen else: if self._style & NC_TOP: edgePen = paintTools.HighlightPen else: edgePen = paintTools.BorderPen if tabIndex == self.GetSelection(): # un-paint the line at the paper edge cancelPen = wx.Pen(self.GetPageColour(tabIndex)) dc.SetPen(cancelPen) if self._style & NC_BOTTOM: dc.DrawLine(tabrect.x+1, tabrect.y, tabrect.x + tabrect.width, tabrect.y) elif self._style & NC_LEFT: dc.DrawLine(tabrect.x + tabrect.width-1, tabrect.y, tabrect.x + tabrect.width-1, tabrect.y + tabrect.height) elif self._style & NC_RIGHT: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + tabrect.height) if tabIndex != self.GetSelection(): if self._style & NC_TOP: dc.DrawLine(tabrect.x, self.GetSize().y-1, tabrect.x + tabrect.width, self.GetSize().y-1) # draw sharp corners at the paper edge dc.SetPen(edgePen) if self._style & NC_BOTTOM: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + 2) dc.DrawLine((tabrect.x + tabrect.width)-1, tabrect.y, (tabrect.x + tabrect.width)-1, tabrect.y + 2) elif self._style & NC_LEFT: dc.DrawLine(self.GetSize().width - 2, tabrect.y, self.GetSize().width, tabrect.y) dc.DrawLine(self.GetSize().width - 2, tabrect.y + tabrect.height - 1, self.GetSize().width, tabrect.y + tabrect.height - 1) elif self._style & NC_RIGHT: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x + 2, tabrect.y) dc.DrawLine(tabrect.x, tabrect.y + tabrect.height - 1, tabrect.x + 2, tabrect.y + tabrect.height - 1) def _DrawTabText(self, dc, tabIndex, xtextpos, ytextpos): dc.SetFont(self.GetPageTextFont(tabIndex)) dc.SetTextForeground(self._GetTabTextColour(tabIndex)) dc.SetBrush(wx.TRANSPARENT_BRUSH) if self._style & NC_ROTATE: angle = (self._style & NC_LEFT) and 90.0 or 270.0 dc.DrawRotatedText(self.GetPageText(tabIndex), xtextpos, ytextpos, angle) else: dc.DrawText(self.GetPageText(tabIndex), xtextpos, ytextpos) def _DrawX(self, dc, tabrect, xrect, textColour): drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: mins = min(self._padding.x, self._padding.y) + 1 mins = min(mins, 6) dc.SetPen(wx.Pen(textColour, 1)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawLine(xrect.x, xrect.y, tabrect.x+tabrect.width-2, tabrect.y+3+mins) dc.DrawLine(xrect.x, xrect.y+mins, tabrect.x+tabrect.width-2, tabrect.y+1) dc.DrawRectangle(xrect.x, xrect.y, xrect.width, xrect.height) elif dxstyle == 2: dc.SetPen(wx.Pen(textColour)) dc.SetBrush(wx.Brush(textColour)) dc.DrawRoundedRectangle(xrect.x, xrect.y, xrect.width, xrect.height, 2) dc.SetPen(wx.Pen(self.GetBackgroundColour(), 2)) dc.DrawLine(xrect.x+2, xrect.y+2, xrect.x+xrect.width-3, xrect.y+xrect.height-3) dc.DrawLine(xrect.x+2, xrect.y+xrect.height-3, xrect.x+xrect.width-3, xrect.y+2) else: self._imglist2.Draw(0, dc, xrect.x, xrect.y, wx.IMAGELIST_DRAW_TRANSPARENT, True) def _EnhanceMultiSelectedTab(self, dc, tabIndex, tabrect): dc.SetPen(wx.Pen(self._GetTabTextColour(tabIndex), 1, wx.DOT_DASH)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2+1, tabrect.y+self._padding.y/2+1, tabrect.width-self._padding.x-2, tabrect.height-self._padding.y-2-2, 2) def _EnhanceSelectedTab(self, dc, paintTools, tabrect): xselpos = tabrect.x xselsize = tabrect.width yselsize = tabrect.height if self._style & NC_BOTTOM: yselpos = (tabrect.y + tabrect.height) - 2 elif self._style & NC_TOP: yselpos = tabrect.y self._HighlightSelectedTabEdge(dc, paintTools, tabrect) self._ShadowTabEdge(dc, paintTools, tabrect) self._DrawFocusIndicator(dc, paintTools, tabrect) def _FillTab(self, dc, paintTools, tabrect, tabIndex): if self._usegradients: self.DrawGradientOnTab(dc, tabrect, self._pages[tabIndex]._firstcolour, self._pages[tabIndex]._secondcolour) elif not self._tabstyle._normal: self.DrawBuiltinStyle(dc, self._tabstyle, tabrect, tabIndex, self.GetSelection()) def _GetPaintTools(self): back_colour = self.GetBackgroundColour() back_brush = wx.Brush(back_colour) back_pen = wx.Pen(back_colour) border_pen = self._borderpen highlightpen = self._highlightpen if self._tabstyle._normal and not self._usegradients: highlightpen = self._highlightpen2 shadowpen = self._shadowpen upperhighpen = self._upperhigh if self.GetHighlightSelection(): selectionpen = wx.Pen(self._selectioncolour) selectionEdgePen = wx.Pen(self._selectionedgecolour) else: selectionpen = selectionEdgePen = None x_pen = self.GetDrawX() == 1 and wx.BLACK_PEN or None focusindpen = self.GetUseFocusIndicator() and self._focusindpen or None return _TabCtrlPaintTools(back_brush, back_pen, border_pen, highlightpen, shadowpen, upperhighpen, selectionpen, selectionEdgePen, x_pen, focusindpen) def _GetTabBitmap(self, tabIndex): bmp = wx.NullBitmap if self.GetPageImage(tabIndex) >= 0: bmpindex = self.GetPageImage(tabIndex) if self.IsPageEnabled(tabIndex): bmp = self._imglist.GetBitmap(bmpindex) else: bmp = self._grayedlist.GetBitmap(bmpindex) return bmp def _GetTabTextColour(self, tabIndex): if self.IsPageEnabled(tabIndex): result = self.GetPageTextColour(tabIndex) else: result = self._disabledcolour return result def _GetThemePageColour(self, index): if self._tabstyle._macstyle: return NC_MAC_LIGHT elif self._tabstyle._kdetheme: return kdetheme[0] elif self._tabstyle._aqua: if index == self.GetSelection(): return topaqua1[0] else: return distaqua[0] elif self._tabstyle._metal: intens = (230 + 80 * (self._tabrect[0].y-self._tabrect[0].y+1)/self._tabrect[0].height) return wx.Colour(intens, intens, intens) elif self._tabstyle._silver: if index == self.GetSelection(): return silvertheme1[0] else: return silvertheme2[0] elif self._tabstyle._gradient: color = wx.WHITE if self._tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: if self._style & NC_TOP: color = self._tabstyle.GetSecondGradientColour(index) elif self._style & NC_BOTTOM: color = self._tabstyle.GetFirstGradientColour(index) elif self._tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and \ self._style & NC_ROTATE: if self._style & NC_LEFT: color = self._tabstyle.GetSecondGradientColour(index) else: color = self._tabstyle.GetFirstGradientColour(index) return color def _HighlightSelectedTabEdge(self, dc, paintTools, tabrect): if self._style & NC_ROTATE: yselpos = tabrect.y + 3 yselsize = tabrect.height - 6 xselpos = self._style & NC_RIGHT and tabrect.x + tabrect.width - 1 or tabrect.x if self.GetHighlightSelection(): dc.SetBrush(paintTools.BackBrush) dc.SetPen(paintTools.SelectionEdgePen) dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) dc.SetPen(paintTools.SelectionPen) for band in range(2): if self._style & NC_RIGHT: xselpos -= 1 else: xselpos += 1 yselpos -= 1 yselsize += 2 dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) else: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) else: xselpos = tabrect.x + 3 xselsize = tabrect.width - 6 if self._style & NC_BOTTOM: yselpos = tabrect.y + tabrect.height - 1 else: yselpos = tabrect.y dc.SetPen(paintTools.HighlightPen) dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) if self.GetHighlightSelection(): dc.SetBrush(paintTools.BackBrush) dc.SetPen(paintTools.SelectionEdgePen) dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) dc.SetPen(paintTools.SelectionPen) for band in range(2): if self._style & NC_BOTTOM: yselpos -= 1 else: yselpos += 1 xselpos -= 1 xselsize += 2 dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) def _HighlightTabEdge(self, dc, paintTools, tabrect): if not self._tabstyle._normal or self._usegradients: if self._style & NC_TOP: dc.SetPen(paintTools.UpperHighlightPen) dc.DrawLine(tabrect.x+2, tabrect.y-1, tabrect.x + tabrect.width - 2, tabrect.y-1) else: if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(tabrect.x + 3, tabrect.y, tabrect.x + tabrect.width - 3, tabrect.y) def _InitExpandableStyles(self, style): self._expanded = not style & NC_ROTATE if self._expanded: self._expandedstyle = style self._contractedstyle = style | NC_ROTATE else: self._contractedstyle = style self._expandedstyle = (style ^ NC_ROTATE) | NC_FIXED_WIDTH def _InitExpandableTabStyles(self, style, expanded, tabstyle): if tabstyle._gradient: alternatestyle = ThemeStyle() firstcolor = tabstyle.GetFirstGradientColour() secondcolor = tabstyle.GetSecondGradientColour() swapcolors = (tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL and style & NC_RIGHT and expanded) or \ (tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and style & NC_RIGHT and not expanded) if swapcolors: firstcolor, secondcolor = (secondcolor, firstcolor) if tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_VERTICAL) | ThemeStyle.GRADIENT_HORIZONTAL else: othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_HORIZONTAL) | ThemeStyle.GRADIENT_VERTICAL alternatestyle.EnableGradientStyle(True, othergradient) alternatestyle.SetFirstGradientColour(firstcolor) alternatestyle.SetSecondGradientColour(secondcolor) if tabstyle._gradient & ThemeStyle.DIFFERENT_GRADIENT_FOR_SELECTED: firstcolor = tabstyle.GetFirstGradientColour(True) secondcolor = tabstyle.GetSecondGradientColour(True) if swapcolors: firstcolor, secondcolor = (secondcolor, firstcolor) alternatestyle.SetFirstGradientColourSelected(firstcolor) alternatestyle.SetSecondGradientColourSelected(secondcolor) if expanded: self._expandedtabstyle = tabstyle self._contractedtabstyle = alternatestyle else: self._contractedtabstyle = tabstyle self._expandedtabstyle = alternatestyle else: self._expandedtabstyle = tabstyle self._contractedtabstyle = tabstyle def _OnStyleChange(self): if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def _ShadowTabEdge(self, dc, paintTools, tabrect): dc.SetPen(paintTools.ShadowPen) if self._style & NC_BOTTOM: dc.DrawLine((tabrect.x + tabrect.width), tabrect.y+1, (tabrect.x+tabrect.width), tabrect.y + tabrect.height-4) elif self._style & NC_TOP: dc.DrawLine(tabrect.x + tabrect.width, tabrect.y+3, tabrect.x+tabrect.width, tabrect.y+tabrect.height-4) def OnPaint(self, event): """ Handles The wx.EVT_PAINT Event For TabCtrl. """ dc = wx.BufferedPaintDC(self) if self.GetPageCount() == 0: event.Skip() return pt = self._GetPaintTools() dc.BeginDrawing() self._DrawBackground(dc, pt) self._CalcMaxTextHeight(dc) posx = self._firsttabpos.x posy = self._firsttabpos.y if self._style & NC_LEFT: _ = 1 if self._firsttime: if not hasattr(self, "_initrect"): self._initrect = [] if self.HasSpinButton() and self._fromdnd: self._firstvisible = self._spinbutton.GetValue() self._firsttime = False self._fromdnd = False else: self._initrect = [] self._firstvisible = 0 else: if self.HasSpinButton(): self._firstvisible = self._spinbutton.GetValue() else: self._firstvisible = 0 lastvisible = self.GetPageCount() #and tabs oncount = -1 self._tabvisible = [1]*self.GetPageCount() tabrect = [] # some theme style rendering routines expect this to exist, so # set it now: self._tabrect = tabrect Xrect = [] for ii in xrange(self._firstvisible, lastvisible): if not self._enablehiding or not self._pages[ii]._ishidden: oncount = oncount + 1 self._tabvisible[ii] = 1 newwidth = self._CalcTabTextWidth(dc, ii) bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) tabrect.append(self._CalcTabRect(ii, posx, posy, newwidth, bmpWidth, bmpHeight)) self._DrawTab(dc, pt, tabrect[-1], ii) self._DrawTabText(dc, ii, *self._CalcTabTextPosition(ii, tabrect[-1], self._CalcTabBitmapSpace(bmpWidth, bmpHeight))) if bmpWidth: self._DrawTabBitmap(dc, ii, *self._CalcTabBitmapPosition(ii, bmpWidth, bmpHeight, tabrect[-1])) if self.GetSelection() in [ii, ii - 1]: # Handle this special case on the selected tab and # on the tab that follows it (if there is one), to ensure # proper rendering of the selected tab's right edge self._EnhanceSelectedTab(dc, pt, tabrect[self.GetSelection() - self._firstvisible]) if self.GetDrawX()[0]: Xrect.append(self._CalcXRect(tabrect[-1])) self._DrawX(dc, tabrect[-1], Xrect[-1], self._GetTabTextColour(ii)) if ii in self._selectedtabs: self._EnhanceMultiSelectedTab(dc, ii, tabrect[-1]) if self._style & NC_TOP or self._style & NC_BOTTOM: # horizontally positioned tabs along top or bottom posx = posx + tabrect[-1].width else: # vertically stacked tabs along side posy = posy + tabrect[-1].height if self._firsttime: self._initrect.append(tabrect[oncount]) else: self._tabvisible[ii] = 0 self._xrect = Xrect if self._firsttime: self._firsttime = False self.UpdateMenuButton(self.HasMenuButton()) self.UpdateSpinButton() if self._enabledragging: if self._isdragging and not self._isleaving: self.DrawInsertionMark(dc, self._olddragpos) dc.EndDrawing() # ---------------------------------------------------------------------------- # # Class NotebookCtrl # This Is The Main Class Implementation # ---------------------------------------------------------------------------- # class NotebookCtrl(wx.Panel): """ Display one or more windows in a notebook. B{Events}: - B{EVT_NOTEBOOKCTRL_PAGE_CHANGING}: sent when the active page in the notebook is changing - B{EVT_NOTEBOOKCTRL_PAGE_CHANGED}: sent when the active page in the notebook has changed - B{EVT_NOTEBOOKCTRL_PAGE_CLOSING}: sent when a page in the notebook is closing - B{EVT_NOTEBOOKCTRL_PAGE_DND}: sent when a page has been dropped onto the notebook in a drag-drop operation - B{EVT_NOTEBOOKCTRL_PAGE_DCLICK}: sent when the user double-clicks a tab in the notebook - B{EVT_NOTEBOOKCTRL_PAGE_RIGHT}: sent when the user clicks a tab in the notebook with the right mouse button - B{EVT_NOTEBOOKCTRL_PAGE_MIDDLE}: sent when the user clicks a tab in the notebook with the middle mouse button """ def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=NC_DEFAULT_STYLE, sizer=wx.HORIZONTAL, margin=2, name="NotebookCtrl"): """ Default Class Constructor. @param style: Style For The NotebookCtrl, Which May Be: a) NC_TOP: NotebookCtrl Placed On Top (Default); b) NC_BOTTOM: NotebookCtrl Placed At The Bottom; c) NC_LEFT: NotebookCtrl Placed At The Left; d) NC_RIGHT: NotebookCtrl Placed At The Right; e) NC_FIXED_WIDTH: All Tabs Have The Same Width; f) wx.NO_BORDER: Shows No Border For The Control (Default, Looks Better); g) wx.STATIC_BORDER: Shows A Static Border On The Control. @param sizer: The Sizer Orientation For The Sizer That Holds All The Panels: Changing This Style Is Only Useful When You Use The Tile Method. In This Case, If sizer=wx.HORIZONTAL, All The Panels Will Be Shown In Columns, While If sizer=wx.VERTICAL All The Panels Will Be Shown In Rows. @param margin: An Integer Number Of Pixels That Add Space Above TabCtrl If style=NC_TOP, Or Below It If style=NC_BOTTOM """ wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN, name=name) self.nb = TabCtrl(self, -1, pos, size, style) self._notebookpages = [] if style & NC_TOP == 0 and style & NC_BOTTOM == 0 \ and style & NC_LEFT == 0 and style & NC_RIGHT == 0: style = style | NC_TOP if style & wx.NO_BORDER == 0 and \ style & wx.STATIC_BORDER == 0: style = style | wx.NO_BORDER self._style = style self._showcolumns = False self._showtabs = True self._sizerstyle = sizer self._custompanel = None self._focusswitch = False self._oldfocus = None if style & NC_TOP or style & NC_BOTTOM: self.sizer = wx.BoxSizer(wx.VERTICAL) self.tabsizer = wx.BoxSizer(wx.VERTICAL) else: self.sizer = wx.BoxSizer(wx.HORIZONTAL) self.tabsizer = wx.BoxSizer(wx.HORIZONTAL) self.bsizer = wx.BoxSizer(sizer) if style & NC_TOP or style & NC_BOTTOM: tabBorderFlag = wx.LEFT | wx.RIGHT else: tabBorderFlag = wx.TOP | wx.BOTTOM if style & NC_TOP or style & NC_LEFT: self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) self._AddMargin(style, margin) self.tabsizer.Add(self.nb, 0, wx.EXPAND) self.sizer.Add(self.bsizer, 1, wx.EXPAND) elif style & NC_BOTTOM or style & NC_RIGHT: self.sizer.Add(self.bsizer, 1, wx.EXPAND) self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) self.tabsizer.Add(self.nb, 0, wx.EXPAND) self._AddMargin(style, margin) self.SetSizer(self.sizer) self.tabsizer.Show(self.nb, False) self.sizer.Layout() self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) def OnKeyDown(self, event): """ Handles The wx.EVT_KEY_DOWN Event For NotebookCtrl. This Is Only Processed If The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. """ if event.GetKeyCode() == wx.WXK_TAB: if event.ControlDown(): sel = self.GetSelection() if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel): sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 self.SetSelection(sel) event.Skip() def OnMouseMotion(self, event): """ Handles The wx.EVT_MOTION Event For NotebookCtrl. """ if self.nb._enabledragging: if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): tolerance = 2 pt = event.GetPosition() dx = abs(pt.x - self.nb._dragstartpos.x) dy = abs(pt.y - self.nb._dragstartpos.y) if dx <= tolerance and dy <= tolerance: self.SetCursor(wx.STANDARD_CURSOR) return self.SetCursor(self.nb._dragcursor) self.nb._isdragging = True else: self.nb._isdragging = False self.SetCursor(wx.STANDARD_CURSOR) if self.nb._showtooltip: if self.nb._istooltipshown: pt = event.GetPosition() self.nb._insidetab = self.nb.GetInsideTab(pt) if self.nb._insidetab < 0: try: self.nb._tipwindow.Destroy() self.nb._istooltipshown = False except: self.nb._istooltipshown = False self.nb.Refresh() event.Skip() def EnableChildFocus(self, enable=True): """ Enables/Disables Sending EVT_NOTEBOOKCTRL_PAGE_CHANGING When In Tile Mode. """ self._focusswitch = enable def FindFocusedPage(self, obj): """ Find Which NotebookCtrl Page Has The Focus Based On Its Child Focus. """ while 1: if obj in self._notebookpages: return obj try: obj = obj.GetParent() except: return None return None def OnFocus(self, event): """ Handles The wx.EVT_CHILD_FOCUS Event For NotebookCtrl. """ if not self._focusswitch: event.Skip() return newfocus = self.FindFocusedPage(event.GetEventObject()) if newfocus == self._oldfocus or newfocus is None: event.Skip() return self._oldfocus = newfocus eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) nPage = self._notebookpages.index(newfocus) eventOut.SetSelection(nPage) eventOut.SetOldSelection(self.GetSelection()) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): # Program Allows The Page Change self.nb._selection = nPage eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) eventOut.SetOldSelection(self.nb._selection) self.GetEventHandler().ProcessEvent(eventOut) event.Skip() def AddPage(self, page, text, select=False, img=-1, hidden=False): """ Add A Page To The Notebook. @param page: Specifies The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ self.Freeze() oldselection = self.nb.GetSelection() if self.GetPageCount() == 0: if self.GetCustomPage() is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) self.bsizer.Layout() self.bsizer.Add(page, 1, wx.EXPAND | wx.ALL, 2) self.nb.AddPage(text, select, img, hidden) self._notebookpages.append(page) page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) if select: if oldselection >= 0: self.bsizer.Show(self.GetPage(oldselection), False) self.nb.SetSelection(self.GetPageCount()-1) self.bsizer.Layout() else: if oldselection >= 0: self.bsizer.Show(page, False) else: self.bsizer.Show(page, True) self.nb.SetSelection(self.GetPageCount()-1) self.bsizer.Layout() if self.GetPageCount() == 1: self.bsizer.Show(page, True) if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.bsizer.Layout() self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def InsertPage(self, nPage, page, text, select=False, img=-1, hidden=False): """ Insert A Page Into The Notebook. @param page: Specifies The New Page; @param nPage: Specifies The Position For The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. @param hidden: C{True} to hide the page; C{False} to display it """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" self.Freeze() oldselection = self.nb.GetSelection() if self.GetPageCount() == 0: if self.GetCustomPage() is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) if oldselection >= 0: self.bsizer.Show(oldselection, False) self.bsizer.Layout() if oldselection >= nPage: oldselection = oldselection + 1 self.nb.InsertPage(nPage, text, select, img, hidden) self.bsizer.Insert(nPage, page, 1, wx.EXPAND | wx.ALL, 2) self._notebookpages.insert(nPage, page) self.bsizer.Layout() page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) self.bsizer.Layout() if select: self.bsizer.Show(nPage, True) self.bsizer.Layout() else: if oldselection >= 0: self.bsizer.Show(oldselection, True) self.bsizer.Layout() else: self.bsizer.Show(nPage, True) self.bsizer.Layout() if self.GetPageCount() == 1: if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def GetPage(self, nPage): """ Returns The Window At The Given Position nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPage: (" + str(nPage) + ")" return self._notebookpages[nPage] def DeleteAllPages(self): """ Deletes All NotebookCtrl Pages. """ self.Freeze() counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): self.bsizer.Detach(counter-ii) panels = self.GetPage(counter-ii) panels.Destroy() self.nb.DeleteAllPages() self._notebookpages = [] self.nb._selection = -1 self.nb.Show(False) custom = self.GetCustomPage() if custom is not None: self.SetCustomPage(custom) custom.Show(True) self.bsizer.Layout() self._ShowTabCtrl(False) self.sizer.Layout() self.Thaw() def DeletePage(self, nPage): """ Deletes The Page nPage, And The Associated Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" oldselection = self.GetSelection() self.Freeze() panel = self.GetPage(nPage) self.bsizer.Detach(nPage) self.bsizer.Layout() self._notebookpages.pop(nPage) self.nb.DeletePage(nPage) panel.Destroy() if self.GetPageCount() > 0: if oldselection == nPage: if self.GetSelection() > 0: self.SetSelection(self.GetSelection()) else: self.SetSelection(self.GetSelection()) self.bsizer.Show(self.GetSelection()) self.bsizer.Layout() if self.GetPageCount() == 0: self.nb.Show(False) self._ShowTabCtrl(False) custom = self.GetCustomPage() if custom is not None: self.bsizer.Add(custom, 1, wx.EXPAND | wx.ALL, 2) custom.Show(True) self.bsizer.Layout() self.sizer.Layout() self.Thaw() return if self.GetPageCount() == 1: if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def SetSelection(self, nPage): """ Sets The Current Tab Selection To The Given nPage. This Call Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" oldselection = self.GetSelection() if oldselection == nPage: return self.nb.SetSelection(nPage) self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def GetPageCount(self): """ Returns The Number Of Pages In NotebookCtrl. """ return self.nb.GetPageCount() def GetSelection(self): """ Returns The Current Selection. """ return self.nb.GetSelection() def GetImageList(self): """ Returns The Image List Associated With The NotebookCtrl. """ return self.nb.GetImageList() def SetImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self.nb.SetImageList(imagelist) def AssignImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self.nb.AssignImageList(imagelist) def GetPadding(self): """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ return self.nb.GetPadding() def SetPadding(self, padding): """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ self.nb.SetPadding(padding) def SetUseFocusIndicator(self, focus=True): """ Globally Enables/Disables Tab Focus Indicator. """ self.nb.SetUseFocusIndicator(focus) def GetUseFocusIndicator(self): """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ return self.nb.GetUseFocusIndicator() def EnablePage(self, nPage, enable=True): """ Enable/Disable The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" self.nb.EnablePage(nPage, enable) def IsPageEnabled(self, nPage): """ Returns Whether A Page Is Enabled Or Not. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" return self.nb.IsPageEnabled(nPage) def SetHighlightSelection(self, highlight=True): """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ self.nb.SetHighlightSelection(highlight) def GetHighlightSelection(self): """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ return self.nb.GetHighlightSelection() def SetAnimationImages(self, nPage, imgarray): """ Sets An Animation List Associated To The Given Page nPage. @param nPage: The Given Page; @param imgarray: A List Of Image Indexes Of Images Inside The ImageList Associated To NotebookCtrl. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" if not imgarray: raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" if min(imgarray) < 0: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ str(min(imgarray)) + " < 0)" if max(imgarray) > self.GetImageList().GetImageCount() - 1: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" self.nb.SetAnimationImages(nPage, imgarray) def GetAnimationImages(self, nPage): """ Returns The Animation Images List Associated To The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" return self.nb.GetAnimationImages(nPage) def StartAnimation(self, nPage, timer=500): """ Starts The Animation On The Given Page nPage, With Refreshing Time Rate "timer". """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" self.nb.StartAnimation(nPage, timer) def StopAnimation(self, nPage): """ Stops The Animation On The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" self.nb.StopAnimation(nPage) def EnableDragAndDrop(self, enable=True): """ Globall Enables/Disables Tabs Drag And Drop. """ self.nb.EnableDragAndDrop(enable) def EnableHiding(self, enable=True): """ Globally Enables/Disables Hiding On Tabs In Runtime. """ self.nb.EnableHiding(enable) def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): """ Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. @param drawx: C{True} to enable drawing a closing "X"; C{False} to disable it @param style: the style of the X to draw when C{drawx} is C{True}; possible values are: - C{1}: Small "X" At The Top-Right Of The Tab; - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); - C{3}: Custom "X" Image Is Drawn On Tabs. @param image1: if C{style} is C{3}, the image to use when drawing the X on an unhighlighted tab @param image2: if C{style} is C{3}, the image to use when drawing the X on a highlighted tab """ self.nb.SetDrawX(drawx, style, image1, image2) def GetDrawX(self): """ Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of Every Page. """ return self.nb.GetDrawX() def SetImageToCloseButton(self, convert=True): """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ self.nb.SetImageToCloseButton(convert) def GetImageToCloseButton(self): """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ return self.nb._convertimage def HideOnSingleTab(self, hide=True): """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ self.nb.HideOnSingleTab(hide) if self.GetPageCount() == 1: if hide: self._ShowTabCtrl(False) else: self._ShowTabCtrl(True) self.sizer.Layout() def SetPagePopupMenu(self, nPage, menu): """ Sets A Popup Menu Specific To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" self.nb.SetPagePopupMenu(nPage, menu) def GetPagePopupMenu(self, nPage): """ Returns The Popup Menu Associated To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" return self.nb.GetPagePopupMenu(nPage) def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): """ Sets A ToolTip For The Given Page nPage. @param nPage: The Given Page; @param tooltip: The ToolTip String; @param timer: The Timer After Which The Tip Window Is Popped Up; @param winsize: The Maximum Width Of The Tip Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" self.nb.SetPageToolTip(nPage, tooltip, timer, winsize) def GetPageToolTip(self, nPage): """ Returns A Tuple With All Page ToolTip Parameters. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" return self.nb.GetPageToolTip(nPage) def EnableToolTip(self, show=True): """ Globally Enables/Disables Tab ToolTips. """ self.nb.EnableToolTip(show) def GetToolTipBackgroundColour(self): """ Returns The ToolTip Window Background Colour. """ return self.nb.GetToolTipBackgroundColour() def SetToolTipBackgroundColour(self, colour=None): """ Sets The ToolTip Window Background Colour. """ if colour is None: colour = wx.Colour(255, 255, 230) self.nb.SetToolTipBackgroundColour(colour) def EnableTabGradients(self, enable=True): """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ self.nb.EnableTabGradients(enable) def SetPageFirstGradientColour(self, nPage, colour=None): """ Sets The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" if colour is None: colour = wx.WHITE self.nb.SetPageFirstGradientColour(nPage, colour) def SetPageSecondGradientColour(self, nPage, colour=None): """ Sets The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" self.nb.SetPageSecondGradientColour(nPage, colour) def GetPageFirstGradientColour(self, nPage): """ Returns The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" return self.nb.GetPageFirstGradientColour(nPage) def GetPageSecondGradientColour(self, nPage): """ Returns The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" return self.nb.GetPageSecondGradientColour(nPage) def CancelTip(self): """ Destroys The Tip Window (Probably You Won't Need This One. """ self.nb.CancelTip() def AdvanceSelection(self, forward=True): """ Cycles Through The Tabs. The Call To This Function Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ self.nb.AdvanceSelection(forward) def SetDefaultPage(self, defaultpage=-1): """ Sets The Default Page That Will Be Selected When An Active And Selected Tab Is Made Inactive. """ if defaultpage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" self.nb.SetDefaultPage(defaultpage) def GetDefaultPage(self): """ Returns The Default Page. """ return self.nb.GetDefaultPage() def GetPageText(self, nPage): """ Returns The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" return self.nb.GetPageText(nPage) def SetPageText(self, nPage, text): """ Sets The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" self.nb.SetPageText(nPage, text) def GetPageImage(self, nPage): """ Returns The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" return self.nb.GetPageImage(nPage) def SetPageImage(self, nPage, img): """ Sets The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" self.nb.SetPageImage(nPage, img) def SetPageTextFont(self, nPage, font=None): """ Sets The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self.nb.SetPageTextFont(nPage, font) def GetPageTextFont(self, nPage): """ Returns The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" return self.nb.GetPageTextFont(nPage) def SetPageTextSecondaryFont(self, nPage, font=None): """ Sets The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self.nb.SetPageTextSecondaryFont(nPage, font) def GetPageTextSecondaryFont(self, nPage): """ Returns The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" return self.nb.GetPageTextSecondaryFont(nPage) def SetPageTextColour(self, nPage, colour=None): """ Sets The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" if colour is None: colour = wx.BLACK self.nb.SetPageTextColour(nPage, colour) def GetPageTextColour(self, nPage): """ Returns The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" return self.nb.GetPageTextColour(nPage) def SetPageColour(self, nPage, colour=None): """ Sets The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self.nb.SetPageColour(nPage, colour) def GetPageColour(self, nPage): """ Returns The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" return self.nb.GetPageColour(nPage) def SetTabHeight(self, height=28): """ Sets The Tabs Height. """ if height <= 0: raise "\nERROR: Impossible To Set An Height <= 0. " self.nb.SetTabHeight(height) def SetControlBackgroundColour(self, colour=None): """ Sets The TabCtrl Background Colour (Behind The Tabs). """ if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) self.nb.SetBackgroundColour(colour) def ApplyTabTheme(self, theme=None): """ Apply A Particular Theme To Be Drawn On Tabs. """ if theme is None: theme = ThemeStyle() self.nb.ApplyTabTheme(theme) def SetSelectionColour(self, colour=None): """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ if colour is None: colour = wx.Colour(255, 180, 0) self.nb.SetSelectionColour(colour) def SetContourLineColour(self, colour=None): """ Sets The Contour Line Colour (Controur Line Around Tabs). """ self.nb.SetContourLineColour(colour) def Tile(self, show=True, orient=None): """ Shows Pages In Column/Row Mode (One Panel After The Other In Columns/Rows). """ if self._GetTabCtrlWindow().IsShown() == show and orient is None: return self.Freeze() if orient is not None and show: if orient == wx.VERTICAL: norient = wx.HORIZONTAL else: norient = wx.VERTICAL if orient is not None and show: origorient = self.bsizer.GetOrientation() if origorient != norient: for ii in xrange(self.GetPageCount()-1, -1, -1): self.bsizer.Detach(ii) self.sizer.Detach(self.bsizer) self.bsizer.Destroy() self.bsizer = wx.BoxSizer(norient) for ii in xrange(self.GetPageCount()): self.bsizer.Add(self._notebookpages[ii], 1, wx.EXPAND | wx.ALL, 2) if self._style & NC_TOP: self.sizer.Add(self.bsizer, 1, wx.EXPAND) else: self.sizer.Insert(0, self.bsizer, 1, wx.EXPAND) self.bsizer.Layout() self.sizer.Layout() selection = self.GetSelection() if show: self._ShowTabCtrl(False) if self._style & NC_TOP or self._style & NC_LEFT: if len(self.nb._selectedtabs) > 0: for ii in xrange(self.GetPageCount()): if ii in self.nb._selectedtabs: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: for ii in xrange(self.GetPageCount()): if self.IsPageEnabled(ii): if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: self.bsizer.Show(ii, False) else: if len(self.nb._selectedtabs) > 0: for ii in xrange(self.GetPageCount()): if ii in self.nb._selectedtabs: self.bsizer.Show(ii, True) else: for ii in xrange(self.GetPageCount()): if self.IsPageEnabled(ii): if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: self.bsizer.Show(ii, False) else: self._ShowTabCtrl(True) if self._style & NC_TOP or self._style & NC_LEFT: for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) else: for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) if selection < 0: self.bsizer.Layout() self.sizer.Layout() return else: self.bsizer.Show(selection, True) self.bsizer.Layout() self._showcolumns = show self.bsizer.Layout() self.sizer.Layout() self.Thaw() def ShowTabs(self, show=True): """ Shows/Hides Tabs On Request. """ if self._GetTabCtrlWindow().IsShown() == show: return if self.GetPageCount() == 0: return self.Freeze() self._ShowTabCtrl(show) self._showtabs = show self.sizer.Layout() self.Thaw() def GetIndex(self, page): """ Returns The Page Index (Position) Based On The NotebookCtrl Page Passed. """ if page in self._notebookpages: return self._notebookpages.index(page) return -1 def ReparentPage(self, nPage, newParent): """ Reparents The NotebookCtrl Page nPage To A New Parent. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentPage: (" + str(nPage) + ")" page = self.GetPage(nPage) page.Reparent(newParent) def ReparentToFrame(self, nPage, createNotebook=False): """ Reparents The NotebookCtrl Page nPage To A New Frame. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentToFrame: (" + str(nPage) + ")" self.Freeze() infos = self.GetPageInfo(nPage) panel = self.GetPage(nPage) text = infos["text"] oldparent = panel.GetParent() frame = NCFrame(None, -1, text, nb=self, infos=infos, panel=panel, oldparent=oldparent) if createNotebook: nb = NotebookCtrl(frame, -1, style=self._style, sizer=self._sizerstyle) nb.SetImageList(infos["imagelist"]) self.ReparentToNotebook(nPage, nb) else: self.ReparentPage(nPage, frame) self.nb.DeletePage(nPage, False) self.bsizer.Detach(nPage) self.bsizer.Layout() self.sizer.Layout() self._notebookpages.pop(nPage) self.AdvanceSelection() if self.GetPageCount() == 0: self._ShowTabCtrl(False) self.sizer.Layout() custom = self.GetCustomPage() if custom is not None: self.SetCustomPage(custom) self.Thaw() frame.Show() def ReparentToNotebook(self, nPage, notebook, newPage=None): """ Reparents The NotebookCtrl Page nPage To A New NotebookCtrl. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentToNotebook: (" + str(nPage) + ")" if newPage is not None and newPage >= notebook.GetPageCount(): raise "\nERROR: Invalid Notebook New Page In ReparentToNotebook: (" + str(nPage) + ")" self.Freeze() infos = self.GetPageInfo(nPage) panel = self.GetPage(nPage) self.ReparentPage(nPage, notebook) if newPage is None: notebook.AddPage(panel, infos["text"], False, infos["image"]) notebook.SetPageInfo(0, infos) for attr in attrs: setattr(notebook, attr, getattr(self.nb, attr)) self.nb.DeletePage(nPage, False) self.bsizer.Detach(nPage) self.bsizer.Layout() self.sizer.Layout() self._notebookpages.pop(nPage) self.AdvanceSelection() if self.GetPageCount() == 0: self._ShowTabCtrl(False) self.sizer.Layout() self.Thaw() def GetPageInfo(self, nPage): """ Returns All The Style Information For A Given Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In GetPageInfo: (" + str(nPage) + ")" text = self.GetPageText(nPage) image = self.GetPageImage(nPage) font1 = self.GetPageTextFont(nPage) font2 = self.GetPageTextSecondaryFont(nPage) fontcolour = self.GetPageTextColour(nPage) pagecolour = self.GetPageColour(nPage) enabled = self.IsPageEnabled(nPage) tooltip, ontime, winsize = self.GetPageToolTip(nPage) menu = self.GetPagePopupMenu(nPage) firstcol = self.GetPageFirstGradientColour(nPage) secondcol = self.GetPageSecondGradientColour(nPage) ishidden = self.nb._pages[nPage]._ishidden isanimated = 0 timer = None if self.nb._timers[nPage].IsRunning(): isanimated = 1 timer = self.nb._timers[nPage].GetInterval() self.StopAnimation(nPage) animatedimages = self.GetAnimationImages(nPage) infos = {"text": text, "image": image, "font1": font1, "font2": font2, "fontcolour": fontcolour, "pagecolour": pagecolour, "enabled": enabled, "tooltip": tooltip, "ontime": ontime, "winsize": winsize, "menu": menu, "isanimated": isanimated, "timer": timer, "animatedimages": animatedimages, "imagelist": self.nb._imglist, "firstcol": firstcol, "secondcol": secondcol, "ishidden": ishidden} return infos def SetPageInfo(self, nPage, infos): """ Sets All The Style Information For A Given Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In SetPageInfo: (" + str(nPage) + ")" self.SetPageTextFont(nPage, infos["font1"]) self.SetPageTextSecondaryFont(nPage, infos["font2"]) self.SetPageTextColour(nPage, infos["fontcolour"]) self.SetPageColour(nPage, infos["pagecolour"]) self.EnablePage(nPage, infos["enabled"]) self.SetPageToolTip(nPage, infos["tooltip"], infos["ontime"], infos["winsize"]) self.SetPagePopupMenu(nPage, infos["menu"]) self.SetPageFirstGradientColour(nPage, infos["firstcol"]) self.SetPageSecondGradientColour(nPage, infos["secondcol"]) self.nb._pages[nPage]._ishidden = infos["ishidden"] if infos["isanimated"] and len(infos["animatedimages"]) > 1: self.SetAnimationImages(nPage, infos["animatedimages"]) self.StartAnimation(nPage, infos["timer"]) def SetCustomPage(self, panel): """ Sets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ self.Freeze() if panel is None: if self._custompanel is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) if self.GetPageCount() == 0: self._ShowTabCtrl(False) else: if self.GetPageCount() == 0: if self._custompanel is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) self.bsizer.Add(panel, 1, wx.EXPAND | wx.ALL, 2) panel.Show(True) self._ShowTabCtrl(False) else: panel.Show(False) self._custompanel = panel self.bsizer.Layout() self.sizer.Layout() self.Thaw() def GetCustomPage(self): """ Gets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ return self._custompanel def HideTab(self, nPage, hide=True): """ Hides A Tab In The NotebookCtrl. """ self.nb.HideTab(nPage, hide) def HitTest(self, point, flags=0): """ Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It Returns The Page Clicked (If Any) And One Of These Flags: NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab NC_HITTEST_ONICON = 1 ==> Hit On Icon NC_HITTEST_ONLABEL = 2 ==> Hit On Label NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page """ return self.nb.HitTest(point, flags) def _AddMargin(self, style, margin): if style & NC_TOP or style & NC_BOTTOM: self.tabsizer.Add((0, margin), 0) elif style & NC_LEFT or style & NC_RIGHT: self.tabsizer.Add((margin, 0), 0) def _GetTabCtrlWindow(self): if self._style & NC_TOP or self._style & NC_LEFT: return self.tabsizer.GetItem(1) else: return self.tabsizer.GetItem(0) def _ShowTabCtrl(self, show): if self._style & NC_TOP: self.sizer.Show(0, show) else: self.sizer.Show(1, show) # ---------------------------------------------------------------------------- # # Class TransientTipWindow # Auxiliary Help Class. Used To Build The Tip Window. # ---------------------------------------------------------------------------- # class _PopupWindow: def _Fill(self, tip, winsize): panel = wx.Panel(self, -1) colour = self.GetParent().GetToolTipBackgroundColour() panel.SetBackgroundColour(colour) # border from sides and top to text (in pixels) border = 5 # how much space between text lines textPadding = 2 max_len = len(tip) tw = winsize mylines = tip.split("\n") sts = wx.StaticText(panel, -1, "\n".join(mylines)) sx, sy = sts.GetBestSize() sts.SetPosition((2, 2)) panel.SetSize((sx+6, sy+6)) self.SetSize(panel.GetSize()) class TransientTipWindow(_PopupWindow, wx.PopupWindow): def __init__(self, parent, tip, winsize): wx.PopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) self._Fill(tip,winsize) def ProcessLeftDown(self, evt): return False def OnDismiss(self): return False class macPopupWindow(wx.Frame): def __init__(self, parent, flags): wx.Frame.__init__(self, parent, id=-1, style=flags|wx.FRAME_NO_TASKBAR|wx.STAY_ON_TOP) self._hideOnActivate = False #Get the parent frame: could be improved maybe? self._parentFrame = parent while True: parent = self._parentFrame.GetParent() if parent: self._parentFrame = parent else: break self.Bind(wx.EVT_ACTIVATE, self.OnActivate) def Show(self, show=True): wx.Frame.Show(self,show) if show: self._parentFrame.Raise() self._hideOnActivate = True def OnActivate(self, evt): """ Let The User Hide The Tooltip By Clicking On It. NotebookCtrl Will Destroy It Later. """ if self._hideOnActivate: wx.Frame.Show(self,False) class macTransientTipWindow(_PopupWindow, macPopupWindow): def __init__(self, parent, tip, winsize): macPopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) self._Fill(tip, winsize) class NCFrame(wx.Frame): def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, nb=None, panel=None, infos=None, oldparent=None): wx.Frame.__init__(self, parent, id, title, pos, size, style) self._infos = infos self._nb = nb self._panel = panel self._oldparent = oldparent self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, event): try: infos = self._infos self._panel.Reparent(self._oldparent) self._nb.AddPage(self._panel, infos["text"], False, infos["image"]) id = self._nb.GetPageCount() - 1 self._nb.SetPageTextFont(id, infos["font1"]) self._nb.SetPageTextSecondaryFont(id, infos["font2"]) self._nb.SetPageTextColour(id, infos["fontcolour"]) self._nb.SetPageColour(id, infos["pagecolour"]) self._nb.EnablePage(id, infos["enabled"]) self._nb.SetPageToolTip(id, infos["tooltip"], infos["ontime"], infos["winsize"]) self._nb.SetPagePopupMenu(id, infos["menu"]) self._nb.SetPageFirstGradientColour(id, infos["firstcol"]) self._nb.SetPageSecondGradientColour(id, infos["secondcol"]) self._nb._pages[id]._ishidden = infos["ishidden"] if infos["isanimated"] and len(infos["animatedimages"]) > 1: self._nb.SetAnimationImages(id, infos["animatedimages"]) self._nb.StartAnimation(id, infos["timer"]) except: self.Destroy() event.Skip() return self.Destroy() event.Skip() class NotebookCtrlWindowHandler(xrc.XmlResourceHandler): """ Create L{NotebookCtrl} windows defined in Xrc resources. Below is an example of a resource definition:: wxVERTICAL wxEXPAND 0 1 NC_GRADIENT_HORIZONTAL | NC_GRADIENT_SELECTION #DCDCDC #F5F5F5 #C4DADB #FFFFFF #C0C0C0 @undocumented: CanHandle, DoCreateResource, SetupWindow """ def __init__(self): """ Create a NotebookCtrlWindowHandler instance. """ xrc.XmlResourceHandler.__init__(self) # Specify the window styles recognized by objects of this type self.AddStyle("wxNO_BORDER", wx.NO_BORDER) self.AddStyle("wxTAB_TRAVERSAL", wx.TAB_TRAVERSAL) self.AddStyle("NC_TOP", NC_TOP) self.AddStyle("NC_BOTTOM", NC_BOTTOM) self.AddStyle("NC_LEFT", NC_LEFT) self.AddStyle("NC_RIGHT", NC_RIGHT) self.AddStyle("NC_FIXED_WIDTH", NC_FIXED_WIDTH) self.AddStyle("NC_ROTATE", NC_ROTATE) self.AddStyle("NC_EXPANDABLE", NC_EXPANDABLE) # More styles, used in the tabstyle parameter self.AddStyle("NC_AQUA_LIGHT", NC_AQUA_LIGHT) self.AddStyle("NC_AQUA_DARK", NC_AQUA_DARK) self.AddStyle("NC_AQUA", NC_AQUA) self.AddStyle("NC_METAL", NC_METAL) self.AddStyle("NC_SILVER", NC_SILVER) self.AddStyle("NC_KDE", NC_KDE) self.AddStyle("NC_GRADIENT_VERTICAL", NC_GRADIENT_VERTICAL) self.AddStyle("NC_GRADIENT_HORIZONTAL", NC_GRADIENT_HORIZONTAL) self.AddStyle("NC_GRADIENT_SELECTION", NC_GRADIENT_SELECTION) self.AddWindowStyles() def _CreateResourceInstance(self, parent, id, position, size, style, name): window = NotebookCtrl(parent, id, position, size=size, style=style, name=name) return window def _GetColorParamValue(self, paramName, defaultValue=wx.WHITE): paramValue = self.GetParamValue(paramName) if paramValue: return self.GetColour(paramName) else: return defaultValue def _GetCustomPage(self, window): customPage = wx.Window(window, -1, style = wx.STATIC_BORDER) customPage.SetBackgroundColour(self._GetColorParamValue('custompagecolor')) return customPage def _GetIntParamValue(self, paramName, defaultValue=0): paramValue = self.GetParamValue(paramName) if paramValue: return int(paramValue) else: return defaultValue def _GetTabTheme(self): tabstyle = self.GetStyle("tabstyle") if tabstyle: result = ThemeStyle() if tabstyle & NC_GRADIENT_VERTICAL or tabstyle & NC_GRADIENT_HORIZONTAL: result.EnableGradientStyle(True, tabstyle) result.SetFirstGradientColour(self._GetColorParamValue('color1')) result.SetSecondGradientColour(self._GetColorParamValue('color2')) result.SetFirstGradientColourSelected(self._GetColorParamValue('selectedcolor1')) result.SetSecondGradientColourSelected(self._GetColorParamValue('selectedcolor2')) elif tabstyle & NC_AQUA_LIGHT or tabstyle & NC_AQUA_DARK: result.EnableAquaTheme(True, tabstyle & NC_AQUA_LIGHT and 2 or 1) elif tabstyle & NC_METAL: result.EnableMetalTheme(True) elif tabstyle & NC_KDE: result.EnableKDETheme(True) elif tabstyle & NC_SILVER: result.EnableSilverTheme(True) else: result = GetDefaultTabStyle() return result # This method and the next one are required for XmlResourceHandlers def CanHandle(self, node): return self.IsOfClass(node, "NotebookCtrl") def DoCreateResource(self): # NOTE: wxWindows can be created in either a single-phase or # in a two-phase way. Single phase is what you normally do, # and two-phase creates the instnace first, and then later # creates the actual window when the Create method is called. # (In wxPython the first phase is done using the wxPre* # function, for example, wxPreFrame, wxPrePanel, etc.) # # wxXmlResource supports either method, a premade instance can # be created and populated by xrc using the appropriate # LoadOn* method (such as LoadOnPanel) or xrc can create the # instance too, using the Load* method. However this makes # the handlers a bit more complex. If you can be sure that a # particular class will never be loaded using a pre-existing # instance, then you can make the handle much simpler. I'll # show both methods below. # The simple method assumes that there is no existing # instance. Be sure of that with an assert. assert self.GetInstance() is None # Now create the object window = self._CreateResourceInstance(self.GetParentAsWindow(), self.GetID(), self.GetPosition(), self.GetSize(), self.GetStyle("style", NC_DEFAULT_STYLE), self.GetName()) # Set standard window attributes self.SetupWindow(window) # Create any child windows of this node self.CreateChildren(window) return window def SetupWindow(self, window): super(NotebookCtrlWindowHandler, self).SetupWindow(window) window.ApplyTabTheme(self._GetTabTheme()) window.SetHighlightSelection(self._GetIntParamValue("highlight", 0) != 0) window.SetUseFocusIndicator(self._GetIntParamValue("focus", 1) != 0) window.SetCustomPage(self._GetCustomPage(window)) spe-0.8.4.h/_spe/sm/wxp/smdi.py0000644000175000017500000014661310775447265015303 0ustar stanistani####(c)www.stani.be------------------------------------------------------------- try: import sm, sm.osx INFO=sm.INFO.copy() INFO['title'] = INFO['titleFull'] = 'Sdi/Mdi Framework' INFO['description']=\ """Framework which makes it easy to switch between Sdi (Linux/Mac) and Mdi (Windows). """ __doc__=INFO['doc']%INFO except: __doc__="Stani's Multiple Document Interface (c)www.stani.be" """ Attributes of Application: - properties: - children - config - DEBUG - imagePath - mdi - title - parentFrame - parentPanel - pos - size - style - methods: - SetMdi - classes: - ChildFrame - ChildPanel - MenuBar - ParentFrame - ParentPanel - StatusBar - ToolBar Attributes of Frame: - properties: - app - dead - menuBar - parentFrame - toolBar - methods: - getIndex - (maximize) - setTitle - SetStatusText - events: - bindTabs - unbindTabs - onFrameActivate - onFrameClose - onFrameMove - onFrameSize - (onFrameTab) - classes: - Panel Attributes of Panel: - properties: - changed - frame - title - parentFrame - parentPanel - methods: Attributes of MenuBar: - properties: - app - frame - parentFrame - parentPanel - toolBar Attributes of ToolBar: - properties: - app - frame - menuBar Todo: - MDI_TABS IS NOT WORKING!! THIS SHOULD BE FIXED - icon support """ ####Modules import os, sys, pprint import wx from wx.lib.evtmgr import eventManager import singleApp import NotebookCtrl wx_Notebook = NotebookCtrl.NotebookCtrl #import sm.spy ####Constants #values SDI = 0 MDI_SASH = 1 MDI_SASH_TABS = 2 MDI = 3 MDI_TABS = 4 MDI_SPLIT = 5 #descriptions SDI_MAC = "single with tabs (mac, linux, windows)" MDI_SASH_WIN = "multiple with sash (windows)" MDI_SASH_TABS_LINUX = "multiple with sash & tabs (linux)" MDI_SASH_TABS_WIN = "multiple with sash & tabs (windows default)" MDI_WIN = "multiple with palette (windows)" MDI_MAC = "single with palette (mac)" MDI_TABS_LINUX = "multiple with tabs (linux)" MDI_TABS_WIN = "multiple with tabs (windows)" MDI_TABS_MAC = "single with tabs (mac)" MDI_SPLIT_ALL = "multiple with sash & tabs (mac default,linux default,windows)" DEFAULT = "" DI = {SDI_MAC : SDI, MDI_SASH_WIN : MDI_SASH, MDI_SASH_TABS_LINUX : MDI_SASH, MDI_SASH_TABS_WIN : MDI_SASH_TABS, MDI_WIN : MDI, MDI_MAC : MDI, MDI_TABS_LINUX : MDI, #MDI_TABS_WIN : MDI_TABS, MDI_TABS_MAC : MDI_TABS, MDI_SPLIT_ALL : MDI_SPLIT, DEFAULT : -1} PLATFORM = sys.platform WIN = PLATFORM.startswith('win') DARWIN = PLATFORM.startswith('darwin') GTK = not (WIN or DARWIN) if DARWIN: print 'If spe is unstable, try this interface from the preferences:\n "%s"\n'%MDI_SPLIT_ALL #wx related FULL_REPAINT_ON_RESIZE = wx.FULL_REPAINT_ON_RESIZE POS = (10,10) SIZE = (600,400) SINGLE_INSTANCE_APP = False STYLE_CHILDFRAME = wx.DEFAULT_FRAME_STYLE STYLE_NOTEBOOK = FULL_REPAINT_ON_RESIZE|wx.CLIP_CHILDREN|wx.NO_BORDER STYLE_PARENTFRAME = wx.DEFAULT_FRAME_STYLE #| wx.MAXIMIZE STYLE_SPLIT = wx.SP_NOBORDER STYLE_TOOLBAR = wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT TABSASH_HEIGHT = 30 TITLE = 'www.stani.be' UNNAMED = 'unnamed' ####Menu helper function def _(x): if DARWIN: return x#.replace('Ctrl','Cmd') else: return x def _strip(x): return x.replace(' ','_').replace('-','_').replace('&& ','').replace('&','').replace('.','').replace('(','').replace(')','') def menuWrite(menuBar,f='menu.txt'): labels = [] for m in range(menuBar.GetMenuCount()): menu = menuBar.GetMenu(m) menuLabel = menuBar.GetLabelTop(m) for item in menu.GetMenuItems(): label = _strip(item.GetLabel()) if label: labels.append((menuLabel,item.GetLabel())) #events result = '\tdef __smdi__(self):\n' for label in labels: label = _strip(label[1]) result+= '\t\twx.EVT_MENU(self,%s,self.menu_%s)\n'%(label.upper(),label.lower()) result+= '\n' for label in labels: result+='\tdef menu_%s(self):\n\t\t"""%s"""\n\t\tpass\n\n'%(_strip(label[1].lower()),'%s > %s'%label) print result print os.getcwd() print f f = open(f,'w') f.write(result) f.close() def test_menuWrite(): import menu menuWrite(wxgMenu.Bar()) ####Base WX_BITMAP = wx.Bitmap class Bitmap: def __init__(self,path,app): self.path = path self.app = app def __call__(self,x,t=wx.BITMAP_TYPE_ANY): path = os.path.join(self.path,os.path.basename(x)) #if self.app.DEBUG: # print 'Bitmap: %s<%s'%(x,path) return WX_BITMAP(path,t) class DummyPage(wx.StaticText): """Page to fill the tabs (not meant to be visible).""" def __init__(self,tabs): wx.StaticText.__init__(self, tabs, wx.ID_ANY, "SPE bug: This shouldn't be visible") class NativeNotebookPlus(wx.Notebook): """Fall back for linux""" def __init__(self,app,*args,**keyw): wx.Notebook.__init__(self,*args,**keyw) self.app = app self.Bind(wx.EVT_MIDDLE_UP,self.onFrameMiddleClick) self.Bind(wx.EVT_LEFT_DCLICK,self.onFrameMiddleClick) def onFrameMiddleClick(self,event): """When a tab is middle clicked (EVT_MOUSE_LEFT&HitTest).""" mousePos = event.GetPosition() index, other = self.HitTest(mousePos) if self.app.mdi in [SDI,MDI_TABS]: #no parent tab zero = 0 else: zero = -1 if index>zero: self.app.children[index-zero-1].frame.onFrameClose() def EnableToolTip(self,*args,**keyw): pass def SetPageToolTip(self,*args,**keyw): pass def Tile(self,*args,**keyw): pass def BindPageChange(self,method): self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,method,self) def UnbindPageChange(self): self.Unbind(wx.EVT_NOTEBOOK_PAGE_CHANGED) class AndreaNotebookPlus(NotebookCtrl.NotebookCtrl): def __init__(self,app,*args,**keyw): self.app = app keyw['size'] = wx.Size(25,25) keyw['margin'] = 0 if keyw.has_key('style'): del keyw['style'] NotebookCtrl.NotebookCtrl.__init__(self,*args,**keyw) #theme self.tabstyle = NotebookCtrl.ThemeStyle() if DARWIN: self.SetControlBackgroundColour(wx.NullColour)#wx.Colour(236,236,236)) self.tabstyle.EnableAquaTheme(True,2) else: self.SetHighlightSelection(True) self.tabstyle.EnableSilverTheme(True) self.ApplyTabTheme(self.tabstyle) #general settings if GTK: self.SetTabHeight(30) else: self.SetTabHeight(25) self.SetDrawX(True, 2) self.SetPadding(wx.Point(4,4)) self.SetUseFocusIndicator(False) self.EnableChildFocus(True) self.EnableDragAndDrop(True) #self.EnableHiding(True) self.SetToolTipBackgroundColour(wx.Colour(240,255,240)) #events self.Bind(NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_CLOSING,self.onClosing) self.Bind(NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_DND, self.onDragAndDrop) #self.Bind(NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_DCLICK, self.OnLeftDClick) def onClosing(self,event): """When a tab is middle clicked (EVT_MOUSE_LEFT&HitTest).""" index = event.GetSelection() zero = self.getZero() if index>zero: self.app.children[index-zero-1].frame.onFrameClose() def onDragAndDrop(self, event): old = event.GetOldPosition() new = event.GetNewPosition() zero = self.getZero() if new != zero: #child can not be before parent if this is a tab children = self.app.children child = children[old-zero-1] children.remove(child) children.insert(new-zero-1,child) event.Skip() def getZero(self): if self.app.mdi in [SDI,MDI_TABS]: #no parent tab return 0 else: return -1 def setIcons(self,bitmaps): #todo: here this should go somewhere else!! pageIcons = [] for bitmap in bitmaps: self.pageIcons.append(self.notebookIcons.Add(bitmap)) self.notebookIcons = wx.ImageList(16,16) self.AssignImageList(self.notebookIcons) def OnLeftDClick(self, event): nPage = event.GetSelection() self.ReparentToFrame(nPage, False) event.Skip() def BindPageChange(self,method): self.Bind(NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_CHANGED,method) def UnbindPageChange(self): self.Unbind(NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_CHANGED) ##try: ## import wx.aui ## NotebookPlus = wx.aui.AuiNotebook ##except: if sys.platform.startswith('linux'): NotebookPlus = NativeNotebookPlus else: NotebookPlus = AndreaNotebookPlus ####Foundation Classes class Framework: """Foundation class for every frame.""" def __init__(self,app,Panel,parentFrame,page='',extra='',**options): self.Freeze() #stage self.__before__(app = app, Panel = Panel, parentFrame = parentFrame, page = page, extra = extra) self.__stage__(page = page, extra = extra, **options) self.__after__() ##rest self.__menu__() self.__tool__(app) self.__statusBar__() self.__finish__() self.__events__() #show self.Thaw() self.Show(True) #---components def __before__(self,app,Panel,parentFrame,page,extra): """Reference frame attributes (not overwritten).""" self.app = app self.Panel = Panel self.parentFrame = parentFrame self.dead = False # todo: is this still necessary if not hasattr(self,'isSdiParent'): self.isSdiParent = False self.page = page self.extra = extra def __stage__(self,page,extra,**options): """Create notebook (to switch between documents) & panel This is mostly overwritten.""" self.panel = self.Panel(parent=self,**options) def __after__(self): """Reference panel attributes (not overwritten).""" panel = self.panel panel.app = self.app panel.frame = self panel.parentFrame = self.parentFrame panel.parentPanel = self.parentFrame.panel panel.changed = False def __menu__(self): """Create: Framework: menu.""" app = self.app if app.MenuBar and not self.noMenu: if app.DEBUG: print """Create: Framework: menu.""" if app.mdi: frame = self.app else: frame = self self.menuBar = menuBar = app.MenuBar(app=self.app,frame=frame) self.SetMenuBar(menuBar) #reference menuBar.app = app #create menuBar.frame = self menuBar.parentFrame = self.parentFrame menuBar.parentPanel = self.parentFrame.panel if hasattr(self,'palette'): self.palette.panel.app = app self.palette.panel.menuBar = menuBar else: self.menuBar = None def __tool__(self,app): """Create toolbar Very important: in the custom wx.ToolBar class after the wx.ToolBar.__init__ the following code must be written: parent.SetToolBar(self)""" if self.app.ToolBar and not (self.noMenu or self.isSdiParent): if self.app.DEBUG: print """Create: Framework: toolbar.""" #create self.toolBar = self.app.ToolBar(parent=self, app=app, id=wx.ID_ANY, style=STYLE_TOOLBAR) #self.SetToolBar(self.toolBar)-> do this in toolbar class #reference self.toolBar.app = self.app self.toolBar.frame = self if self.menuBar: self.toolBar.menuBar = self.menuBar self.menuBar.toolBar = self.toolBar else: self.toolBar = None if self.menuBar: self.menuBar.toolBar = None def __statusBar__(self): """Create statusbar (to be overwritten).""" if self.noMenu: self.panel.SetStatusText = self.parentFrame.SetStatusText self.panel.statusBar = self.parentFrame.statusBar else: self.panel.SetStatusText = self.SetStatusText if self.app.StatusBar: if self.app.DEBUG: print """Create: Framework: statusbar.""" self.statusBar = self.app.StatusBar(parent=self,id=wx.ID_ANY) self.SetStatusBar(self.statusBar) #---other def __finish__(self): self.setTitle(self.page,self.extra) if hasattr(self.panel,'__finish__'): self.panel.__finish__() def __layoutTabs__(self,parent=None): """Not for mdi children""" if not parent: parent = self #sizer layout sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.tabs, 1, wx.EXPAND, 0) parent.SetAutoLayout(True) parent.SetSizer(sizer) parent.Layout() #events self.bindTabs() #---events def _isActiveEvent(self,event): return (event is None) or (not hasattr(event,'GetActive')) or event.GetActive() def __events__(self): """Initialize events.""" eventManager.Register(self.onFrameActivate, wx.EVT_ACTIVATE, self) eventManager.Register(self.onFrameClose, wx.EVT_CLOSE, self) eventManager.Register(self.onFrameMove, wx.EVT_MOVE, self) eventManager.Register(self.onFrameSize, wx.EVT_SIZE, self) if self.menuBar: self.menuBar.__events__() if self.toolBar: self.toolBar.__events__() ## if hasattr(self.panel,'onIdle'): ## eventManager.Register(self.onFrameIdle, wx.EVT_IDLE, self) def onFrameActivate(self, event): """Activate event (to be overwritten).""" getActive = self._isActiveEvent(event) if getActive: if self.app.DEBUG: print 'Event<: Framework: %s.Activate(%s)'%(self.__class__,getActive) if hasattr(self.panel,'onActivate'): self.panel.onActivate(event) elif hasattr(self.panel,'onDeactivate'): self.panel.onDeactivate(event) if self.app.DEBUG: print 'Event>: Framework: %s.Activate(%s)'%(self.__class__,getActive) if event: event.Skip() def onFrameClose(self, event=None, destroy = 1): """Close event (to be overwritten/extended).""" debug = self.app.DEBUG if debug: print 'Event<: Framework: %s.Close'%self.__class__ if hasattr(self.panel,'onClose'): self.dead = self.panel.onClose() else: self.dead = True if self.dead: if destroy: eventManager.DeregisterWindow(self) self.Destroy() if event: event.Skip() if debug: print 'Event>: Framework: %s.Close returns True'%self.__class__ return True else: if debug: print 'Event>: Framework: %s.Close returns False'%self.__class__ return False def onFrameMove(self, event=None): """Move event (to be overwritten).""" if self.app.DEBUG: print 'Event<: Framework: %s.Move'%self.__class__ if event: event.Skip() #sm.spy.frame(1) if hasattr(self.panel,'onMove'): self.panel.onMove(event) if self.app.DEBUG: print 'Event>: Framework: %s.Move'%self.__class__ def onFrameSize(self, event=None): """Size event (to be overwritten).""" #sm.spy.frame(1) if self.app.DEBUG: print 'Event<: Framework: %s.Size'%self.__class__ if hasattr(self.panel,'onSize'): self.panel.onSize(event) if self.app.DEBUG: print 'Event>: Framework: %s.Size'%self.__class__ if event: event.Skip() def onFrameIdle(self, event): """To be overwritten.""" if not self.dead: if hasattr(self.panel,'onIdle'): self.panel.onIdle() def bindTabs(self): """Bind events to notebook tabs (to be overwriten).""" pass def unbindTabs(self): """Unbind events to notebook tabs (to be overwriten).""" pass def getIndex(self): """Get index of current child.""" try: return self.app.children.index(self.panel) except ValueError: return -1 class Tabs(Framework): #---events def bindTabs(self): self.tabs.Bind(self.app.EVENT_NOTEBOOK, self.onFrameTab) #eventManager.Register(self.onFrameTab, self.app.EVENT_NOTEBOOK, self.tabs) def unbindTabs(self): self.tabs.Unbind(self.app.EVENT_NOTEBOOK) #eventManager.DeregisterWindow(self.tabs) def raiseTab(self,index): if index > -1: app = self.app if app.DEBUG: print 'Event<: Tab: %s.onFrameTab(%s)'%(self.__class__,index) parent = app.mdi in [SDI,MDI_TABS] if index == 0 and parent: window = self.parentFrame if hasattr(window,'panelFrame'): window = window.panelFrame else: window = self.app.children[index-[0,1][parent]].frame if app.DEBUG: print '%s.Raise()'%window print window.Raise window.Raise() if app.DEBUG: print 'Event>: Tab: %s.onFrameTab(%s)'%(self.__class__,index) #---SDI Platform dependent class TabWin32(Tabs): """SDI Implementation for windows (see also App.SetMdi)""" ## def onFrameTab(self,event): ## """When a tab is changed (EVT_MOUSE_LEFT&HitTest).""" ## mousePos = event.GetPosition() ## index, other = self.tabs.HitTest(mousePos) ## self.raiseTab(index) def onFrameTab(self,event): self.raiseTab(event.GetSelection()) event.Skip() class TabUnix(Tabs): """SDI Implementation for windows (see also App.SetMdi)""" def onFrameTab(self,event): """When a tab is changed (EVT_NOTEBOOK_CHANGING).""" index = event.GetSelection() event.Veto()#instead of event.Skip() (don't do this here anyway) self.raiseTab(index) if PLATFORM == 'win32': TabPlatform = TabWin32 else: TabPlatform = TabUnix ####Parent classes class Parent(Framework): #---initialize def __init__(self, app, page = '', **options): self.options = options self.noMenu = False Framework.__init__(self, app = app, Panel = app.ParentPanel, page = page, parentFrame = self, **options) def __finish__(self): Framework.__finish__(self) #---events def onFrameClose(self,event=None): self.dead = Framework.onFrameClose(self,event,destroy=0) if not self.dead: return #Avoid event exceptions of child frames for child in self.app.children: if child: if hasattr(child,'frame'): eventManager.DeregisterWindow(child.frame) child.dead = 1 #Destroy itself self.Destroy() if event: event.Skip() #---menu def menu_new(self, event=None): self.child() def menu_close(self,event=None): if self.app.children: childActive = self.app.childActive if childActive: childActive.onFrameClose() #---parentPanel def child(self,*args,**keyw): self.ChildFrame(self,*args,**keyw) def maximize(self): if self.app.mdi == MDI_SPLIT: return True i = 0 m = 0 for child in self.app.children: if child.frame.IsMaximized(): return True return False #---other def setTitle(self,page='',extra='',draw=True,colour=None): if draw: t = self.app.title if page: t = '%s - %s'%(page,t) self.SetTitle(t) class MdiParentFrame(Parent,wx.MDIParentFrame): """Uniformed parent Mdi/Sdi class based on Mdi. self.Panel is defined by joined class""" def __init__(self,app, id = wx.ID_ANY, page = 'parentFrame', parent = None, size = SIZE, style = STYLE_PARENTFRAME, pos = POS, **options): wx.MDIParentFrame.__init__(self, id = id, name = page, parent = parent, size = size, style = style | FULL_REPAINT_ON_RESIZE, title = page, pos = pos) if style & wx.MAXIMIZE: try: #not working on mandrake9 self.Maximize(1) except: pass #This always has to be last! Parent.__init__(self,app=app,page=page,**options) def __stage__(self,page,extra,**options): self.panelFrame = wx.MDIChildFrame(parent=self,id=wx.ID_ANY) self.panelFrame.SetTitle(self.app.panelFrameTitle) #parentPanel self.panel = self.Panel(parent=self.panelFrame,**options) eventManager.Register(self.onSashClose, wx.EVT_CLOSE, self.panelFrame) #palette if self.app.Palette: self.palette = self.app.Palette(parent=self,id=wx.ID_ANY) self.palette.Show() def onSashClose(self,event): if hasattr(self.panel,'onClosePanelFrame'): self.panel.onClosePanelFrame(event) def setTitle(self,page='',extra='',draw=True,colour=None): if draw: self.SetTitle(self.app.title) class MdiTabsParentFrame(TabPlatform,MdiParentFrame): def __stage__(self,page,extra,**options): app = self.app self.panelFrame = wx.MDIChildFrame(parent=self,id=wx.ID_ANY) self.panelFrame.SetTitle(app.panelFrameTitle) self.panelFrame.Raise= self.panelFrame.Activate #parentPanel self.tabs = NotebookPlus(app=app,parent=self.parentFrame, id=wx.ID_ANY, style = STYLE_NOTEBOOK ) self.panel = self.Panel(parent=self.tabs,**options) self.tabs.AddPage(self.panel, page) self.__layoutTabs__() #events eventManager.Register(self.onSashClose, wx.EVT_CLOSE, self.panelFrame) #palette if app.Palette: self.palette = self.app.Palette(parent=self,id=wx.ID_ANY) self.palette.Show() class MdiSashParentFrame(MdiParentFrame): """Uniformed parent Mdi/Sdi class based on Mdi. self.Panel is defined by joined class""" def __stage__(self,page,extra,**options): """Create tabs to switch between documents as an wx.SashLayoutWindow""" if self.app.DEBUG: print 'Create: Mdi: %s.tabs'%(self.__class__,) #sash for parentPanel self.sashId = wx.NewId() self.sash = wx.SashLayoutWindow(id=self.sashId, name='sash', parent=self, style=wx.NO_BORDER) self.sash.SetDefaultSize(wx.Size(792, 200)) self.sash.SetOrientation(wx.LAYOUT_HORIZONTAL) self.sash.SetAlignment(wx.LAYOUT_BOTTOM) self.sash.SetSashVisible(wx.SASH_TOP, 1) self.sash.SetMinimumSizeY(1) #self.sash.Show(True) eventManager.Register(self.onFrameSashDragged, wx.EVT_SASH_DRAGGED, self.sash) #parentPanel self.panel = self.Panel(parent=self.sash,**options) #layout self.panelSizer = wx.BoxSizer(wx.VERTICAL) self.panelSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND, 0) self.sash.SetAutoLayout(1) self.sash.SetSizer(self.panelSizer) def __finish__(self): Parent.__finish__(self) wx.LayoutAlgorithm().LayoutMDIFrame(self) #---events def onFrameSashDragged(self,event): """Called when the shashwindow is dragged.""" if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: return eID = event.GetId() if eID == self.sashId: self.sash.SetDefaultSize(wx.Size(1000,event.GetDragRect().height)) wx.LayoutAlgorithm().LayoutMDIFrame(self) def onFrameSize(self, event): """Overwritten for sash dragging.""" Framework.onFrameSize(self) wx.LayoutAlgorithm().LayoutMDIFrame(self) class MdiSashTabsParentFrame(TabPlatform,MdiSashParentFrame): def __stage__(self,page,**options): """Create tabs to switch between documents as an wx.SashLayoutWindow""" if self.app.DEBUG: print 'Create: Mdi: %s.tabs'%(self.__class__,) self.tabsSash = wx.SashLayoutWindow(id=wx.ID_ANY, name='tabs', parent=self, style=wx.CLIP_CHILDREN) self.tabsSash.SetOrientation(wx.LAYOUT_HORIZONTAL) self.tabsSash.SetAlignment(wx.LAYOUT_TOP) self.tabsSash.SetDefaultSize(wx.Size(792, TABSASH_HEIGHT)) self.tabs = NotebookPlus(app=self.app,id=wx.ID_ANY, parent=self.tabsSash, style=STYLE_NOTEBOOK) self.__layoutTabs__(self.tabsSash) MdiSashParentFrame.__stage__(self,page,**options) def onFrameTab(self,event): """When a tab is changed (EVT_MOUSE_LEFT&HitTest).""" TabPlatform.onFrameTab(self,event) event.Skip() class MdiSplitParentFrame(Parent,wx.Frame): """Default on Linux.""" def __init__(self,app, id = wx.ID_ANY, page = 'parentFrame', parent = None, size = SIZE, style = STYLE_PARENTFRAME, pos = POS, **options): wx.Frame.__init__(self, id = id, name = page, parent = parent, size = size, style = style | FULL_REPAINT_ON_RESIZE, title = page, pos = pos) if style & wx.MAXIMIZE: try: #not working on mandrake9 self.Maximize(1) except: pass #This always has to be last! Parent.__init__(self,app=app,page=page,**options) def __stage__(self,page,extra,**options): self.split = split = wx.SplitterWindow(self,wx.ID_ANY,style=STYLE_SPLIT) self.tabs = NotebookPlus(app=self.app,parent=split, id=wx.ID_ANY, style = STYLE_NOTEBOOK ) #self.tabs = wx.Notebook(parent=split, id=wx.ID_ANY, # style = STYLE_NOTEBOOK ) self.panel = self.Panel(parent=split,**options) split.SetMinimumPaneSize(20) size = self.GetSize() self.SetSize((size[0],size[1]-1)) self.SetSize((size[0],size[1])) split.UpdateSize() if sys.platform.startswith('linux'): split.SplitHorizontally(self.tabs, self.panel, size[1]-20) else: split.SplitHorizontally(self.tabs, self.panel, -200) self.bindTabs() def bindTabs(self,event=None): self.tabs.BindPageChange(self.onFrameTab) def unbindTabs(self): self.tabs.UnbindPageChange() def onFrameTab(self,event): if not self.dead: index = event.GetSelection() #print index if index>-1 and index: Child: %s.Close returns False'%self.__class__ return False #no references to self after this point if event: event.Skip() #index if mdi in [SDI,MDI_TABS]: delta = 1 else: delta = 0 #Update children children = app.children children.remove(panel) sdi = (mdi in [SDI,MDI_TABS] and children) #deregister events eventManager.DeregisterWindow(self) if sdi: #not for mdichild eventManager.DeregisterWindow(self.tabs) #update rest if hasattr(parentFrame,'tabs'): #Update childBook tabs current = index+delta # * parent frame (mdi & sdi) parentFrame.unbindTabs() parentFrame.tabs.DeletePage(current) destroyed = True selected = parentFrame.tabs.GetSelection() parentFrame.bindTabs() # * children frames (sdi) if sdi: #not for mdichild c = 1 for child in children: child.frame.unbindTabs() tabs = child.frame.tabs tabs.DeletePage(current)#remove closed item from other children if c>=current: tabs.SetSelection(c)#adapt selection child.frame.bindTabs() c += 1 selected = parentFrame.tabs.GetSelection() else: selected = 0 if children: app.childActive = children[selected] app.childActive.frame.Activate() else: app.childActive = None if not destroyed and mdi!=MDI_SPLIT: self.Destroy() if not children: parentFrame.setTitle() if debug: print 'Event>: Child: %s.Close returns True'%self.__class__ return True def setTitle(self,page='',extra='',new=True,draw=True,colour=None): if new: #parameters if page: self.pageTitle = page if extra: self.extraTitle = extra #go if self.pageTitle: m = ['',' *'][self.panel.changed and not self.pageIcons] self._pageTitle = '%s%s'%(self.pageTitle,m) else: self._pageTitle = '' if draw: if self.app.mdiName == SDI or WIN: self.SetTitle(self.extraTitle) elif hasattr(self,'SetTitle'): self.SetTitle(self.pageTitle) self.setIcon() def setIcon(self): pass class MdiSashTabsChildFrame(Child,wx.MDIChildFrame): def __init__(self,parentFrame, id = wx.ID_ANY, page = UNNAMED, extra = '', style = STYLE_CHILDFRAME, maximize = None, **options): self.noMenu = True app = parentFrame.app #debug message if app.DEBUG: print 'Create: Mdi: %s'%self.__class__ if maximize == None: maximize = parentFrame.maximize() if maximize: style |= wx.MAXIMIZE wx.MDIChildFrame.__init__(self, id = id, name = page, parent = parentFrame, style = style | FULL_REPAINT_ON_RESIZE, title = page) self.Maximize()#if maximize and PLATFORM != 'win32':#sm:seems better to leave this away. self.Raise = self.Activate #raise doesn't work here #This always has to be last! Child.__init__(self, parentFrame = parentFrame, page = page, extra = extra, **options) def __finish__(self): self.tabs = self.parentFrame.tabs Child.__finish__(self) def setTitle(self,page='',extra='',new=True,draw=True,colour=None): Child.setTitle(self,page,extra,new,draw) self.parentFrame.setTitle(self._pageTitle,draw=draw) if new and draw: index = self.getIndex() self.tabs.SetPageText(index,self._pageTitle) if not(colour is None) and hasattr(self.tabs,'SetPageColour'): self.tabs.SetPageColour(index,colour) def onFrameActivate(self, event): if self._isActiveEvent(event): self.setTitle(new=False) self.parentFrame.tabs.SetSelection(self.getIndex()) Child.onFrameActivate(self,event) class MdiChildFrame(MdiSashTabsChildFrame, Child): """Mdi Child frame without tabs.""" def addPageToParent(self,panel,mdi): pass def setTitle(self,page='',extra='',new=True,draw=True,colour=None): Child.setTitle(self,page,extra,new,draw) self.parentFrame.setTitle(self._pageTitle,draw=draw) def __finish__(self): Child.__finish__(self) def onFrameActivate(self, event): if self._isActiveEvent(event): self.setTitle(new=False) Child.onFrameActivate(self,event) class MdiTabsChildFrame(TabPlatform,MdiSashTabsChildFrame, Child): def __stage__(self,page,extra,**options): """Create tabs to switch between documents as an wx.SashLayoutWindow""" if self.app.DEBUG: print 'Create: Sdi: %s.tabs'%(self.__class__,) tabs = self.tabs = NotebookPlus(app=self.app,parent=self, id=wx.ID_ANY, style = STYLE_NOTEBOOK ) panel = self.panel = self.Panel(parent=tabs,**options) #Add parent tab to itself tabs.AddPage(page=DummyPage(tabs),text=self.app.title) #Add child tabs to itself and vice versa for child in self.app.children: childTabs = child.frame.tabs tabs.AddPage(page=DummyPage(tabs),text=child.frame._pageTitle) childTabs.AddPage(page=DummyPage(childTabs),text=page) #Add itself to itself tabs.AddPage(page=panel,text=page,select=True) self.__layoutTabs__() def __finish__(self): Child.__finish__(self) def setTitle(self,page='',extra='',new=True,draw=True,colour=None): Child.setTitle(self,page,extra,new) if new and draw: index = self.getIndex()+1 self.tabs.SetPageText(index,self._pageTitle) if not(colour is None) and hasattr(self.tabs,'SetPageColour'): self.tabs.SetPageColour(index,colour) def onFrameActivate(self, event): if self._isActiveEvent(event): self.setTitle(new=False) self.parentFrame.tabs.SetSelection(self.getIndex()+1) Child.onFrameActivate(self,event) class MdiSplitChildFrame(Child,wx.Panel): def __init__(self,parentFrame, id = wx.ID_ANY, style = STYLE_CHILDFRAME, page = '', extra = '', maximize = None, **options): self.noMenu = True app = parentFrame.app #debug message if app.DEBUG: print 'Create: MdiSplit: %s'%self.__class__,page,extra wx.Panel.__init__(self, id = id, name = page, parent = parentFrame.tabs, size = wx.Size(600,400), style = style | FULL_REPAINT_ON_RESIZE,) #title = page) #This always has to be last! Child.__init__(self, parentFrame = parentFrame, page = page, extra = extra, **options) eventManager.Register(self.onFrameActivate, wx.EVT_SET_FOCUS, self) def __stage__(self,page,extra,**options): """Create tabs to switch between documents as an wx.SashLayoutWindow""" if self.app.DEBUG: print 'Create: Sdi: %s.tabs'%(self.__class__,) self.panel = self.Panel(parent=self,name=page,**options) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.EXPAND, 0) self.SetAutoLayout(True) self.SetSizer(sizer) self.Layout() def addPageToParent(self,panel,mdi): """"Add page with childs title to parent Can be overwritten.""" parentFrame = self.parentFrame tabs = self.tabs = parentFrame.tabs parentFrame.unbindTabs() tabs.AddPage(page=self, text=self.page,select=(mdi not in [SDI,MDI_TABS])) parentFrame.bindTabs() def setTitle(self,page='',extra='',new=True,draw=True,colour=None): Child.setTitle(self,page,extra,new) self.parentFrame.setTitle(self._pageTitle,extra=self.extraTitle,draw=draw) if new and draw: index = self.getIndex() self.tabs.SetPageText(index,self._pageTitle) if not(colour is None) and hasattr(self.tabs,'SetPageColour'): self.tabs.SetPageColour(index,colour) def SetIcon(self,*args,**keyw): pass def IsMaximized(self): return True def Activate(self): self.setTitle() self.parentFrame.tabs.SetSelection(self.getIndex()) def Raise(self): self.Activate() def onFrameActivate(self, event=None): if self._isActiveEvent(event): self.setTitle(new=False) Child.onFrameActivate(self,event) ## def onFrameActivate(self, event=None): ## if (not event) or event.GetActive(): ## self.setTitle(new=False) ## Child.onFrameActivate(self,event) class SdiChildFrame(TabPlatform,Child,wx.Frame): def __init__(self,parentFrame, id = wx.ID_ANY, style = STYLE_CHILDFRAME, page = '', extra = '', maximize = None, **options): self.noMenu = False app = parentFrame.app #debug message if app.DEBUG: print 'Create: Sdi: %s'%self.__class__,page,extra #maximize&init if maximize == None: maximize = parentFrame.maximize() if maximize: style |= wx.MAXIMIZE wx.Frame.__init__(self, id = id, name = page, parent = parentFrame, size = wx.Size(600,400), style = style | FULL_REPAINT_ON_RESIZE, title = page) if maximize: if PLATFORM != 'win32': self.Maximize() else: self.SetSize(app.size) #This always has to be last! Child.__init__(self, parentFrame = parentFrame, page = page, extra = extra, **options) def __stage__(self,page,extra,**options): """Create tabs to switch between documents as an wx.SashLayoutWindow""" if self.app.DEBUG: print 'Create: Sdi: %s.tabs'%(self.__class__,) tabs = self.tabs = NotebookPlus(app=self.app,parent=self, id=wx.ID_ANY, style = STYLE_NOTEBOOK ) panel = self.panel = self.Panel(parent=tabs,**options) #Add parent tab to itself tabs.AddPage(page=DummyPage(tabs),text=self.app.title) #Add child tabs to itself and vice versa for child in self.app.children: childTabs = child.frame.tabs tabs.AddPage(page=DummyPage(tabs),text=child.frame._pageTitle) childTabs.AddPage(page=DummyPage(childTabs),text=page) #Add itself to itself tabs.AddPage(page=panel,text=page,select=True) self.__layoutTabs__() def setTitle(self,page='',extra='',new=True,draw=True,colour=None): Child.setTitle(self,page,extra,new) if new and draw: self.tabs.SetPageText(self.getIndex()+1,self._pageTitle) ####Application class App(singleApp.SingleInstanceApp): def __init__(self, ParentPanel, ChildPanel, MenuBar, ToolBar, StatusBar, Palette=None, mdi=DEFAULT, debug=0, title='name', panelFrameTitle='panel',size=wx.Size(800,400), imagePath = None, pos=wx.Point(wx.ID_ANY,wx.ID_ANY), singleInstance = False, style=STYLE_PARENTFRAME,**attributes): #passing arguments global CHILDPANEL self.ParentPanel = ParentPanel self.ChildPanel = CHILDPANEL = ChildPanel self.MenuBar = MenuBar self.ToolBar = ToolBar self.StatusBar = StatusBar self.Palette = Palette self.SetMdi(mdi) self.DEBUG = debug self.title = title self.panelFrameTitle= panelFrameTitle self.size = size self.imagePath = imagePath self.pos = pos self.singleInstance = singleInstance self.active = True self.style = style #initialization self.children = [] self.childActive = None if self.imagePath: self.bitmap = wx.Bitmap = Bitmap(imagePath,self) else: self.bitmap = wx.Bitmap #options self.attributes = attributes for key in attributes: if hasattr(self,key): print "Warning: Application can't accept attribute '%s'."%key else: setattr(self,key,attributes[key]) #start if singleInstance: print "Launching single instance application (with xml-rpc server) ..." singleApp.SingleInstanceApp.__init__(self,redirect=not debug,name=title) else: print "Launching application..." wx.App.__init__(self,redirect=not debug) def OnArgs(self, evt): if hasattr(self.parentPanel,'onArgs'): self.parentPanel.onArgs(evt.data) self.GetTopWindow().Raise() self.GetTopWindow().Iconize(False) def OnInit(self): if self.singleInstance: if self.active: return False self.Bind(singleApp.EVT_POST_ARGS, self.OnArgs) wx.InitAllImageHandlers() self.parentFrame = self.ParentFrame(self, size = self.size, page = self.title, pos = self.pos, style = self.style, **self.attributes) self.parentPanel = self.parentFrame.panel self.parentFrame.Show(True) self.SetTopWindow(self.parentFrame) return True def SetMdi(self,mdiName=DEFAULT): """Defines parent and children frame classes.""" self.mdiName = mdiName if not DI.has_key(mdiName): mdiName = DEFAULT if mdiName == DEFAULT: if WIN: mdiName = MDI_SASH_TABS_WIN elif DARWIN:#mac osx mdiName = MDI_SPLIT_ALL else: mdiName = MDI_SPLIT_ALL#MDI_SASH_TABS_LINUX self.mdi = DI[mdiName] if self.mdi == SDI: self.ParentFrame = SdiParentFrame self.ChildFrame = SdiChildFrame elif self.mdi == MDI_SASH: self.ParentFrame = MdiSashParentFrame self.ChildFrame = MdiChildFrame elif self.mdi == MDI_SASH_TABS: self.ParentFrame = MdiSashTabsParentFrame self.ChildFrame = MdiSashTabsChildFrame #self.EVENT_NOTEBOOK = wx.EVT_NOTEBOOK_PAGE_CHANGED elif self.mdi == MDI: self.ParentFrame = MdiParentFrame self.ChildFrame = MdiChildFrame elif self.mdi == MDI_TABS: self.ParentFrame = MdiTabsParentFrame self.ChildFrame = MdiTabsChildFrame elif self.mdi == MDI_SPLIT: self.ParentFrame = MdiSplitParentFrame self.ChildFrame = MdiSplitChildFrame self.EVENT_NOTEBOOK = NotebookCtrl.EVT_NOTEBOOKCTRL_PAGE_CHANGED ## #Tabs: notebook event is platformdependent ## if WIN: ## #Under Windows, GetSelection() will return the same value as ## #GetOldSelection() when called from EVT_NOTEBOOK_PAGE_CHANGING handler and ## #not the page which is going to be selected ## #Therefore on Windows a combination of mouse click and hittest must be used. ## self.EVENT_NOTEBOOK = wx.EVT_LEFT_DOWN ## else: ## self.EVENT_NOTEBOOK = wx.EVT_NOTEBOOK_PAGE_CHANGING ####Test app class TestMenuBar(wx.MenuBar): def __init__(self,app,frame,*args,**kwds): wx.MenuBar.__init__(self,*args,**kwds) self.file = wx.Menu() self.file.Append(wx.ID_NEW, _("&New\tCtrl+N"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_CLOSE, _("&Close\tCtrl+W"), "", wx.ITEM_NORMAL) self.file.Append(wx.ID_EXIT, _("&Exit\tAlt+F4"), "", wx.ITEM_NORMAL) self.Append(self.file, "&File") def __events__(self): wx.EVT_MENU(self.frame,wx.ID_NEW,self.menu_new) wx.EVT_MENU(self.frame,wx.ID_CLOSE,self.menu_close) wx.EVT_MENU(self.frame,wx.ID_EXIT,self.menu_exit) def menu_new(self,event=None): self.parentPanel.new() def menu_close(self,event=None): self.parentPanel.close() def menu_exit(self,event=None): self.parentFrame.onFrameClose() ArtIDs = [ wx.ART_FILE_OPEN, wx.ART_PRINT, wx.ART_ADD_BOOKMARK, wx.ART_REPORT_VIEW, wx.ART_LIST_VIEW, wx.ART_HELP, ] class TestToolBar(wx.ToolBar): def __init__(self,parent=None,id=wx.ID_ANY,menu=None,app=None,**kwds): self.app = app wx.ToolBar.__init__(self,parent=parent,id=id,**kwds) parent.SetToolBar(self) self.tools = [] for id in ArtIDs: toolId = wx.NewId() bmp = wx.ArtProvider_GetBitmap(id, wx.ART_TOOLBAR, (16,16)) self.AddLabelTool(toolId, "", bmp, wx.NullBitmap, wx.ITEM_NORMAL, "info", "") self.tools.append(toolId) self.Realize() def __events__(self): for id in self.tools: wx.EVT_TOOL(self,id, self.test) def test(self,event): print 'test seems ok' class TestParentPanel(wx.TextCtrl): def __init__(self,parent,**kwds): wx.TextCtrl.__init__(self,parent=parent,id=wx.ID_ANY,value='parent',**kwds) self.test_child = 0 def new(self): value = 'child%02d'%self.test_child self.app.ChildFrame(self.frame,page=value,value=value) self.test_child += 1 def close(self): if self.app.children: active = self.app.childActive if active: active.frame.onFrameClose() class TestChildPanel(wx.TextCtrl): def __init__(self,parent,**kwds): wx.TextCtrl.__init__(self,parent=parent,id=wx.ID_ANY,**kwds) def __test__(debug,mdi=MDI): app = App(TestParentPanel, TestChildPanel, TestMenuBar, TestToolBar, wx.StatusBar, mdi=mdi, title='Parent', debug=debug) app.MainLoop() if __name__=='__main__': __test__(debug=1,mdi=MDI_TABS_WIN)#multiple document interface for windows #__test__(debug=1,mdi=MDI_TABS_MAC)#single document interface for mac #__test__(debug=1,mdi=MDI_SPLIT_ALL)#multiple document interface for mac spe-0.8.4.h/_spe/sm/wxp/realtime.py0000644000175000017500000003676310772036304016136 0ustar stanistani"""realtime.py | GPL - license | (c)2005 www.stani.be This module provides two classes which enable to update only selectively parts of a wx.TreeCtrl or a wx.ListCtrl. This makes fast/realtime updating possible of only changed items instead of the whole tree or list. These classes are used in SPE's sidebar: - TreeCtrl for Explore - ListCtrl for Todo & Index""" #todo: Maybe self.deleted of Item is not necessary import wx WARNING = 'Warning: %s: please contact spe.stani.be at gmail.com' class Item: def init(self): self.backgroundColour = (255,255,255) self.data = None self.deleted = False self.textColour = (0,0,0) self.wx = None def reset(self): self._update = [] #lists should be created for each instance separately self._updateAll = [] class Ctrl: _base = None def __init__(self): self.items = {} def _createUniqueId(self,base,others=[],data=None): """Create unique id with data & index.""" if data: try: dataId = '|'+repr(data).replace('%','%%') except: dataId = '' else: dataId = '' id = ('%s%s|%%d'%(base.replace('%','%%'),dataId)).encode('ascii','replace') nr = 0 othersId = [other.id for other in others] while id%nr in othersId: nr += 1 return id%nr def _deleteItem(self,item,fromItems=True): """Delete safely (not wx) item from self._items""" if item.wx != None and not item.deleted: self._wxDeleteItem(self,item.wx) item.wx = None if fromItems: item._delete() if self.items.has_key(item.id): del self.items[item.id] def _renewItem(self,item): """DeleteWx component and refresh update. This is used for an item which previously came earlier.""" self._deleteItem(item, fromItems = False) item._update = item._updateAll def _DeleteItem(self,item): """Indepedent delete wx item method (to be overwritten).""" def _insertItem(self,parent,children,index,text): """Inserts an item after a given one, used by self._update() (to be overwritten)""" def _prependItem(self,parent,text): """Inserts an item as the first one, used by self._update(). (to be overwritten)""" def _update(self,parent,recursively=False): """Update (recursively) all children (Item) of parent(Item or List).""" children = parent.children previousChildren = parent.previousChildren for index, child in enumerate(children[:]): if child in previousChildren: #child exists already prevIndex = previousChildren.index(child) abandoneds = previousChildren[:prevIndex] abandoneds.reverse() for abandoned in abandoneds: if abandoned in children: #only remove wx attribute self._renewItem(abandoned) else: #remove everything self._DeleteItem(abandoned) previousChildren= previousChildren[prevIndex+1:] elif previousChildren and previousChildren[0] not in children: #child can be copied in existing, abandoned item empty_slot = previousChildren[0] child = children[index]\ = self._copyItemTo(child,empty_slot) previousChildren= previousChildren[1:] else: #child must be created if index>0: child.wx = self._insertItem(parent,children,index,child.text) else: child.wx = self._prependItem(parent,child.text) self._updateItem(child,index) #recursive on its children if recursively: self._update(child,True) previousChildren.reverse() for abandoned in previousChildren: self._DeleteItem(abandoned) parent.previousChildren = children def _updateItem(self,item,index=None): """Execute pending update actions of TreeItem""" for action in item._update: arguments = [self,item.wx] arguments.extend(action[1:]) action[0](*arguments) def SetItemTextColour(self,item,color): """Sets the text colour of a TreeItem""" if item.textColour != color: item.textColour = color item._update.append((self._base.SetItemTextColour,color)) item._updateAll.append((self._base.SetItemTextColour,color)) def SetItemBackgroundColour(self,item,color): """Sets the background colour of a TreeItem""" if item.backgroundColour != color: item.backgroundColour = color item._update.append((self._base.SetItemBackgroundColour,color)) item._updateAll.append((self._base.SetItemBackgroundColour,color)) class TreeItem(Item): """All the wx actions are handled by the Tree class.""" def __init__(self,text,id): """self.wx holds the wx.TreeItemData""" self.id = id self.text = text # self.previousChildren = [] self.image = {} self.init() self.reset() def _delete(self): """When an item is removed its children are also removed recursively.""" for child in self.children: if child.children: child._delete(); child.deleted = True self.deleted = True def init(self): Item.init(self) self.bold = False def reset(self): Item.reset(self) self.children = [] class TreeCtrl(Ctrl,wx.TreeCtrl): _base = wx.TreeCtrl def __init__(self,*args,**kwargs): Ctrl.__init__(self) wx.TreeCtrl.__init__(self,*args, **kwargs) self._DeleteItem = self.Delete self._wxDeleteItem = wx.TreeCtrl.Delete self._style = kwargs['style'] self._hideRoot = self._style & wx.TR_HIDE_ROOT def _copyItemTo(self,frm,to): """Copy/steal wx control from an abandoned TreeItem to avoid creating a new wx control.""" frm.wx = to.wx if frm.data != to.data: frm._update.append((wx.TreeCtrl.SetPyData,frm.data)) frm._updateAll.append((wx.TreeCtrl.SetPyData,frm.data)) frm.previousChildren = to.previousChildren if frm.text != to.text: frm._update.append((wx.TreeCtrl.SetItemText,frm.text)) frm._updateAll.append((wx.TreeCtrl.SetItemText,frm.text)) return frm def _insertItem(self,parent,children,index,text): """Inserts an item after a given one.""" return wx.TreeCtrl.InsertItem(self,parent.wx,children[index-1].wx,text) def _prependItem(self,parent,text): """Inserts an item as the first one.""" return wx.TreeCtrl.PrependItem(self,parent.wx,text) def AddRoot(self,text): self.root = TreeItem(text=text,id=text) self.items[text] = self.root self.root.wx = wx.TreeCtrl.AddRoot(self,text) if not self._hideRoot: self.root._update.append((wx.TreeCtrl.Expand,)) return self.root def AppendItem(self,parent,text,data=None): """Add data immediately, if the label is not unique. Be aware that that is a devation from wx.ListCtrl, if data is not wxTreeItemData. There are two possibilities that an item is appended to its parent - if already present, pick it up and update the text - if not, create one item""" if hasattr(data,'GetData'): data = data.GetData() pChildren = parent.children id = self._createUniqueId( base = '%s|%s'%(parent.id,text), others = pChildren, data = data ) #get item if self.items.has_key(id): item = self.items[id] item.reset() else: item = self.items[id] = TreeItem(text=text,id=id) pChildren.append(item) #data if data != None: self.SetPyData(item,data) return item def Delete(self,item): """Delete item and all its children from the tree.""" self._deleteItem(item) def Update(self): """Update only differences between current and previous state. This method MUST be called in the end otherwise there will be no visual change.""" self._update(self.root,recursively=True) self._updateItem(self.root) def Collapse(self,item): """Collapse a TreeItem.""" if wx.TreeCtrl.IsExpanded(self,item.wx): wx.TreeCtrl.Collapse(self,item.wx) def CollapseAndReset(self,item): """Remove children of a TreeItem, mostly used for self.root.""" item.children = [] def Expand(self,item): """Expands a TreeItem.""" if not ((self._hideRoot and item == self.root) or wx.TreeCtrl.IsExpanded(self,item.wx)): wx.TreeCtrl.Expand(self,item.wx) def SetItemBold(self,item,bold=True): """Sets the background colour of a TreeItem""" if item.bold != bold: item.bold = bold item._update.append((wx.TreeCtrl.SetItemBold,bold)) item._updateAll.append((wx.TreeCtrl.SetItemBold,bold)) def SetItemImage(self,item,image,which=wx.TreeItemIcon_Normal): """Sets the image for a certain state (which) of a TreeItem""" if (not item.image.has_key(which)) or item.image[which] != image: item.image[which] = image item._update.append((wx.TreeCtrl.SetItemImage,image,which)) item._updateAll.append((wx.TreeCtrl.SetItemImage,image,which)) def SetItemText(self,item,text): """Sets the text of a TreeItem""" if item.text != text: item.text = text item._update.append((wx.TreeCtrl.SetItemText,text)) item._updateAll.append((wx.TreeCtrl.SetItemText,text)) def SetPyData(self,item,data): """Sets the py data of a TreeItem.""" if item.data != data: item.data = data item._update.append((wx.TreeCtrl.SetPyData,data)) item._updateAll.append((wx.TreeCtrl.SetPyData,data)) class ListItem(Item): def __init__(self,index,text,id): self.index = index self.text = text self.id = id # self.image = None self.init() self.reset() def init(self): Item.init(self) self.data = 0 def _delete(self): """Flag as deleted.""" self.deleted = True class ListCtrl(Ctrl,wx.ListCtrl): _base = wx.ListCtrl def __init__(self,*args,**kwds): Ctrl.__init__(self) wx.ListCtrl.__init__(self,*args,**kwds) self._DeleteItem = self.DeleteItem self._wxDeleteItem = wx.ListCtrl.DeleteItem self.children = [] self.previousChildren = [] def _copyItemTo(self,frm,to): """Copy/steal wx control from an abandoned TreeItem to avoid creating a new wx control.""" frm.wx = to.wx if frm.data != to.data: frm._update.append((wx.ListCtrl.SetItemData,frm.data)) frm._updateAll.append((wx.ListCtrl.SetItemData,frm.data)) toText = to.text for column, label in frm.text.items(): if toText.has_key(column) and label != toText[column]: frm._update.append((wx.ListCtrl.SetStringItem,column,label)) frm._updateAll.append((wx.ListCtrl.SetStringItem,column,label)) return frm def _insertItem(self,parent,children,index,text): """Inserts an item after a given one.""" return wx.ListCtrl.InsertStringItem(self,index,text[0]) def _prependItem(self,parent,text): """Inserts an item as the first one.""" return wx.ListCtrl.InsertStringItem(self,0,text[0]) def _updateItem(self,item,index): """Same as Ctrl, but update also index.""" item.wx = index Ctrl._updateItem(self,item,index) def DeleteAllItems(self): self.children = [] def DeleteItem(self,item): """Delete item safely.""" if item in self.children: self.children.remove(item) self._deleteItem(item) def InsertStringItem(self,index,label,data=None): """Add data immediately, if the label is not unique. Be aware that that is a devation from wx.ListCtrl There are two possibilities that an item is appended to its parent - if already present, pick it up and update the text - if not, create one item""" id = self._createUniqueId( base = label, others = self.children, data = data ) #get item if self.items.has_key(id): item = self.items[id] item.reset() else: item = self.items[id] = ListItem(index=index,text={0:label},id=id) self.children.append(item) #data if data != None: self.SetItemData(item,data) return item def InsertImageStringItem(self,index,label,imageIndex): item = self.InsertStringItem(index,label) self.SetItemImage(item,imageIndex) return item def SetItemImage(self,item,imageIndex): if item.image != imageIndex: item.image = imageIndex item._update.append((wx.ListCtrl.SetItemImage,imageIndex)) item._updateAll.append((wx.ListCtrl.SetItemImage,imageIndex)) def SetItemData(self,item,data): if item.data != data: item.data = data item._update.append((wx.ListCtrl.SetItemData,data)) item._updateAll.append((wx.ListCtrl.SetItemData,data)) def SetItemText(self,item,text): """Sets the text of a TreeItem""" if item.text != text: item.text = text item._update.append((wx.TreeCtrl.SetItemText,text)) item._updateAll.append((wx.TreeCtrl.SetItemText,text)) def SetStringItem(self,item,column,label): text = item.text if not text.has_key(column) or text[column] != label: text[column] = label item._update.append((wx.ListCtrl.SetStringItem,column,label)) item._updateAll.append((wx.ListCtrl.SetStringItem,column,label)) def Update(self): """Update only differences between current and previous state. This method MUST be called in the end otherwise there will be no visual change.""" self._update(self,recursively=False) spe-0.8.4.h/_spe/dialogs/helpShortcutsDialog.py0000644000175000017500000000533410272471120020470 0ustar stanistani#Boa:Dialog:wxDialog1 #(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Help dialog showing all the shortcuts.""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import os #---Boa generated from wxPython.wx import * def create(parent,path=''): return wxDialog1(parent,path) [wxID_WXDIALOG1, wxID_WXDIALOG1LISTCTRL1, ] = map(lambda _init_ctrls: wxNewId(), range(2)) class wxDialog1(wxDialog): def _init_coll_listCtrl1_Columns(self, parent): # generated method, don't edit parent.InsertColumn(col=0, format=wxLIST_FORMAT_LEFT, heading='Key', width=170) parent.InsertColumn(col=1, format=wxLIST_FORMAT_LEFT, heading='Description', width=500) def _init_utils(self): # generated method, don't edit pass def _init_ctrls(self, prnt): # generated method, don't edit wxDialog.__init__(self, id=wxID_WXDIALOG1, name='', parent=prnt, pos=wxPoint(119, 108), size=wxSize(486, 376), style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX, title='Spe - Shorcuts - www.stani.be') self._init_utils() self.SetClientSize(wxSize(478, 349)) self.listCtrl1 = wxListCtrl(id=wxID_WXDIALOG1LISTCTRL1, name='listCtrl1', parent=self, pos=wxPoint(0, 0), size=wxSize(478, 349), style=wxLC_REPORT, validator=wxDefaultValidator) self._init_coll_listCtrl1_Columns(self.listCtrl1) def __init__(self, parent, path): #wxImage_AddHandler(wxPNGHandler()) self._init_ctrls(parent) self.init_listCtrl1(path) def init_listCtrl1(self,path): f=open(os.path.join(path,'dialogs','shortcuts.txt')) lines=f.read().split('\n') f.close() ln=0 self.il=wxImageList(16, 16) self.key = self.il.Add(wxBitmap(os.path.join(path,'images','keyboard.png'),wxBITMAP_TYPE_PNG)) self.keys = self.il.Add(wxBitmap(os.path.join(path,'images','key_bindings.png'),wxBITMAP_TYPE_PNG)) self.listCtrl1.SetImageList(self.il, wxIMAGE_LIST_SMALL) for line in lines: data=line.split('\t') if len(data)>2: if data[0].replace('SHIFT','').replace('CTRL','').replace('ALT','')==data[0]: self.listCtrl1.InsertImageStringItem(ln,data[0],self.key) else: self.listCtrl1.InsertImageStringItem(ln,data[0],self.keys) self.listCtrl1.SetStringItem(ln, 1, data[2]) ln+=1 spe-0.8.4.h/_spe/dialogs/runTerminalDialog.wxg0000644000175000017500000001124010573602362020277 0ustar stanistani Stani's Python Editor - Run wxVERTICAL wxALL 4 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALL|wxALIGN_CENTER_VERTICAL 4 -1 wxALL 4 wxALL 4 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 1 wxALL|wxALIGN_CENTER_VERTICAL 4 wx.ID_CANCEL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wx.ID_OK spe-0.8.4.h/_spe/dialogs/stcStyleEditor.py0000644000175000017500000014610110366063006017464 0ustar stanistani#----------------------------------------------------------------------------- # Name: STCStyleEditor.py # Purpose: Style editor for the wx.StyledTextCtrl adapted for SPE # # Author: Riaan Booysen, Vlad, Stani # # Created: 2001/08/20 # RCS-ID: $Id: STCStyleEditor.py,v 1.5 2004/06/26 18:45:02 RD Exp $ # Copyright: (c) 2001 - 2002 Riaan Booysen # Licence: wx.Windows license #----------------------------------------------------------------------------- #Boa:Dialog:STCStyleEditDlg import os, string, pprint, copy import ConfigParser import wx from wx.lib.anchors import LayoutAnchors import wx.stc as wx_stc customStyle = 'stc.style.Custom' settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'} commonPropDefs = {} styleCategoryDescriptions = { '----Language----': 'Styles spesific to the language', '----Standard----': 'Styles shared by all languages', '----Settings----': 'Properties set by STC methods', '----Common----': 'User definable values that can be shared between languages'} [ID_STCSTYLEEDITDLG, ID_STCSTYLEEDITDLGADDCOMMONITEMBTN, ID_STCSTYLEEDITDLGBGCOLBTN, ID_STCSTYLEEDITDLGBGCOLCB, ID_STCSTYLEEDITDLGBGCOLDEFCB, ID_STCSTYLEEDITDLGBGCOLOKBTN, ID_STCSTYLEEDITDLGCANCELBTN, ID_STCSTYLEEDITDLGCONTEXTHELPBUTTON1, ID_STCSTYLEEDITDLGELEMENTLB, ID_STCSTYLEEDITDLGFACECB, ID_STCSTYLEEDITDLGFACEDEFCB, ID_STCSTYLEEDITDLGFACEOKBTN, ID_STCSTYLEEDITDLGFGCOLBTN, ID_STCSTYLEEDITDLGFGCOLCB, ID_STCSTYLEEDITDLGFGCOLDEFCB, ID_STCSTYLEEDITDLGFGCOLOKBTN, ID_STCSTYLEEDITDLGFIXEDWIDTHCHK, ID_STCSTYLEEDITDLGOKBTN, ID_STCSTYLEEDITDLGPANEL1, ID_STCSTYLEEDITDLGPANEL2, ID_STCSTYLEEDITDLGPANEL3, ID_STCSTYLEEDITDLGPANEL4, ID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN, ID_STCSTYLEEDITDLGSIZECB, ID_STCSTYLEEDITDLGSIZEOKBTN, ID_STCSTYLEEDITDLGSPEEDSETTINGCH, ID_STCSTYLEEDITDLGSTATICBOX1, ID_STCSTYLEEDITDLGSTATICBOX2, ID_STCSTYLEEDITDLGSTATICLINE1, ID_STCSTYLEEDITDLGSTATICTEXT2, ID_STCSTYLEEDITDLGSTATICTEXT3, ID_STCSTYLEEDITDLGSTATICTEXT4, ID_STCSTYLEEDITDLGSTATICTEXT6, ID_STCSTYLEEDITDLGSTATICTEXT7, ID_STCSTYLEEDITDLGSTATICTEXT8, ID_STCSTYLEEDITDLGSTATICTEXT9, ID_STCSTYLEEDITDLGSTC, ID_STCSTYLEEDITDLGSTYLEDEFST, ID_STCSTYLEEDITDLGTABOLDCB, ID_STCSTYLEEDITDLGTABOLDDEFCB, ID_STCSTYLEEDITDLGTAEOLFILLEDCB, ID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB, ID_STCSTYLEEDITDLGTAITALICCB, ID_STCSTYLEEDITDLGTAITALICDEFCB, ID_STCSTYLEEDITDLGTASIZEDEFCB, ID_STCSTYLEEDITDLGTAUNDERLINEDCB, ID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB, ] = map(lambda _init_ctrls: wx.NewId(), range(47)) class STCStyleEditDlg(wx.Dialog): """ Style editor for the wx.StyledTextCtrl """ _custom_classes = {'wx.Window' : ['wx.StyledTextCtrl']} def _init_utils(self): # generated method, don't edit pass def _init_ctrls(self, prnt): # generated method, don't edit wx.Dialog.__init__(self, id=ID_STCSTYLEEDITDLG, name='STCStyleEditDlg', parent=prnt, pos=wx.Point(583, 291), size=wx.Size(459, 482), style=wx.WANTS_CHARS | wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, title=self.stc_title) self._init_utils() self.SetClientSize(wx.Size(451, 455)) self.SetAutoLayout(True) self.SetSizeHints(425, 400, -1, -1) self.Center(wx.BOTH) wx.EVT_SIZE(self, self.OnStcstyleeditdlgSize) self.speedsettingCh = wx.Choice(choices=[], id=ID_STCSTYLEEDITDLGSPEEDSETTINGCH, name='speedsettingCh', parent=self, pos=wx.Point(96, 28), size=wx.Size(346, 21), style=0, validator=wx.DefaultValidator) self.speedsettingCh.SetConstraints(LayoutAnchors(self.speedsettingCh, True, True, True, False)) self.speedsettingCh.SetHelpText('The speed setting allows you to revert to one of the predefined style sets. This will overwrite your current settings when tha dialog is posted.') wx.EVT_CHOICE(self.speedsettingCh, ID_STCSTYLEEDITDLGSPEEDSETTINGCH, self.OnSpeedsettingchChoice) self.elementLb = wx.ListBox(choices=[], id=ID_STCSTYLEEDITDLGELEMENTLB, name='elementLb', parent=self, pos=wx.Point(8, 72), size=wx.Size(160, 128), style=0, validator=wx.DefaultValidator) self.elementLb.SetConstraints(LayoutAnchors(self.elementLb, True, True, True, False)) self.elementLb.SetHelpText('Select a style here to edit it. Common definitions can be added and maintained here. A common definition is a property that can be shared between styles and special cased per platform.') wx.EVT_LISTBOX(self.elementLb, ID_STCSTYLEEDITDLGELEMENTLB, self.OnElementlbListbox) self.styleDefST = wx.StaticText(id=ID_STCSTYLEEDITDLGSTYLEDEFST, label='(nothing selected)', name='styleDefST', parent=self, pos=wx.Point(96, 8), size=wx.Size(366, 16), style=wx.ST_NO_AUTORESIZE) self.styleDefST.SetFont(wx.Font(self.style_font_size, wx.SWISS, wx.NORMAL, wx.BOLD, False, '')) self.styleDefST.SetConstraints(LayoutAnchors(self.styleDefST, True, True, True, False)) self.staticLine1 = wx.StaticLine(id=ID_STCSTYLEEDITDLGSTATICLINE1, name='staticLine1', parent=self, pos=wx.Point(48, 62), size=wx.Size(120, 2), style=wx.LI_HORIZONTAL) self.staticLine1.SetConstraints(LayoutAnchors(self.staticLine1, True, True, True, False)) self.staticText6 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT6, label='Style', name='staticText6', parent=self, pos=wx.Point(8, 56), size=wx.Size(40, 13), style=0) self.staticText8 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT8, label='Style def:', name='staticText8', parent=self, pos=wx.Point(8, 8), size=wx.Size(88, 13), style=0) self.staticText9 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT9, label='SpeedSetting:', name='staticText9', parent=self, pos=wx.Point(8, 32), size=wx.Size(88, 13), style=0) self.panel3 = wx.Panel(id=ID_STCSTYLEEDITDLGPANEL3, name='panel3', parent=self, pos=wx.Point(176, 56), size=wx.Size(146, 104), style=wx.TAB_TRAVERSAL) self.panel3.SetConstraints(LayoutAnchors(self.panel3, False, True, True, False)) self.panel4 = wx.Panel(id=ID_STCSTYLEEDITDLGPANEL4, name='panel4', parent=self, pos=wx.Point(330, 56), size=wx.Size(114, 104), style=wx.TAB_TRAVERSAL) self.panel4.SetConstraints(LayoutAnchors(self.panel4, False, True, True, False)) self.panel1 = wx.Panel(id=ID_STCSTYLEEDITDLGPANEL1, name='panel1', parent=self, pos=wx.Point(176, 161), size=wx.Size(143, 40), style=wx.TAB_TRAVERSAL) self.panel1.SetConstraints(LayoutAnchors(self.panel1, False, True, True, False)) self.panel2 = wx.Panel(id=ID_STCSTYLEEDITDLGPANEL2, name='panel2', parent=self, pos=wx.Point(330, 162), size=wx.Size(112, 40), style=wx.TAB_TRAVERSAL) self.panel2.SetConstraints(LayoutAnchors(self.panel2, False, True, True, False)) self.stc = wx_stc.StyledTextCtrl(id=ID_STCSTYLEEDITDLGSTC, name='stc', parent=self, pos=wx.Point(8, 208), size=wx.Size(435, 207), style=wx.SUNKEN_BORDER) self.stc.SetConstraints(LayoutAnchors(self.stc, True, True, True, True)) self.stc.SetHelpText('The style preview window. Click or move the cursor over a spesific style to select the style for editing in the editors above.') wx.EVT_LEFT_UP(self.stc, self.OnUpdateUI) wx.EVT_KEY_UP(self.stc, self.OnUpdateUI) self.contextHelpButton1 = wx.ContextHelpButton(parent=self, pos=wx.Point(8, 423), size=wx.Size(24, 24), style=wx.BU_AUTODRAW) self.contextHelpButton1.SetConstraints(LayoutAnchors(self.contextHelpButton1, True, False, False, True)) self.okBtn = wx.Button(id=ID_STCSTYLEEDITDLGOKBTN, label='OK', name='okBtn', parent=self, pos=wx.Point(282, 423), size=wx.Size(75, 23), style=0) self.okBtn.SetConstraints(LayoutAnchors(self.okBtn, False, False, True, True)) self.okBtn.SetToolTipString('Save changes to the config file') wx.EVT_BUTTON(self.okBtn, ID_STCSTYLEEDITDLGOKBTN, self.OnOkbtnButton) self.cancelBtn = wx.Button(id=ID_STCSTYLEEDITDLGCANCELBTN, label='Cancel', name='cancelBtn', parent=self, pos=wx.Point(366, 423), size=wx.Size(75, 23), style=0) self.cancelBtn.SetConstraints(LayoutAnchors(self.cancelBtn, False, False, True, True)) self.cancelBtn.SetToolTipString('Close dialog without saving changes') wx.EVT_BUTTON(self.cancelBtn, ID_STCSTYLEEDITDLGCANCELBTN, self.OnCancelbtnButton) self.staticText4 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT4, label='Face:', name='staticText4', parent=self.panel1, pos=wx.Point(0, 0), size=wx.Size(48, 13), style=0) self.fixedWidthChk = wx.CheckBox(id=ID_STCSTYLEEDITDLGFIXEDWIDTHCHK, label='', name='fixedWidthChk', parent=self.panel1, pos=wx.Point(0, 23), size=wx.Size(13, 19), style=0) self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts') wx.EVT_CHECKBOX(self.fixedWidthChk, ID_STCSTYLEEDITDLGFIXEDWIDTHCHK, self.OnFixedwidthchkCheckbox) self.faceCb = wx.ComboBox(choices=[], id=ID_STCSTYLEEDITDLGFACECB, name='faceCb', parent=self.panel1, pos=wx.Point(17, 18), size=wx.Size(105, 21), style=0, validator=wx.DefaultValidator, value='') self.staticText7 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT7, label='Size:', name='staticText7', parent=self.panel2, pos=wx.Point(0, 0), size=wx.Size(40, 13), style=0) self.sizeCb = wx.ComboBox(choices=[], id=ID_STCSTYLEEDITDLGSIZECB, name='sizeCb', parent=self.panel2, pos=wx.Point(0, 17), size=wx.Size(91, 21), style=0, validator=wx.DefaultValidator, value='') self.sizeOkBtn = wx.Button(id=ID_STCSTYLEEDITDLGSIZEOKBTN, label='ok', name='sizeOkBtn', parent=self.panel2, pos=wx.Point(90, 17), size=wx.Size(21, 21), style=0) self.faceOkBtn = wx.Button(id=ID_STCSTYLEEDITDLGFACEOKBTN, label='ok', name='faceOkBtn', parent=self.panel1, pos=wx.Point(122, 18), size=wx.Size(21, 21), style=0) self.fgColBtn = wx.Button(id=ID_STCSTYLEEDITDLGFGCOLBTN, label='Foreground', name='fgColBtn', parent=self.panel3, pos=wx.Point(8, 16), size=wx.Size(72, 16), style=0) wx.EVT_BUTTON(self.fgColBtn, ID_STCSTYLEEDITDLGFGCOLBTN, self.OnFgcolbtnButton) self.fgColCb = wx.ComboBox(choices=[], id=ID_STCSTYLEEDITDLGFGCOLCB, name='fgColCb', parent=self.panel3, pos=wx.Point(8, 32), size=wx.Size(89, 21), style=0, validator=wx.DefaultValidator, value='') self.fgColOkBtn = wx.Button(id=ID_STCSTYLEEDITDLGFGCOLOKBTN, label='ok', name='fgColOkBtn', parent=self.panel3, pos=wx.Point(96, 32), size=wx.Size(21, 21), style=0) self.staticText3 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT3, label='default', name='staticText3', parent=self.panel3, pos=wx.Point(100, 16), size=wx.Size(37, 16), style=0) self.fgColDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGFGCOLDEFCB, label='checkBox1', name='fgColDefCb', parent=self.panel3, pos=wx.Point(120, 31), size=wx.Size(16, 16), style=0) self.bgColBtn = wx.Button(id=ID_STCSTYLEEDITDLGBGCOLBTN, label='Background', name='bgColBtn', parent=self.panel3, pos=wx.Point(8, 56), size=wx.Size(72, 16), style=0) wx.EVT_BUTTON(self.bgColBtn, ID_STCSTYLEEDITDLGBGCOLBTN, self.OnBgcolbtnButton) self.bgColCb = wx.ComboBox(choices=[], id=ID_STCSTYLEEDITDLGBGCOLCB, name='bgColCb', parent=self.panel3, pos=wx.Point(8, 72), size=wx.Size(89, 21), style=0, validator=wx.DefaultValidator, value='') self.bgColOkBtn = wx.Button(id=ID_STCSTYLEEDITDLGBGCOLOKBTN, label='ok', name='bgColOkBtn', parent=self.panel3, pos=wx.Point(96, 72), size=wx.Size(21, 21), style=0) self.staticBox2 = wx.StaticBox(id=ID_STCSTYLEEDITDLGSTATICBOX2, label='Text attributes', name='staticBox2', parent=self.panel4, pos=wx.Point(0, 0), size=wx.Size(112, 99), style=0) self.staticBox2.SetConstraints(LayoutAnchors(self.staticBox2, False, True, True, False)) self.staticBox2.SetHelpText('Text attribute flags.') self.staticText2 = wx.StaticText(id=ID_STCSTYLEEDITDLGSTATICTEXT2, label='default', name='staticText2', parent=self.panel4, pos=wx.Point(68, 11), size=wx.Size(37, 16), style=0) self.taBoldDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTABOLDDEFCB, label='checkBox1', name='taBoldDefCb', parent=self.panel4, pos=wx.Point(88, 27), size=wx.Size(16, 16), style=0) self.taItalicDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAITALICDEFCB, label='checkBox1', name='taItalicDefCb', parent=self.panel4, pos=wx.Point(88, 43), size=wx.Size(16, 16), style=0) self.taUnderlinedDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB, label='checkBox1', name='taUnderlinedDefCb', parent=self.panel4, pos=wx.Point(88, 59), size=wx.Size(16, 16), style=0) self.taEOLfilledDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB, label='checkBox1', name='taEOLfilledDefCb', parent=self.panel4, pos=wx.Point(88, 75), size=wx.Size(16, 16), style=0) self.taEOLfilledCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAEOLFILLEDCB, label='EOL filled', name='taEOLfilledCb', parent=self.panel4, pos=wx.Point(8, 75), size=wx.Size(72, 16), style=0) wx.EVT_CHECKBOX(self.taEOLfilledCb, ID_STCSTYLEEDITDLGTAEOLFILLEDCB, self.OnTaeoffilledcbCheckbox) self.taUnderlinedCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAUNDERLINEDCB, label='Underlined', name='taUnderlinedCb', parent=self.panel4, pos=wx.Point(8, 59), size=wx.Size(72, 16), style=0) wx.EVT_CHECKBOX(self.taUnderlinedCb, ID_STCSTYLEEDITDLGTAUNDERLINEDCB, self.OnTaunderlinedcbCheckbox) self.taItalicCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTAITALICCB, label='Italic', name='taItalicCb', parent=self.panel4, pos=wx.Point(8, 43), size=wx.Size(72, 16), style=0) wx.EVT_CHECKBOX(self.taItalicCb, ID_STCSTYLEEDITDLGTAITALICCB, self.OnTaitaliccbCheckbox) self.taBoldCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTABOLDCB, label='Bold', name='taBoldCb', parent=self.panel4, pos=wx.Point(8, 27), size=wx.Size(72, 16), style=0) wx.EVT_CHECKBOX(self.taBoldCb, ID_STCSTYLEEDITDLGTABOLDCB, self.OnTaboldcbCheckbox) self.bgColDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGBGCOLDEFCB, label='checkBox1', name='bgColDefCb', parent=self.panel3, pos=wx.Point(120, 71), size=wx.Size(16, 16), style=0) self.staticBox1 = wx.StaticBox(id=ID_STCSTYLEEDITDLGSTATICBOX1, label='Colour', name='staticBox1', parent=self.panel3, pos=wx.Point(0, 0), size=wx.Size(142, 99), style=0) self.staticBox1.SetConstraints(LayoutAnchors(self.staticBox1, False, True, True, False)) self.faceDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGFACEDEFCB, label='checkBox1', name='faceDefCb', parent=self.panel1, pos=wx.Point(120, 0), size=wx.Size(16, 16), style=0) self.taSizeDefCb = wx.CheckBox(id=ID_STCSTYLEEDITDLGTASIZEDEFCB, label='checkBox1', name='taSizeDefCb', parent=self.panel2, pos=wx.Point(88, 0), size=wx.Size(16, 16), style=0) def __init__(self, parent, langTitle, configFile, STC): global commonPropDefs commonPropDefs = {'fore': '#888888', 'size': 10, 'face': wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT).GetFaceName()} self.stc_title = 'wx.StyledTextCtrl Style Editor' self.stc_title = 'wx.StyledTextCtrl Style Editor - %s' % langTitle if wx.Platform == '__WXMSW__': self.style_font_size = 10 elif wx.Platform == '__WXMAC__': self.style_font_size = 14 commonPropDefs['size']=14 else: self.style_font_size = 10 self._init_ctrls(parent) self.configFile = configFile self.style = '' self.styleNum = 0 self.names = [] self.values = {} self.STC = STC self._blockUpdate = False for combo, okBtn, evtRet, evtCB, evtRDC in ( (self.fgColCb, self.fgColOkBtn, self.OnfgColRet, self.OnfgColCombobox, self.OnGotoCommonDef), (self.bgColCb, self.bgColOkBtn, self.OnbgColRet, self.OnbgColCombobox, self.OnGotoCommonDef), (self.faceCb, self.faceOkBtn, self.OnfaceRet, self.OnfaceCombobox, self.OnGotoCommonDef), (self.sizeCb, self.sizeOkBtn, self.OnsizeRet, self.OnsizeCombobox, self.OnGotoCommonDef)): self.bindComboEvts(combo, okBtn, evtRet, evtCB, evtRDC) (self.config, self.commonDefs, self.styleIdNames, self.styles, self.styleGroupNames, self.predefStyleGroups, self.displaySrc, self.keywords, self.braceInfo) = \ initFromConfig(configFile) self.currSpeedSetting = customStyle for grp in [self.currSpeedSetting]+self.styleGroupNames: self.speedsettingCh.Append(grp) self.speedsettingCh.SetSelection(0) margin = 0 self.stc.SetMarginType(margin, wx_stc.STC_MARGIN_NUMBER) self.stc.SetMarginWidth(margin, 25) self.stc.SetMarginSensitive(margin, True) wx_stc.EVT_STC_MARGINCLICK(self.stc, ID_STCSTYLEEDITDLGSTC, self.OnMarginClick) self.stc.SetUseTabs(False) self.stc.SetTabWidth(4) self.stc.SetIndentationGuides(True) self.stc.SetEdgeMode(wx_stc.STC_EDGE_BACKGROUND) self.stc.SetEdgeColumn(44) self.setStyles() self.populateStyleSelector() self.defNames, self.defValues = parseProp(\ self.styleDict.get(wx_stc.STC_STYLE_DEFAULT, '')) self.stc.SetText(self.displaySrc) self.stc.EmptyUndoBuffer() self.stc.SetCurrentPos(self.stc.GetTextLength()) self.stc.SetAnchor(self.stc.GetTextLength()) self.populateCombosWithCommonDefs() # Logical grouping of controls and the property they edit self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb, 'fore', ID_STCSTYLEEDITDLGFGCOLDEFCB), ((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb, 'back', ID_STCSTYLEEDITDLGBGCOLDEFCB), (self.taBoldCb, self.taBoldDefCb, 'bold', ID_STCSTYLEEDITDLGTABOLDDEFCB), (self.taItalicCb, self.taItalicDefCb, 'italic', ID_STCSTYLEEDITDLGTAITALICDEFCB), (self.taUnderlinedCb, self.taUnderlinedDefCb, 'underline', ID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB), (self.taEOLfilledCb, self.taEOLfilledDefCb, 'eolfilled', ID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB), ((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb, 'size', ID_STCSTYLEEDITDLGTASIZEDEFCB), ((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb, 'face', ID_STCSTYLEEDITDLGFACEDEFCB)] self.clearCtrls(disableDefs=True) # centralised default checkbox event handler self.chbIdMap = {} for ctrl, chb, prop, wid in self.allCtrls: self.chbIdMap[wid] = ctrl, chb, prop, wid wx.EVT_CHECKBOX(chb, wid, self.OnDefaultCheckBox) chb.SetToolTipString('Toggle defaults') self.Center(wx.BOTH) #---Property methods------------------------------------------------------------ def getCtrlForProp(self, findprop): for ctrl, chb, prop, wid in self.allCtrls: if findprop == prop: return ctrl, chb raise Exception('PropNotFound', findprop) def editProp(self, on, prop, val=''): oldstyle = self.rememberStyles() if on: if not self.names.count(prop): self.names.append(prop) self.values[prop] = val else: try: self.names.remove(prop) except ValueError: pass try: del self.values[prop] except KeyError: pass try: self.updateStyle() return True except KeyError, errkey: wx.LogError('Name not found in Common definition, '\ 'please enter valid reference. (%s)'%errkey) self.restoreStyles(oldstyle) return False #---Control population methods-------------------------------------------------- def setStyles(self): if self._blockUpdate: return self.styles, self.styleDict, self.styleNumIdxMap = \ setSTCStyles(self.stc, self.styles, self.styleIdNames, self.commonDefs, self.keywords) def updateStyle(self): # called after a control edited self.names, self.values # Special case for saving common defs settings if self.styleNum == 'common': strVal = self.style[2] = self.values.values()[0] if self.style[1] == 'size': self.style[2] = int(strVal) self.commonDefs[self.style[0]] = self.style[2] self.styleDefST.SetLabel(strVal) else: self.style = writePropVal(self.names, self.values) styleDecl = writeProp(self.styleNum, self.style) self.styles[self.styleNumIdxMap[self.styleNum]] = styleDecl self.styleDefST.SetLabel(self.style) self.setStyles() def findInStyles(self, txt, styles): for style in styles: if string.find(style, txt) != -1: return True return False def rememberStyles(self): return self.names[:], copy.copy(self.values) def restoreStyles(self, style): self.names, self.values = style self.updateStyle() def clearCtrls(self, isDefault=False, disableDefs=False): self._blockUpdate = True try: for ctrl, chb, prop, wid in self.allCtrls: if prop in ('fore', 'back'): cbtn, txt, btn = ctrl cbtn.SetBackgroundColour(\ wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)) cbtn.SetForegroundColour(wx.Colour(255, 255, 255)) cbtn.Enable(isDefault) txt.SetValue('') txt.Enable(isDefault) btn.Enable(isDefault) elif prop == 'size': cmb, btn = ctrl cmb.SetValue('') cmb.Enable(isDefault) btn.Enable(isDefault) elif prop == 'face': cmb, btn, chk = ctrl cmb.SetValue('') cmb.Enable(isDefault) btn.Enable(isDefault) chk.Enable(isDefault) chk.SetValue(False) elif prop in ('bold', 'italic', 'underline', 'eolfilled'): ctrl.SetValue(False) ctrl.Enable(isDefault) chb.Enable(not isDefault and not disableDefs) chb.SetValue(True) finally: self._blockUpdate = False def populateProp(self, items, default, forceDisable=False): self._blockUpdate = True try: for name, val in items: if name: ctrl, chb = self.getCtrlForProp(name) if name in ('fore', 'back'): cbtn, txt, btn = ctrl repval = val%self.commonDefs cbtn.SetBackgroundColour(strToCol(repval)) cbtn.SetForegroundColour(wx.Colour(0, 0, 0)) cbtn.Enable(not forceDisable) txt.SetValue(val) txt.Enable(not forceDisable) btn.Enable(not forceDisable) chb.SetValue(default) elif name == 'size': cmb, btn = ctrl cmb.SetValue(val) cmb.Enable(not forceDisable) btn.Enable(not forceDisable) chb.SetValue(default) elif name == 'face': cmb, btn, chk = ctrl cmb.SetValue(val) cmb.Enable(not forceDisable) btn.Enable(not forceDisable) chk.Enable(not forceDisable) chb.SetValue(default) elif name in ('bold', 'italic', 'underline', 'eolfilled'): ctrl.Enable(not forceDisable) ctrl.SetValue(True) chb.SetValue(default) finally: self._blockUpdate = False def valIsCommonDef(self, val): return len(val) >= 5 and val[:2] == '%(' def populateCtrls(self): self.clearCtrls(self.styleNum == wx_stc.STC_STYLE_DEFAULT, disableDefs=self.styleNum < 0) # handle colour controls for settings if self.styleNum < 0: self.fgColDefCb.Enable(True) if self.styleNum == -1: self.bgColDefCb.Enable(True) # populate with default style self.populateProp(self.defValues.items(), True, self.styleNum != wx_stc.STC_STYLE_DEFAULT) # override with current settings self.populateProp(self.values.items(), False) def getCommonDefPropType(self, commonDefName): val = self.commonDefs[commonDefName] if type(val) == type(0): return 'size' if len(val) == 7 and val[0] == '#': return 'fore' return 'face' def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth): wx.EVT_COMBOBOX(combo, combo.GetId(), comboEvtMeth) wx.EVT_BUTTON(btn, btn.GetId(), btnEvtMeth) wx.EVT_RIGHT_DCLICK(combo, rdclickEvtMeth) combo.SetToolTipString('Select from list or click "ok" button on the right to change a manual entry, right double-click \n'\ 'the drop down button to select Common definition in the Style Editor (if applicable)') btn.SetToolTipString('Accept value') def populateCombosWithCommonDefs(self, fixedWidthOnly=None): self._blockUpdate = True try: commonDefs = {'fore': [], 'face': [], 'size': []} if self.elementLb.GetSelection() < self.commonDefsStartIdx: for common in self.commonDefs.keys(): prop = self.getCommonDefPropType(common) commonDefs[prop].append('%%(%s)%s'%(common, prop=='size' and 'd' or 's')) # Colours currFg, currBg = self.fgColCb.GetValue(), self.bgColCb.GetValue() self.fgColCb.Clear(); self.bgColCb.Clear() for colCommonDef in commonDefs['fore']: self.fgColCb.Append(colCommonDef) self.bgColCb.Append(colCommonDef) self.fgColCb.SetValue(currFg); self.bgColCb.SetValue(currBg) # Font if fixedWidthOnly is None: fixedWidthOnly = self.fixedWidthChk.GetValue() fontEnum = wx.FontEnumerator() fontEnum.EnumerateFacenames(fixedWidthOnly=fixedWidthOnly) fontNameList = fontEnum.GetFacenames() currFace = self.faceCb.GetValue() self.faceCb.Clear() for colCommonDef in ['']+fontNameList+commonDefs['face']: self.faceCb.Append(colCommonDef) self.faceCb.SetValue(currFace) # Size (XXX add std font sizes) currSize = self.sizeCb.GetValue() self.sizeCb.Clear() for colCommonDef in commonDefs['size']: self.sizeCb.Append(colCommonDef) self.sizeCb.SetValue(currSize) finally: self._blockUpdate = False def populateStyleSelector(self): numStyles = self.styleIdNames.items() numStyles.sort() self.styleNumLookup = {} stdStart = -1 stdOffset = 0 extrOffset = 0 # add styles for num, name in numStyles: if num == wx_stc.STC_STYLE_DEFAULT: self.elementLb.InsertItems([name, '----Language----'], 0) self.elementLb.Append('----Standard----') stdStart = stdPos = self.elementLb.GetCount() else: # std styles if num >= 33 and num < 40: self.elementLb.InsertItems([name], stdStart + stdOffset) stdOffset = stdOffset + 1 # extra styles elif num >= 40: self.elementLb.InsertItems([name], stdStart + extrOffset -1) extrOffset = extrOffset + 1 # normal lang styles else: self.elementLb.Append(name) self.styleNumLookup[name] = num # add settings self.elementLb.Append('----Settings----') settings = settingsIdNames.items() settings.sort();settings.reverse() for num, name in settings: self.elementLb.Append(name) self.styleNumLookup[name] = num # add definitions self.elementLb.Append('----Common----') self.commonDefsStartIdx = self.elementLb.GetCount() for common in self.commonDefs.keys(): tpe = type(self.commonDefs[common]) self.elementLb.Append('%('+common+')'+(tpe is type('') and 's' or 'd')) self.styleNumLookup[common] = num #---Colour methods-------------------------------------------------------------- def getColourDlg(self, colour, title=''): data = wx.ColourData() data.SetColour(colour) data.SetChooseFull(True) dlg = wx.ColourDialog(self, data) try: dlg.SetTitle(title) if dlg.ShowModal() == wx.ID_OK: data = dlg.GetColourData() return data.GetColour() finally: dlg.Destroy() return None colDlgTitles = {'fore': 'Foreground', 'back': 'Background'} def editColProp(self, colBtn, colCb, prop): col = self.getColourDlg(colBtn.GetBackgroundColour(), self.colDlgTitles[prop]+ ' colour') if col: colBtn.SetForegroundColour(wx.Colour(0, 0, 0)) colBtn.SetBackgroundColour(col) colStr = colToStr(col) colCb.SetValue(colStr) self.editProp(True, prop, colStr) def OnFgcolbtnButton(self, event): self.editColProp(self.fgColBtn, self.fgColCb, 'fore') def OnBgcolbtnButton(self, event): self.editColProp(self.bgColBtn, self.bgColCb, 'back') def editColTCProp(self, colCb, colBtn, prop, val=None): if val is None: colStr = colCb.GetValue() else: colStr = val if colStr: col = strToCol(colStr%self.commonDefs) if self.editProp(colStr!='', prop, colStr): if colStr: colBtn.SetForegroundColour(wx.Colour(0, 0, 0)) colBtn.SetBackgroundColour(col) else: colBtn.SetForegroundColour(wx.Colour(255, 255, 255)) colBtn.SetBackgroundColour(\ wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)) def OnfgColRet(self, event): try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore') except AssertionError: wx.LogError('Not a valid colour value') def OnfgColCombobox(self, event): if self._blockUpdate: return try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore', event.GetString()) except AssertionError: wx.LogError('Not a valid colour value') def OnbgColRet(self, event): try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back') except AssertionError: wx.LogError('Not a valid colour value') def OnbgColCombobox(self, event): if self._blockUpdate: return try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back', event.GetString()) except AssertionError: wx.LogError('Not a valid colour value') #---Text attribute events------------------------------------------------------- def OnTaeoffilledcbCheckbox(self, event): self.editProp(event.IsChecked(), 'eolfilled') def OnTaitaliccbCheckbox(self, event): self.editProp(event.IsChecked(), 'italic') def OnTaboldcbCheckbox(self, event): self.editProp(event.IsChecked(), 'bold') def OnTaunderlinedcbCheckbox(self, event): self.editProp(event.IsChecked(), 'underline') def OnGotoCommonDef(self, event): val = event.GetEventObject().GetValue() if self.valIsCommonDef(val): idx = self.elementLb.FindString(val) if idx != -1: self.elementLb.SetSelection(idx, True) self.OnElementlbListbox(None) def OnfaceRet(self, event): self.setFace(self.faceCb.GetValue()) def OnfaceCombobox(self, event): if self._blockUpdate: return self.setFace(event.GetString()) def setFace(self, val): try: val%self.commonDefs except KeyError: wx.LogError('Invalid common definition') else: self.editProp(val!='', 'face', val) def OnsizeRet(self, event): self.setSize(self.sizeCb.GetValue()) def OnsizeCombobox(self, event): if self._blockUpdate: return self.setSize(event.GetString()) def setSize(self, val): try: int(val%self.commonDefs) except ValueError: wx.LogError('Not a valid integer size value') except KeyError: wx.LogError('Invalid common definition') else: self.editProp(val!='', 'size', val) #---Main GUI events------------------------------------------------------------- def OnElementlbListbox(self, event): isCommon = self.elementLb.GetSelection() >= self.commonDefsStartIdx styleIdent = self.elementLb.GetStringSelection() # common definition selected if isCommon: common = styleIdent[2:-2] prop = self.getCommonDefPropType(common) self.clearCtrls(disableDefs=True) if prop == 'fore': self.fgColBtn.Enable(True) self.fgColCb.Enable(True) self.fgColOkBtn.Enable(True) elif prop == 'face': self.faceCb.Enable(True) self.fixedWidthChk.Enable(True) self.faceOkBtn.Enable(True) elif prop == 'size': self.sizeCb.Enable(True) self.sizeOkBtn.Enable(True) commonDefVal = str(self.commonDefs[common]) self.styleDefST.SetLabel(commonDefVal) self.populateProp( [(prop, commonDefVal)], True) self.styleNum = 'common' self.style = [common, prop, commonDefVal] self.names, self.values = [prop], {prop: commonDefVal} # normal style element selected elif len(styleIdent) >=2 and styleIdent[:2] != '--': self.styleNum = self.styleNumLookup[styleIdent] self.style = self.styleDict[self.styleNum] self.names, self.values = parseProp(self.style) if self.styleNum == wx_stc.STC_STYLE_DEFAULT: self.defNames, self.defValues = \ self.names, self.values self.checkBraces(self.styleNum) self.styleDefST.SetLabel(self.style) self.populateCtrls() # separator selected else: self.clearCtrls(disableDefs=True) if styleIdent: self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent]) self.populateCombosWithCommonDefs() def OnDefaultCheckBox(self, event): if self.chbIdMap.has_key(event.GetId()): ctrl, chb, prop, wid = self.chbIdMap[event.GetId()] restore = not event.IsChecked() if prop in ('fore', 'back'): cbtn, cmb, btn = ctrl cbtn.Enable(restore) cmb.Enable(restore) btn.Enable(restore) if restore: colStr = cmb.GetValue() #if prop == 'fore': colStr = self.fgColCb.GetValue() #else: colStr = self.bgColCb.GetValue() if colStr: self.editProp(True, prop, colStr) else: self.editProp(False, prop) elif prop == 'size': cmb, btn = ctrl val = cmb.GetValue() if val: self.editProp(restore, prop, val) cmb.Enable(restore) btn.Enable(restore) elif prop == 'face': cmb, btn, chk = ctrl val = cmb.GetStringSelection() if val: self.editProp(restore, prop, val) cmb.Enable(restore) btn.Enable(restore) chk.Enable(restore) elif prop in ('bold', 'italic', 'underline', 'eolfilled'): ctrl.Enable(restore) if ctrl.GetValue(): self.editProp(restore, prop) def OnOkbtnButton(self, event): # write styles and common defs to the config wx.BeginBusyCursor() try: writeStylesToConfig(self.config, customStyle, self.styles) if self.STC is not None: setSTCStyles(self.STC, self.styles, self.styleIdNames, self.commonDefs, self.keywords) finally: wx.EndBusyCursor() self.EndModal(wx.ID_OK) if wx.Platform == '__WXMAC__': dlg = wx.MessageDialog(self, 'Please restart SPE.', 'Styles reconfigured...', wx.OK | wx.ICON_INFORMATION ) dlg.ShowModal() dlg.Destroy() return wx.ID_OK def OnCancelbtnButton(self, event): self.EndModal(wx.ID_CANCEL) def OnCommondefsbtnButton(self, event): dlg = wx.TextEntryDialog(self, 'Edit common definitions dictionary', 'Common definitions', pprint.pformat(self.commonDefs), style=wx.TE_MULTILINE | wx.OK | wx.CANCEL | wx.CENTRE) try: if dlg.ShowModal() == wx.ID_OK: answer = eval(dlg.GetValue()) assert type(answer) is type({}), 'Not a valid dictionary' oldDefs = self.commonDefs self.commonDefs = answer try: self.setStyles() except KeyError, badkey: wx.LogError(str(badkey)+' not defined but required, \n'\ 'reverting to previous common definition') self.commonDefs = oldDefs self.setStyles() self.populateCombosWithCommonDefs() finally: dlg.Destroy() def OnSpeedsettingchChoice(self, event): group = event.GetString() if group: if self.currSpeedSetting == customStyle: self.predefStyleGroups[customStyle] = self.styles self.styles = self.predefStyleGroups[group] self.setStyles() self.defNames, self.defValues = parseProp(\ self.styleDict.get(wx_stc.STC_STYLE_DEFAULT, '')) self.OnElementlbListbox(None) self.currSpeedSetting = group def OnFixedwidthchkCheckbox(self, event): self.populateCombosWithCommonDefs(event.Checked()) #---STC events------------------------------------------------------------------ def OnUpdateUI(self, event): styleBefore = self.stc.GetStyleAt(self.stc.GetCurrentPos()) if self.styleIdNames.has_key(styleBefore): self.elementLb.SetStringSelection(self.styleIdNames[styleBefore], True) else: self.elementLb.SetSelection(0, False) self.styleDefST.SetLabel('Style %d not defined, sorry.'%styleBefore) self.OnElementlbListbox(None) event.Skip() def checkBraces(self, style): if style == wx_stc.STC_STYLE_BRACELIGHT and self.braceInfo.has_key('good'): line, col = self.braceInfo['good'] pos = self.stc.PositionFromLine(line-1) + col braceOpposite = self.stc.BraceMatch(pos) if braceOpposite != -1: self.stc.BraceHighlight(pos, braceOpposite) elif style == wx_stc.STC_STYLE_BRACEBAD and self.braceInfo.has_key('bad'): line, col = self.braceInfo['bad'] pos = self.stc.PositionFromLine(line-1) + col self.stc.BraceBadLight(pos) else: self.stc.BraceBadLight(-1) return def OnStcstyleeditdlgSize(self, event): self.Layout() # Without this refresh, resizing leaves artifacts self.Refresh(1) event.Skip() def OnMarginClick(self, event): self.elementLb.SetStringSelection('Line numbers', True) self.OnElementlbListbox(None) self.result = ( '', '' ) self.EndModal(wx.ID_CANCEL) #---Functions useful outside of the editor---------------------------------- def setSelectionColour(stc, style): names, values = parseProp(style) if 'fore' in names: stc.SetSelForeground(True, strToCol(values['fore'])) if 'back' in names: stc.SetSelBackground(True, strToCol(values['back'])) def setCursorColour(stc, style): names, values = parseProp(style) if 'fore' in names: stc.SetCaretForeground(strToCol(values['fore'])) def setEdgeColour(stc, style): names, values = parseProp(style) if 'fore' in names: stc.SetEdgeColour(strToCol(values['fore'])) def strToCol(strCol): assert len(strCol) == 7 and strCol[0] == '#', 'Not a valid colour string' return wx.Colour(string.atoi('0x'+strCol[1:3], 16), string.atoi('0x'+strCol[3:5], 16), string.atoi('0x'+strCol[5:7], 16)) def colToStr(col): return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2), string.zfill(string.upper(hex(col.Green())[2:]), 2), string.zfill(string.upper(hex(col.Blue())[2:]), 2)) def writeProp(num, style): if num >= 0: return 'style.%s='%(string.zfill(`num`, 3)) + style else: return 'setting.%d='%(num) + style def writePropVal(names, values): res = [] for name in names: if name: res.append(values[name] and name+':'+values[name] or name) return string.join(res, ',') def parseProp(prop): items = string.split(prop, ',') names = [] values = {} for item in items: nameVal = string.split(item, ':') names.append(string.strip(nameVal[0])) if len(nameVal) == 1: values[nameVal[0]] = '' else: values[nameVal[0]] = string.strip(nameVal[1]) return names, values def parsePropLine(prop): name, value = string.split(prop, '=') return int(string.split(name, '.')[-1]), value def setSTCStyles(stc, styles, styleIdNames, commonDefs, keywords): #wx.LogMessage('Set style') styleDict = {} styleNumIdxMap = {} # build style dict based on given styles for numStyle in styles: num, style = parsePropLine(numStyle) styleDict[num] = style # Add blank style entries for undefined styles newStyles = [] styleItems = styleIdNames.items() + settingsIdNames.items() styleItems.sort() idx = 0 for num, name in styleItems: styleNumIdxMap[num] = idx if not styleDict.has_key(num): styleDict[num] = '' newStyles.append(writeProp(num, styleDict[num])) idx = idx + 1 # Set background colour to reduce flashing effect on refresh or page switch bkCol = None if styleDict.has_key(0): prop = styleDict[0] else: prop = styleDict[wx_stc.STC_STYLE_DEFAULT] names, vals = parseProp(prop) if 'back' in names: bkCol = strToCol(vals['back']) if bkCol is None: bkCol = wx.WHITE stc.SetBackgroundColour(bkCol) # Set the styles on the wx.STC if wx.Platform != '__WXMAC__': stc.StyleResetDefault() stc.ClearDocumentStyle() stc.StyleSetSpec(wx_stc.STC_STYLE_DEFAULT, styleDict[wx_stc.STC_STYLE_DEFAULT] % commonDefs) stc.StyleClearAll() stc.SetLexer(wx_stc.STC_LEX_PYTHON) stc.SetKeyWords(0, keywords) for num, style in styleDict.items(): if num >= 0: stc.StyleSetSpec(num, styleDict[num] % commonDefs) elif num == -1: setSelectionColour(stc, style % commonDefs) elif num == -2: setCursorColour(stc, style % commonDefs) elif num == -3: setEdgeColour(stc, style % commonDefs) stc.Colourise(0, stc.GetTextLength()) return newStyles, styleDict, styleNumIdxMap #---Config reading and writing ------------------------------------------------- commonDefsFile = 'common.defs.%s'%(wx.Platform == '__wx.MSW__' and 'msw' or 'gtk') def getDefs(): if wx.Platform == '__WXMSW__': commonDefs = { 'helv': 'Courier New', 'mono': 'Courier New', 'lnsize': 10, 'backcol': '#FFFFFF', 'size': 10} elif wx.Platform =='__WXMAC__': commonDefs = { 'helv': 'Helvetica', 'mono': 'Courier', 'lnsize': 14, 'backcol': '#FFFFFF', 'size': 14} else: commonDefs = { 'helv': 'Helvetica', 'mono': 'Courier', 'lnsize': 10, 'backcol': '#FFFFFF', 'size': 10} commonStyleIdNames = { wx_stc.STC_STYLE_DEFAULT: 'Style default', wx_stc.STC_STYLE_LINENUMBER: 'Line numbers', wx_stc.STC_STYLE_BRACELIGHT: 'Matched braces', wx_stc.STC_STYLE_BRACEBAD: 'Unmatched brace', wx_stc.STC_STYLE_CONTROLCHAR: 'Control characters', wx_stc.STC_STYLE_INDENTGUIDE: 'Indent guide'} # Lang spesific settings styleIdNames = { wx_stc.STC_P_DEFAULT: 'Default', wx_stc.STC_P_COMMENTLINE: 'Comment', wx_stc.STC_P_NUMBER : 'Number', wx_stc.STC_P_STRING : 'String', wx_stc.STC_P_CHARACTER: 'Single quoted string', wx_stc.STC_P_WORD: 'Keyword', wx_stc.STC_P_TRIPLE:'Triple quotes', wx_stc.STC_P_TRIPLEDOUBLE: 'Triple double quotes', wx_stc.STC_P_CLASSNAME: 'Class definition', wx_stc.STC_P_DEFNAME: 'Function or method', wx_stc.STC_P_OPERATOR: 'Operators', wx_stc.STC_P_IDENTIFIER: 'Identifiers', wx_stc.STC_P_COMMENTBLOCK: 'Comment blocks', wx_stc.STC_P_STRINGEOL: 'EOL unclosed string'} styleIdNames.update(commonStyleIdNames) braceInfo = { 'good': (9, 12), 'bad': (10, 12)} displaySrc ="""## Comment Blocks! class MyClass(MyParent): \"\"\" Class example \"\"\" def __init__(self): ''' Triple quotes ''' # Do something silly ## Do something silly again a = ('Py' + "thon") * 100 b = 'EOL unclosed string c = [Matched braces] d = {Unmatched brace""" keywords = "and assert break class continue def del elif else except " + \ "exec finally for from global if import in is lambda not or pass print raise return try while" return (commonDefs, styleIdNames, displaySrc, keywords, braceInfo) def initFromConfig(cfg): (commonDefs, styleIdNames, displaySrc, keywords, braceInfo) = getDefs() # read in all group names for this language predefStyleGroupNames = [] for val in cfg.sections(): if len(val) >= 10 and val[:10] == 'stc.style.' and val != customStyle: predefStyleGroupNames.append(val) # read in current styles styles = readStylesFromConfig(cfg,customStyle) # read in predefined styles predefStyleGroups = {} for group in predefStyleGroupNames: predefStyleGroups[group] = readStylesFromConfig(cfg, group) return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames, predefStyleGroups, displaySrc, keywords, braceInfo) def readStylesFromConfig(config, group): styles = [] if config.has_section(group): for val in config.options(group): if val[:6] == 'style.' or val[:8] == 'setting.': styles.append(val + "=" + config.get(group, val, True)) return styles def writeStylesToConfig(config, group, styles): if config.has_section(group): config.remove_section(group) config.add_section(group) for style in styles: name, value = string.split(style, '=') config.set(group, name, string.strip(value)) #------------------------------------------------------------------------------- def initSTC(stc, config): """ Main module entry point. Initialise a wx.STC from given config file.""" (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames, predefStyleGroups, displaySrc, keywords, braceInfo) = initFromConfig(config) setSTCStyles(stc, styles, styleIdNames, commonDefs, keywords) def setStyle(stc, config, styleName): (commonDefs, styleIdNames, displaySrc, keywords, braceInfo) = getDefs() styles = readStylesFromConfig(config, styleName) setSTCStyles(stc, styles, styleIdNames, commonDefs, keywords) def SetStyles(stc, config): #try: styleSetting = config.get("Default","stcstyle") if styleSetting == "": return False setStyle(stc, config, "stc.style." + styleSetting) return True #except: #return False #------------------------------------------------------------------------------- if __name__ == '__main__': app = wx.PySimpleApp() provider = wx.SimpleHelpProvider() wx.HelpProvider_Set(provider) base = os.path.split(__file__)[0] configPath = os.path.abspath(os.path.join(base, 'defaults.cfg')) if 0: f = wx.Frame(None, -1, 'Test frame (double click for editor)') stc = wx.StyledTextCtrl(f, -1) def OnDblClick(evt, stc=stc): dlg = STCStyleEditDlg(None, 'Python', config, stc) try: dlg.ShowModal() finally: dlg.Destroy() stc.SetText(open('STCStyleEditor.py').read()) wx.EVT_LEFT_DCLICK(stc, OnDblClick) initSTC(stc, config) f.Show(True) app.MainLoop() else: config = ConfigParser.ConfigParser() config.read(configPath) dlg = STCStyleEditDlg(None, 'Python', config, None) try: dlg.ShowModal() finally: dlg.Destroy() spe-0.8.4.h/_spe/dialogs/runWinPdbDialog.py0000644000175000017500000000476110754716453017554 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Sat Dec 10 23:11:40 2005 import wx def _(x): return x class RunWinPdbDialog(wx.Dialog): def __init__(self, fileName, runPreviousArguments, runPreviousException, *args, **kwds): #todo: replace choices = [] with choices = runPreviousArguments # begin wxGlade: RunWinPdbDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.fileName = wx.StaticText(self, -1, _("File")) self.argumentsLabel = wx.StaticText(self, -1, _("Arguments")) self.arguments = wx.ComboBox(self, -1, choices=[], style=wx.CB_DROPDOWN) self.exception = wx.CheckBox(self, -1, _("Show dialog to launch debugger at unhandled exceptions")) self.label = wx.StaticText(self, -1, _("Only one script at the time can be run with Winpdb")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.ok = wx.Button(self, wx.ID_OK, _("Run")) self.__set_properties() self.__do_layout() # end wxGlade self.fileName.SetLabel("File name: "+fileName) self.exception.SetValue(runPreviousException) #self.exit.SetValue(runPreviousExit) def __set_properties(self): #todo: comment out self.arguments.SetSelection(-1) # begin wxGlade: RunWinPdbDialog.__set_properties self.SetTitle(_("Stani's Python Editor - Run with WinPdb")) self.label.Enable(False) self.ok.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: RunWinPdbDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_1.Add(self.fileName, 1, wx.ALL, 4) sizer_2.Add(self.argumentsLabel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_2.Add(self.arguments, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) sizer_1.Add(self.exception, 0, wx.ALL, 4) sizer_3.Add(self.label, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.cancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.ok, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_3, 1, wx.EXPAND, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade ## def onOk(self, event): # wxGlade: RunDialog. ## return wx.ID_OK # end of class RunWinPdbDialog spe-0.8.4.h/_spe/dialogs/blancoFrame.wxg0000644000175000017500000000430410272471120017063 0ustar stanistani frame_1 wxVERTICAL 0 4 4 wxEXPAND 0 wxHORIZONTAL 0 4 4 0 4 4 0 4 4 spe-0.8.4.h/_spe/dialogs/runDialog.wxg0000644000175000017500000001045710573602362016614 0ustar stanistani Stani's Python Editor - Run wxVERTICAL wxALL 4 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALL|wxALIGN_CENTER_VERTICAL 4 -1 wxALL 4 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 1 wxALL|wxALIGN_CENTER_VERTICAL 4 wx.ID_CANCEL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wx.ID_OK spe-0.8.4.h/_spe/dialogs/blancoDialog.wxg0000644000175000017500000000430510272471120017231 0ustar stanistani dialog_1 wxHORIZONTAL 0 4 4 wxEXPAND 0 wxVERTICAL 0 4 4 0 4 4 0 4 4 spe-0.8.4.h/_spe/dialogs/__init__.py0000644000175000017500000000035410272471120016235 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """This package contains various dialogs used by spe.""" __doc__=INFO['doc']%INFO spe-0.8.4.h/_spe/dialogs/runWinPdbDialog.wxg0000644000175000017500000001054510573602362017716 0ustar stanistani Stani's Python Editor - Run with WinPdb wxVERTICAL wxALL 4 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALL|wxALIGN_CENTER_VERTICAL 4 -1 wxALL 4 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 1 wxALL|wxALIGN_CENTER_VERTICAL 4 wx.ID_CANCEL wxALL|wxALIGN_CENTER_VERTICAL 4 1 wx.ID_OK spe-0.8.4.h/_spe/dialogs/separatorDialog.py0000644000175000017500000001102510363547345017631 0ustar stanistani#Boa:Dialog:wxDialog1 #(c)www.stani.be import _spe.info,sm INFO=_spe.info.copy() INFO['description']=\ """Dialog to insert a coloured separator for the class explorer in the sidebar.""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import wx import string def create(parent): return wxDialog1(parent) [wxID_WXDIALOG1, wxID_WXDIALOG1BUTTON1, wxID_WXDIALOG1BUTTON2, wxID_WXDIALOG1BUTTON3, wxID_WXDIALOG1BUTTON4, wxID_WXDIALOG1CHECKBOX1, wxID_WXDIALOG1TEXTCTRL1, ] = map(lambda _init_ctrls: wx.NewId(), range(7)) class wxDialog1(wx.Dialog): def _init_utils(self): # generated method, don't edit pass def _init_ctrls(self, prnt): # generated method, don't edit wx.Dialog.__init__(self, id=wxID_WXDIALOG1, name='', parent=prnt, pos=wx.Point(639, 463), size=wx.Size(360, 136), style=wx.DEFAULT_DIALOG_STYLE, title='Spe - Insert separator') self._init_utils() self.SetClientSize(wx.Size(352, 109)) self.textCtrl1 = wx.TextCtrl(id=wxID_WXDIALOG1TEXTCTRL1, name='label', parent=self, pos=wx.Point(8, 9), size=wx.Size(256, 21), style=0, value='Label') self.button1 = wx.Button(id=wxID_WXDIALOG1BUTTON1, label='Background', name='button1', parent=self, pos=wx.Point(272, 35), size=wx.Size(75, 23), style=0) wx.EVT_BUTTON(self.button1, wxID_WXDIALOG1BUTTON1, self.OnBackgroundChoose) self.button2 = wx.Button(id=wxID_WXDIALOG1BUTTON2, label='Foreground', name='button2', parent=self, pos=wx.Point(272, 8), size=wx.Size(75, 23), style=0) wx.EVT_BUTTON(self.button2, wxID_WXDIALOG1BUTTON2, self.OnForegroundChoose) self.button3 = wx.Button(id=wxID_WXDIALOG1BUTTON3, label='Insert', name='button3', parent=self, pos=wx.Point(192, 80), size=wx.Size(75, 23), style=0) wx.EVT_BUTTON(self.button3, wxID_WXDIALOG1BUTTON3, self.OnInsert) self.button4 = wx.Button(id=wxID_WXDIALOG1BUTTON4, label='Cancel', name='button4', parent=self, pos=wx.Point(272, 80), size=wx.Size(75, 23), style=0) wx.EVT_BUTTON(self.button4, wxID_WXDIALOG1BUTTON4, self.OnCancel) self.checkBox1 = wx.CheckBox(id=wxID_WXDIALOG1CHECKBOX1, label='Use background color', name='checkBox1', parent=self, pos=wx.Point(8, 40), size=wx.Size(256, 13), style=0) self.checkBox1.SetValue(0) wx.EVT_CHECKBOX(self.checkBox1, wxID_WXDIALOG1CHECKBOX1, self.OnBackgroundUse) def __init__(self, parent): self._init_ctrls(parent) self.foregroundColour=wx.Colour(0,0,0) self.backgroundColour=wx.Colour(255,255,255) self.button1.Disable() def OnCancel(self,event): self.Close() def OnBackgroundChoose(self, event): backgroundColour=self.selectColour(self.backgroundColour) if backgroundColour: self.backgroundColour=backgroundColour self.textCtrl1.SetBackgroundColour(self.backgroundColour) def OnForegroundChoose(self, event): foregroundColour=self.selectColour(self.foregroundColour) if foregroundColour: self.foregroundColour=foregroundColour self.textCtrl1.SetForegroundColour(self.foregroundColour) def selectColour(self,colour): dlg = wx.ColourDialog(self) dlg.GetColourData().SetChooseFull(1) dlg.GetColourData().SetColour(colour) if dlg.ShowModal() == wx.ID_OK: data = dlg.GetColourData().GetColour() else:return None dlg.Destroy() return data def OnBackgroundUse(self, event): checked=event.IsChecked() if checked:colour=self.backgroundColour else:colour=wx.Colour(255,255,255) self.textCtrl1.SetBackgroundColour(colour) self.button1.Enable(checked) def OnInsert(self, event): if not self.checkBox1.GetValue():self.backgroundColour=wx.Colour(255,255,255) label=self.textCtrl1.GetValue() separator='#---%s---%s%s%s'%(\ label, wxColour2html(self.foregroundColour), wxColour2html(self.backgroundColour), sm.zfill('-',(59-len(label))).replace('0','-')) self.GetParent().source.ReplaceSelection(separator) self.Close() def wxColour2html(c): return ('#%s%s%s'%tuple(map(lambda x:sm.zfill(hex(x)[2:],2),c.Get()))).upper() spe-0.8.4.h/_spe/dialogs/preferences.wxg0000644000175000017500000025220110755657026017175 0ustar stanistani Spe preferences wxHORIZONTAL 0 4 4 wxEXPAND 0 wxVERTICAL 0 4 4 wxEXPAND 0 General Editor Paths 4 10 0 1 4 wxLEFT|wxTOP 4 1 wxLEFT 4 wxLEFT 4 1 wxLEFT 4 1 wxLEFT 4 1 wxLEFT 4 wxEXPAND 0 4 3 1 2 4 wxLEFT|wxALIGN_CENTER_VERTICAL 4 1 wxEXPAND 0 0 <default> wxLEFT|wxALIGN_CENTER_VERTICAL 4 1 wxEXPAND 0 100 wxLEFT|wxALIGN_CENTER_VERTICAL 4 1 wxEXPAND 0 1000 wxLEFT|wxFIXED_MINSIZE 4 1 wxEXPAND|wxFIXED_MINSIZE 0 0 <default> ascii, 646, us-ascii (English) cp037, IBM037, IBM039 (English) cp424, EBCDIC-CP-HE, IBM424 (Hebrew) cp437, 437, IBM437 (English) cp500, EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 (Western Europe) cp737 (Greek) cp775, IBM775 (Baltic languages) cp850, 850, IBM850 (Western Europe) cp852, 852, IBM852 (Central and Eastern Europe) cp855, 855, IBM855 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian) cp856 (Hebrew) cp857, 857, IBM857 (Turkish) cp860, 860, IBM860 (Portuguese) cp861, 861, CP-IS, IBM861 (Icelandic) cp862, 862, IBM862 (Hebrew) cp863, 863, IBM863 (Canadian) cp864, IBM864 (Arabic) cp865, 865, IBM865 (Danish, Norwegian) cp869, 869, CP-GR, IBM869 (Greek) cp874 (Thai) cp875 (Greek) cp1006 (Urdu) cp1026, ibm1026 (Turkish) cp1140, ibm1140 (Western Europe) cp1250, windows-1250 (Central and Eastern Europe) cp1251, windows-1251 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian) cp1252, windows-1252 (Western Europe) cp1253, windows-1253 (Greek) cp1254, windows-1254 (Turkish) cp1255, windows-1255 (Hebrew) cp1256, windows1256 (Arabic) cp1257, windows-1257 (Baltic languages) cp1258, windows-1258 (Vietnamese) latin_1, iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 (West Europe) iso8859_2, iso-8859-2, latin2, L2 (Central and Eastern Europe) iso8859_3, iso-8859-3, latin3, L3 (Esperanto, Maltese) iso8859_4, iso-8859-4, latin4, L4 (Baltic languagues) iso8859_5, iso-8859-5, cyrillic (Bulgarian, Byelorussian, Macedonian, Russian, Serbian) iso8859_6, iso-8859-6, arabic (Arabic) iso8859_7, iso-8859-7, greek, greek8 (Greek) iso8859_8, iso-8859-8, hebrew (Hebrew) iso8859_9, iso-8859-9, latin5, L5 (Turkish) iso8859_10, iso-8859-10, latin6, L6 (Nordic languages) iso8859_13, iso-8859-13 (Baltic languages) iso8859_14, iso-8859-14, latin8, L8 (Celtic languages) iso8859_15, iso-8859-15 (Western Europe) koi8_r (Russian) koi8_u (Ukrainian) mac_cyrillic, maccyrillic (Bulgarian, Byelorussian, Macedonian, Russian, Serbian) mac_greek, macgreek (Greek) mac_iceland, maciceland (Icelandic) mac_latin2, maclatin2, maccentraleurope (Central and Eastern Europe) mac_roman, macroman (Western Europe) mac_turkish, macturkish (Turkish) utf_16, U16, utf16 (all languages) utf_16_be, UTF-16BE (all languages (BMP only)) utf_16_le, UTF-16LE (all languages (BMP only)) utf_7, U7 (all languages) utf_8, U8, UTF, utf8 (all languages) wxLEFT|wxALIGN_CENTER_VERTICAL 4 1 wxEXPAND 0 0 <default> Windows Macintosh wxEXPAND 0 wxHORIZONTAL wxEXPAND 0 4 4 1 4 0 1 0 1 0 1 0 1 0 4 4 wxEXPAND 0 4 4 2 4 0 1 0 1 0 5 5 0 1 0 5 5 0 1 0 5 5 0 4 3 1 2 4 wxEXPAND 0 wxVERTICAL 0 4 4 wxEXPAND 0 4 4 1 2 4 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 0 1 wxEXPAND 0 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 2 disable first paragraph only whole documentation wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 1 none compiler wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 0 realtime when clicked when manually refreshed (F5) wxTOP 4 1 wxTOP 4 1 wxTOP 4 1 wxEXPAND 0 wxVERTICAL wxEXPAND 0 4 4 1 4 0 4 4 0 0 0 1 0 wxEXPAND 0 wxHORIZONTAL wxALIGN_CENTER_VERTICAL 0 1 0 4 4 0 4 0 4 64 wxEXPAND 0 wxVERTICAL 0 4 4 0 1 0 4 4 0 1 0 4 4 wxEXPAND 0 wxHORIZONTAL wxALIGN_CENTER_VERTICAL 0 1 0 4 4 0 79 0 4 64 wxEXPAND 0 wxVERTICAL 0 1 wxEXPAND 0 $parent $id "Ignore" -1 -1, 150 wxVERTICAL wxEXPAND 0 wxVERTICAL wxEXPAND 0 0 1 1 3 0 wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxLEFT|wxRIGHT|wxTOP|wxEXPAND 5 -1 wxRIGHT|wxTOP 5 OnBrowseSignature wxEXPAND|wxALIGN_RIGHT 0 wxHORIZONTAL wxEXPAND 0 4 4 1 2 4 wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxTOP|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/bin/gnome-terminal --title SPE --working-directory="%(path)s" & /usr/bin/konsole --caption SPE --workdir "%(path)s" & cd "%(path)s"; /usr/bin/Eterm & cd "%(path)s"; /usr/X11R6/bin/xterm & cd "%(path)s"; /usr/bin/wterm & cd "%(path)s"; /usr/bin/aterm & cd "%(path)s"; /usr/bin/rxvt-xterm & cd "%(path)s"; /usr/bin/open -a Terminal cd "%(path)s"; /usr/bin/urxvt & wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxTOP|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/bin/gnome-terminal --title SPE --working-directory="%(path)s" -e '%(python)s "%(file)s" %(arguments)s' & /usr/bin/konsole --noclose --caption SPE --workdir "%(path)s" -e %(python)s "%(file)s" %(arguments)s & /usr/bin/Eterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/X11R6/bin/xterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/wterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/aterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/rxvt-xterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/urvxt -e 'cd "%(path)s"; %(python)s "%(file)s"' wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxTOP|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/bin/gnome-terminal --title SPE --working-directory="%(path)s" -e '%(python)s "%(file)s" %(arguments)s' & /usr/bin/konsole --caption SPE --workdir "%(path)s" -e %(python)s "%(file)s" %(arguments)s & /usr/bin/Eterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/X11R6/bin/xterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/wterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/aterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/rxvt-xterm -e 'cd "%(path)s"; %(python)s "%(file)s"' /usr/bin/urxvt -e 'cd "%(path)s"; %(python)s "%(file)s"' wxEXPAND|wxALIGN_RIGHT 0 wxHORIZONTAL wxEXPAND 0 4 4 1 2 4 wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/bin/firefox /usr/bin/mozilla -remote /usr/bin/mozilla /usr/bin/gnome-moz-remote /usr/bin/konqueror /usr/bin/mozilla-firebird /usr/bin/netscape /usr/bin/galeon /usr/bin/skipstone /usr/bin/xterm -e lynx /usr/local/bin/opera wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/share/doc/python-docs-2.2.3/html /usr/share/doc/python-docs/html /usr/share/doc/python-docs2.2/html wxLEFT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL 5 0 <default> /usr/share/doc/wxPython-2.4.2.4/docs /usr/share/doc/wxPython-docs 0 4 4 wxEXPAND 0 wxHORIZONTAL 0 1 wxRIGHT 4 wxRIGHT 4 1 0 0 4 4 0 4 4 spe-0.8.4.h/_spe/dialogs/runDialog.py0000644000175000017500000000454510754716453016450 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Sat Dec 10 23:11:40 2005 import wx def _(x): return x class RunDialog(wx.Dialog): def __init__(self, fileName, runPreviousArguments, runPreviousBeep, *args, **kwds): #todo: replace choices = [] with choices = runPreviousArguments # begin wxGlade: RunDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.fileName = wx.StaticText(self, -1, _("File")) self.argumentsLabel = wx.StaticText(self, -1, _("Arguments")) self.arguments = wx.ComboBox(self, -1, choices=[], style=wx.CB_DROPDOWN) self.beep = wx.CheckBox(self, -1, _("Beep after execution of script")) self.label = wx.StaticText(self, -1, _("Use Edit>Execute to run code snippets in shell")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.ok = wx.Button(self, wx.ID_OK, _("Run")) self.__set_properties() self.__do_layout() # end wxGlade self.fileName.SetLabel("File name: "+fileName) self.beep.SetValue(runPreviousBeep) def __set_properties(self): #todo: comment out self.arguments.SetSelection(-1) # begin wxGlade: RunDialog.__set_properties self.SetTitle(_("Stani's Python Editor - Run")) self.label.Enable(False) self.ok.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: RunDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_1.Add(self.fileName, 1, wx.ALL, 4) sizer_2.Add(self.argumentsLabel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_2.Add(self.arguments, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) sizer_1.Add(self.beep, 1, wx.ALL, 4) sizer_3.Add(self.label, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.cancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.ok, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_3, 1, wx.EXPAND, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade ## def onOk(self, event): # wxGlade: RunDialog. ## return wx.ID_OK # end of class RunDialog spe-0.8.4.h/_spe/dialogs/speDialog.py0000644000175000017500000000403510272471120016405 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """General spe dialog, showing the logo on top and displaying the text in a customized wxHtmlwindow, so that the links are opened in an external webbrowser.""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________ import os,webbrowser import wx import sm.wxp def create(parent,message,path): dlg= wxDialog1(parent,message,path) dlg.ShowModal() [wxID_WXDIALOG1] = map(lambda _init_ctrls: wx.NewId(), range(1)) class wxDialog1(wx.Dialog): def _init_utils(self): # generated method, don't edit pass def _init_ctrls(self, prnt): # generated method, don't edit wx.Dialog.__init__(self, id=wxID_WXDIALOG1, name='', parent=prnt, pos=wx.Point(25, 31), size=wx.Size(488, 588), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.MAXIMIZE_BOX, title='Spe') self._init_utils() self.SetClientSize(wx.Size(480, 554)) def __init__(self, parent,message,path=''): self._init_ctrls(parent) self.SetBackgroundColour(wx.Colour(0, 0, 0)) self.staticBitmap1 = wx.StaticBitmap( bitmap=wx.Bitmap(os.path.join(path,'images','spe_about.jpg'), wx.BITMAP_TYPE_JPEG), id=-1, name='staticBitmap1', parent=self, pos=wx.Point(0, 0), size=wx.Size(480, 100), style=0) self.text = sm.wxp.HtmlWindow(id=-1, name='text', parent=self, pos=wx.Point(0, 0), size=wx.Size(480, 339)) self.text.SetPage('%s'%message) self.init_sizers() def init_sizers(self): """Stretch the listbox.""" self.box1=wx.BoxSizer(wx.VERTICAL) self.box1.Add(self.staticBitmap1,0,0,0) self.box1.Add(self.text, 1, wx.ALL|wx.EXPAND, 0) self.SetAutoLayout(1) self.SetSizer(self.box1) spe-0.8.4.h/_spe/dialogs/runTerminalDialog.py0000644000175000017500000000557210754716453020145 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Sat Jan 21 01:25:28 2006 import wx def _(x): return x class RunTerminalDialog(wx.Dialog): def __init__(self, fileName, runPreviousArguments, runPreviousInspect, runPreviousExit, *args, **kwds): #todo: replace choices = [] with choices = runPreviousArguments # begin wxGlade: RunTerminalDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.fileName = wx.StaticText(self, -1, _("File")) self.argumentsLabel = wx.StaticText(self, -1, _("Arguments")) self.arguments = wx.ComboBox(self, -1, choices=[], style=wx.CB_DROPDOWN) self.inspect = wx.CheckBox(self, -1, _("Inspect interactively after running script")) self.exit = wx.CheckBox(self, -1, _("Exit terminal after running script")) self.label = wx.StaticText(self, -1, _("Use Edit>Execute to run code snippets in shell")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel")) self.ok = wx.Button(self, wx.ID_OK, _("Run")) self.__set_properties() self.__do_layout() # end wxGlade self.fileName.SetLabel("File name: "+fileName) self.inspect.SetValue(runPreviousInspect) self.exit.SetValue(runPreviousExit) def __set_properties(self): #todo: comment out self.arguments.SetSelection(-1) # begin wxGlade: RunTerminalDialog.__set_properties self.SetTitle(_("Stani's Python Editor - Run")) self.label.Enable(False) self.ok.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: RunTerminalDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_1.Add(self.fileName, 1, wx.ALL, 4) sizer_2.Add(self.argumentsLabel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_2.Add(self.arguments, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) sizer_1.Add(self.inspect, 0, wx.ALL, 4) sizer_1.Add(self.exit, 1, wx.ALL, 4) sizer_3.Add(self.label, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.cancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_3.Add(self.ok, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) sizer_1.Add(sizer_3, 1, wx.EXPAND, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade # end of class RunTerminalDialog class MyApp(wx.App): def OnInit(self): wx.InitAllImageHandlers() dialog = RunTerminalDialog(None, -1, "") self.SetTopWindow(dialog) dialog.Show() return 1 # end of class MyApp if __name__ == "__main__": import gettext gettext.install("app") # replace with the appropriate catalog name app = MyApp(0) app.MainLoop() spe-0.8.4.h/_spe/dialogs/helpDialog.py0000644000175000017500000000074310272471120016550 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Help dialog.""" __doc__=INFO['doc']%INFO import os def create(self,path,fileName,replacements=None): text=open(os.path.join(path,'doc',fileName)).read() if replacements: text=text % replacements if os.path.splitext(fileName)[1].lower()=='.txt':text=text.replace('\n','
') self.messageScrolled(text) spe-0.8.4.h/_spe/dialogs/preferencesDialog.py0000644000175000017500000006554310755657026020153 0ustar stanistani# generated by wxGlade 0.3.1 on Thu Oct 02 01:22:53 2003 """Preferences can be added in three steps: 1. Add the control with wxGlade (check todo afterwards!) 2. Append the name to the VALUES list 3. Add an entry in _spe/default.cfg""" import ConfigParser,os,types from wx.gizmos import EditableListBox import wx import sm.wxp.smdi as smdi VALUES = ['AutoComplete','AutoReloadChangedFile','Backup','CallTips', 'CheckFileOnSave','CheckSourceRealtime','ConvertTabsToSpaces', 'Encoding','ExecuteWarning','Mdi','EdgeColumn','PythonDocs', 'RecentFileAmount', 'RedirectShell','Redraw','Signature', 'SaveBeforeRun','Shortcuts','ShowShell','StripTrailingSpaces', 'TabWidth','Terminal','TerminalRun','TerminalRunExit', 'UpdateSidebar','UseTabs','ViewWhiteSpace','IndentationGuides', 'ViewEdge','WebBrowser','WordChars','WxPythonDocs','globalRecent', 'globalFolders','globalNotes','globalFileList','SaveOnExit', 'SingleInstanceApp','ToolTipsForFileTabs', 'CloseChildrenOnNewWorkspace','SaveWorkspaceOnFileSave', 'RememberLastWorkspace',]#'ShowToolbar','ViewLineNumbers' def _(x): return x class Create(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: Create.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.notebook_1 = wx.Notebook(self, -1, style=0) self.Paths = wx.Panel(self.notebook_1, -1) self.Editor = wx.Panel(self.notebook_1, -1) self.General = wx.Panel(self.notebook_1, -1) self.GeneralEditor_staticbox = wx.StaticBox(self.Editor, -1, _("General")) self.tabsWhiteSpaces_staticbox = wx.StaticBox(self.Editor, -1, _("Tabs && white spaces")) self.Guides_staticbox = wx.StaticBox(self.Editor, -1, _("Guides")) self.AutoCompletion_staticbox = wx.StaticBox(self.Editor, -1, _("Auto complete")) self.general_Label_staticbox = wx.StaticBox(self.Paths, -1, _("General")) self.terminal_Label_staticbox = wx.StaticBox(self.Paths, -1, _("Terminal Emulator")) self.html_Label_staticbox = wx.StaticBox(self.Paths, -1, _("Html")) self.sizer_3_staticbox = wx.StaticBox(self.General, -1, _("Workspaces")) self.Backup = wx.CheckBox(self.General, -1, _("Create backup files")) self.ToolTipsForFileTabs = wx.CheckBox(self.General, -1, _("Show tooltips on file tabs")) self.RedirectShell = wx.CheckBox(self.General, -1, _("Redirect output to spe shell")) self.CheckFileOnSave = wx.CheckBox(self.General, -1, _("Check file for syntax errors on save")) self.ShowShell = wx.CheckBox(self.General, -1, _("Show shell")) self.SingleInstanceApp = wx.CheckBox(self.General, -1, _("Run SPE as a single instance application (through a xml-rpc server)")) self.label_di = wx.StaticText(self.General, -1, _("Document Interface*")) self.Mdi = wx.ComboBox(self.General, -1, choices=[_("")], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.label_recent = wx.StaticText(self.General, -1, _("Amount of recent files")) self.RecentFileAmount = wx.TextCtrl(self.General, -1, _("100")) self.label_redraw = wx.StaticText(self.General, -1, _("Refresh interval [msec]")) self.Redraw = wx.TextCtrl(self.General, -1, _("1000")) self.label_encoding = wx.StaticText(self.General, -1, _("Encoding")) self.Encoding = wx.ComboBox(self.General, -1, choices=[_(""), _("ascii, 646, us-ascii (English)"), _("cp037, IBM037, IBM039 (English)"), _("cp424, EBCDIC-CP-HE, IBM424 (Hebrew)"), _("cp437, 437, IBM437 (English)"), _("cp500, EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 (Western Europe)"), _("cp737 (Greek)"), _("cp775, IBM775 (Baltic languages)"), _("cp850, 850, IBM850 (Western Europe)"), _("cp852, 852, IBM852 (Central and Eastern Europe)"), _("cp855, 855, IBM855 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)"), _("cp856 (Hebrew)"), _("cp857, 857, IBM857 (Turkish)"), _("cp860, 860, IBM860 (Portuguese)"), _("cp861, 861, CP-IS, IBM861 (Icelandic)"), _("cp862, 862, IBM862 (Hebrew)"), _("cp863, 863, IBM863 (Canadian)"), _("cp864, IBM864 (Arabic)"), _("cp865, 865, IBM865 (Danish, Norwegian)"), _("cp869, 869, CP-GR, IBM869 (Greek)"), _("cp874 (Thai)"), _("cp875 (Greek)"), _("cp1006 (Urdu)"), _("cp1026, ibm1026 (Turkish)"), _("cp1140, ibm1140 (Western Europe)"), _("cp1250, windows-1250 (Central and Eastern Europe)"), _("cp1251, windows-1251 (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)"), _("cp1252, windows-1252 (Western Europe)"), _("cp1253, windows-1253 (Greek)"), _("cp1254, windows-1254 (Turkish)"), _("cp1255, windows-1255 (Hebrew)"), _("cp1256, windows1256 (Arabic)"), _("cp1257, windows-1257 (Baltic languages)"), _("cp1258, windows-1258 (Vietnamese)"), _("latin_1, iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 (West Europe)"), _("iso8859_2, iso-8859-2, latin2, L2 (Central and Eastern Europe)"), _("iso8859_3, iso-8859-3, latin3, L3 (Esperanto, Maltese)"), _("iso8859_4, iso-8859-4, latin4, L4 (Baltic languagues)"), _("iso8859_5, iso-8859-5, cyrillic (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)"), _("iso8859_6, iso-8859-6, arabic (Arabic)"), _("iso8859_7, iso-8859-7, greek, greek8 (Greek)"), _("iso8859_8, iso-8859-8, hebrew (Hebrew)"), _("iso8859_9, iso-8859-9, latin5, L5 (Turkish)"), _("iso8859_10, iso-8859-10, latin6, L6 (Nordic languages)"), _("iso8859_13, iso-8859-13 (Baltic languages)"), _("iso8859_14, iso-8859-14, latin8, L8 (Celtic languages)"), _("iso8859_15, iso-8859-15 (Western Europe)"), _("koi8_r (Russian)"), _("koi8_u (Ukrainian)"), _("mac_cyrillic, maccyrillic (Bulgarian, Byelorussian, Macedonian, Russian, Serbian)"), _("mac_greek, macgreek (Greek)"), _("mac_iceland, maciceland (Icelandic)"), _("mac_latin2, maclatin2, maccentraleurope (Central and Eastern Europe)"), _("mac_roman, macroman (Western Europe)"), _("mac_turkish, macturkish (Turkish)"), _("utf_16, U16, utf16 (all languages)"), _("utf_16_be, UTF-16BE (all languages (BMP only))"), _("utf_16_le, UTF-16LE (all languages (BMP only))"), _("utf_7, U7 (all languages)"), _("utf_8, U8, UTF, utf8 (all languages)")], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.label_shortcuts = wx.StaticText(self.General, -1, _("Keyboard shortcuts*")) self.Shortcuts = wx.ComboBox(self.General, -1, choices=[_(""), _("Windows"), _("Macintosh")], style=wx.CB_DROPDOWN) self.SaveOnExit = wx.CheckBox(self.General, -1, _("Automatically Save Workspaces when exiting")) self.CloseChildrenOnNewWorkspace = wx.CheckBox(self.General, -1, _("Close all children when opening a new workspace")) self.SaveWorkspaceOnFileSave = wx.CheckBox(self.General, -1, _("Save Workspace when saving files")) self.RememberLastWorkspace = wx.CheckBox(self.General, -1, _("Remember Last Workspace")) self.label_globals = wx.StaticText(self.General, -1, _("Use the same in all workspaces:")) self.globalRecent = wx.CheckBox(self.General, -1, _("Recent Files")) self.globalFolders = wx.CheckBox(self.General, -1, _("Folders")) self.globalNotes = wx.CheckBox(self.General, -1, _("Notes")) self.globalFileList = wx.CheckBox(self.General, -1, _("Open File list")) self.label_font = wx.StaticText(self.Editor, -1, _("Fonts && Size")) self.chooseFont = wx.Button(self.Editor, -1, _("Configure ...")) self.label_wordchars = wx.StaticText(self.Editor, -1, _("Word characters")) self.WordChars = wx.TextCtrl(self.Editor, -1, "") self.label_calltips = wx.StaticText(self.Editor, -1, _("Calltips")) self.CallTips = wx.ComboBox(self.Editor, -1, choices=[_("disable"), _("first paragraph only"), _("whole documentation")], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.label_CheckSourceRealtime = wx.StaticText(self.Editor, -1, _("Check realtime with")) self.CheckSourceRealtime = wx.ComboBox(self.Editor, -1, choices=[_("none"), _("compiler")], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.label_sidebar = wx.StaticText(self.Editor, -1, _("Update sidebar")) self.UpdateSidebar = wx.ComboBox(self.Editor, -1, choices=[_("realtime"), _("when clicked"), _("when manually refreshed (F5)")], style=wx.CB_DROPDOWN|wx.CB_READONLY) self.AutoReloadChangedFile = wx.CheckBox(self.Editor, -1, _("Auto reload changed file")) self.SaveBeforeRun = wx.CheckBox(self.Editor, -1, _("Check if file is saved before code is executed in shell")) self.ExecuteWarning = wx.CheckBox(self.Editor, -1, _("Warn before executing whole file")) self.ViewWhiteSpace = wx.CheckBox(self.Editor, -1, _("Show whitespaces")) self.UseTabs = wx.CheckBox(self.Editor, -1, _("Use tabs")) self.ConvertTabsToSpaces = wx.CheckBox(self.Editor, -1, _("Convert tabs to spaces on open")) self.StripTrailingSpaces = wx.CheckBox(self.Editor, -1, _("Strip trailing spaces on save")) self.label_tabWidth = wx.StaticText(self.Editor, -1, _("Tab width")) self.TabWidth = wx.SpinCtrl(self.Editor, -1, "4", min=0, max=100) self.IndentationGuides = wx.CheckBox(self.Editor, -1, _("Show indentation guides")) self.ViewEdge = wx.CheckBox(self.Editor, -1, _("Show eol (end of line) guide")) self.label_edgeColumn = wx.StaticText(self.Editor, -1, _("Show eol guide at col")) self.EdgeColumn = wx.SpinCtrl(self.Editor, -1, "79", min=0, max=100) self.AutoComplete = wx.CheckBox(self.Editor, -1, _("Active")) self.AutoCompleteIgnore = EditableListBox(self.Editor, -1, "Ignore") self.signatureLabel = wx.StaticText(self.Paths, -1, _("Signature")) self.Signature = wx.ComboBox(self.Paths, -1, choices=[], style=wx.CB_DROPDOWN) self.browseSignature = wx.Button(self.Paths, -1, _("Browse")) self.label_terminal = wx.StaticText(self.Paths, -1, _("Open")) self.Terminal = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/bin/gnome-terminal --title SPE --working-directory=\"%(path)s\" &"), _("/usr/bin/konsole --caption SPE --workdir \"%(path)s\" &"), _("cd \"%(path)s\"; /usr/bin/Eterm &"), _("cd \"%(path)s\"; /usr/X11R6/bin/xterm &"), _("cd \"%(path)s\"; /usr/bin/wterm &"), _("cd \"%(path)s\"; /usr/bin/aterm &"), _("cd \"%(path)s\"; /usr/bin/rxvt-xterm &"), _("cd \"%(path)s\"; /usr/bin/open -a Terminal"), _("cd \"%(path)s\"; /usr/bin/urxvt &")], style=wx.CB_DROPDOWN) self.label_terminalRun = wx.StaticText(self.Paths, -1, _("Run")) self.TerminalRun = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/bin/gnome-terminal --title SPE --working-directory=\"%(path)s\" -e '%(python)s \"%(file)s\" %(arguments)s' &"), _("/usr/bin/konsole --noclose --caption SPE --workdir \"%(path)s\" -e %(python)s \"%(file)s\" %(arguments)s &"), _("/usr/bin/Eterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/X11R6/bin/xterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/wterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/aterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/rxvt-xterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/urvxt -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'")], style=wx.CB_DROPDOWN) self.label_terminalRunExit = wx.StaticText(self.Paths, -1, _("Run && Exit")) self.TerminalRunExit = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/bin/gnome-terminal --title SPE --working-directory=\"%(path)s\" -e '%(python)s \"%(file)s\" %(arguments)s' &"), _("/usr/bin/konsole --caption SPE --workdir \"%(path)s\" -e %(python)s \"%(file)s\" %(arguments)s &"), _("/usr/bin/Eterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/X11R6/bin/xterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/wterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/aterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/rxvt-xterm -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'"), _("/usr/bin/urxvt -e 'cd \"%(path)s\"; %(python)s \"%(file)s\"'")], style=wx.CB_DROPDOWN) self.label_webBrowser = wx.StaticText(self.Paths, -1, _("Webbrowser")) self.WebBrowser = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/bin/firefox"), _("/usr/bin/mozilla -remote"), _("/usr/bin/mozilla"), _("/usr/bin/gnome-moz-remote"), _("/usr/bin/konqueror"), _("/usr/bin/mozilla-firebird"), _("/usr/bin/netscape"), _("/usr/bin/galeon"), _("/usr/bin/skipstone"), _("/usr/bin/xterm -e lynx"), _("/usr/local/bin/opera")], style=wx.CB_DROPDOWN) self.label_pythonDocs = wx.StaticText(self.Paths, -1, _("Python docs")) self.PythonDocs = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/share/doc/python-docs-2.2.3/html"), _("/usr/share/doc/python-docs/html"), _("/usr/share/doc/python-docs2.2/html")], style=wx.CB_DROPDOWN) self.label_wxPythonDocs = wx.StaticText(self.Paths, -1, _("wxPython docs")) self.WxPythonDocs = wx.ComboBox(self.Paths, -1, choices=[_(""), _("/usr/share/doc/wxPython-2.4.2.4/docs"), _("/usr/share/doc/wxPython-docs")], style=wx.CB_DROPDOWN) self.label_warning = wx.StaticText(self, -1, _("Settings marked with * will only be updated next time SPE starts.")) self.defaults = wx.Button(self, -1, _("Defaults")) self.save = wx.Button(self, -1, _("Save")) self.Cancel = wx.Button(self, -1, _("Cancel")) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_BUTTON, self.OnBrowseSignature, self.browseSignature) # end wxGlade self.parent=args[0] self.update() wx.EVT_BUTTON(self.chooseFont, self.chooseFont.GetId(), self.OnChooseFontButton) wx.EVT_BUTTON(self.defaults, self.defaults.GetId(), self.OnDefaultsButton) wx.EVT_BUTTON(self.save, self.save.GetId(), self.OnSaveButton) wx.EVT_BUTTON(self.Cancel, self.Cancel.GetId(), self.OnCancelButton) self.customStyle = False def __set_properties(self): self.__fill() #todo: always after wxGlade update: #self.Signature.SetSelection(-1)!! # begin wxGlade: Create.__set_properties self.SetTitle(_("Spe preferences")) self.Backup.SetValue(1) self.RedirectShell.SetValue(1) self.CheckFileOnSave.SetValue(1) self.ShowShell.SetValue(1) self.Mdi.SetSelection(0) self.Encoding.SetSelection(0) self.Shortcuts.SetSelection(0) self.SaveOnExit.SetValue(1) self.CloseChildrenOnNewWorkspace.SetValue(1) self.SaveWorkspaceOnFileSave.SetValue(1) self.RememberLastWorkspace.SetValue(1) self.globalRecent.SetValue(1) self.globalFolders.SetValue(1) self.globalNotes.SetValue(1) self.CallTips.SetSelection(2) self.CheckSourceRealtime.SetSelection(1) self.UpdateSidebar.SetSelection(0) self.AutoReloadChangedFile.SetValue(1) self.SaveBeforeRun.SetValue(1) self.ExecuteWarning.SetValue(1) self.ConvertTabsToSpaces.SetValue(1) self.IndentationGuides.SetValue(1) self.ViewEdge.SetValue(1) self.AutoComplete.SetValue(1) self.AutoCompleteIgnore.SetMinSize((-1, 150)) self.Terminal.SetSelection(0) self.TerminalRun.SetSelection(0) self.TerminalRunExit.SetSelection(0) self.WebBrowser.SetSelection(0) self.PythonDocs.SetSelection(0) self.WxPythonDocs.SetSelection(0) self.save.SetDefault() # end wxGlade def __do_layout(self): # begin wxGlade: Create.__do_layout sizer_1 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.VERTICAL) bottom = wx.BoxSizer(wx.HORIZONTAL) paths_Sizer = wx.BoxSizer(wx.VERTICAL) html_Label = wx.StaticBoxSizer(self.html_Label_staticbox, wx.HORIZONTAL) html_Sizer = wx.FlexGridSizer(4, 2, 4, 4) terminal_Label = wx.StaticBoxSizer(self.terminal_Label_staticbox, wx.HORIZONTAL) terminal_Sizer = wx.FlexGridSizer(4, 2, 4, 4) general_Label = wx.StaticBoxSizer(self.general_Label_staticbox, wx.VERTICAL) general_Label_Sizer = wx.FlexGridSizer(1, 3, 0, 0) grid_sizer_1 = wx.FlexGridSizer(3, 2, 4, 4) AutoCompletion = wx.StaticBoxSizer(self.AutoCompletion_staticbox, wx.VERTICAL) Guides = wx.StaticBoxSizer(self.Guides_staticbox, wx.VERTICAL) eol = wx.BoxSizer(wx.HORIZONTAL) tabsWhiteSpaces = wx.StaticBoxSizer(self.tabsWhiteSpaces_staticbox, wx.VERTICAL) grid_sizer_2 = wx.FlexGridSizer(4, 1, 4, 4) width = wx.BoxSizer(wx.HORIZONTAL) GeneralEditor = wx.StaticBoxSizer(self.GeneralEditor_staticbox, wx.VERTICAL) grid_general = wx.FlexGridSizer(4, 2, 4, 4) generalSizer = wx.FlexGridSizer(10, 1, 4, 4) sizer_3 = wx.StaticBoxSizer(self.sizer_3_staticbox, wx.HORIZONTAL) grid_sizer_5 = wx.FlexGridSizer(4, 2, 4, 4) grid_sizer_3 = wx.FlexGridSizer(4, 1, 4, 4) grid_sizer_4 = wx.FlexGridSizer(3, 2, 4, 4) sizer_1.Add((4, 4), 0, 0, 0) sizer_2.Add((4, 4), 0, 0, 0) generalSizer.Add(self.Backup, 0, wx.LEFT|wx.TOP, 4) generalSizer.Add(self.ToolTipsForFileTabs, 0, wx.LEFT, 4) generalSizer.Add(self.RedirectShell, 0, wx.LEFT, 4) generalSizer.Add(self.CheckFileOnSave, 0, wx.LEFT, 4) generalSizer.Add(self.ShowShell, 0, wx.LEFT, 4) generalSizer.Add(self.SingleInstanceApp, 0, wx.LEFT, 4) grid_sizer_4.Add(self.label_di, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 4) grid_sizer_4.Add(self.Mdi, 0, wx.EXPAND, 0) grid_sizer_4.Add(self.label_recent, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 4) grid_sizer_4.Add(self.RecentFileAmount, 0, wx.EXPAND, 0) grid_sizer_4.Add(self.label_redraw, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 4) grid_sizer_4.Add(self.Redraw, 0, wx.EXPAND, 0) grid_sizer_4.Add(self.label_encoding, 0, wx.LEFT|wx.FIXED_MINSIZE, 4) grid_sizer_4.Add(self.Encoding, 0, wx.EXPAND|wx.FIXED_MINSIZE, 0) grid_sizer_4.Add(self.label_shortcuts, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 4) grid_sizer_4.Add(self.Shortcuts, 0, wx.EXPAND, 0) grid_sizer_4.AddGrowableCol(1) generalSizer.Add(grid_sizer_4, 1, wx.EXPAND, 0) grid_sizer_3.Add(self.SaveOnExit, 0, 0, 0) grid_sizer_3.Add(self.CloseChildrenOnNewWorkspace, 0, 0, 0) grid_sizer_3.Add(self.SaveWorkspaceOnFileSave, 0, 0, 0) grid_sizer_3.Add(self.RememberLastWorkspace, 0, 0, 0) sizer_3.Add(grid_sizer_3, 1, wx.EXPAND, 0) sizer_3.Add((4, 4), 0, 0, 0) grid_sizer_5.Add(self.label_globals, 0, 0, 0) grid_sizer_5.Add(self.globalRecent, 0, 0, 0) grid_sizer_5.Add((5, 5), 0, 0, 0) grid_sizer_5.Add(self.globalFolders, 0, 0, 0) grid_sizer_5.Add((5, 5), 0, 0, 0) grid_sizer_5.Add(self.globalNotes, 0, 0, 0) grid_sizer_5.Add((5, 5), 0, 0, 0) grid_sizer_5.Add(self.globalFileList, 0, 0, 0) sizer_3.Add(grid_sizer_5, 1, wx.EXPAND, 0) generalSizer.Add(sizer_3, 0, wx.EXPAND, 0) self.General.SetSizer(generalSizer) generalSizer.AddGrowableCol(0) GeneralEditor.Add((4, 4), 0, 0, 0) grid_general.Add(self.label_font, 0, wx.ALIGN_CENTER_VERTICAL, 0) grid_general.Add(self.chooseFont, 0, wx.EXPAND, 0) grid_general.Add(self.label_wordchars, 0, 0, 0) grid_general.Add(self.WordChars, 0, wx.EXPAND, 0) grid_general.Add(self.label_calltips, 0, wx.ALIGN_CENTER_VERTICAL, 0) grid_general.Add(self.CallTips, 0, wx.EXPAND, 0) grid_general.Add(self.label_CheckSourceRealtime, 0, wx.ALIGN_CENTER_VERTICAL, 0) grid_general.Add(self.CheckSourceRealtime, 0, wx.EXPAND, 0) grid_general.Add(self.label_sidebar, 0, wx.ALIGN_CENTER_VERTICAL, 0) grid_general.Add(self.UpdateSidebar, 0, wx.EXPAND, 0) grid_general.AddGrowableCol(1) GeneralEditor.Add(grid_general, 1, wx.EXPAND, 0) GeneralEditor.Add(self.AutoReloadChangedFile, 0, wx.TOP, 4) GeneralEditor.Add(self.SaveBeforeRun, 0, wx.TOP, 4) GeneralEditor.Add(self.ExecuteWarning, 0, wx.TOP, 4) grid_sizer_1.Add(GeneralEditor, 1, wx.EXPAND, 0) grid_sizer_2.Add((4, 4), 0, 0, 0) grid_sizer_2.Add(self.ViewWhiteSpace, 0, 0, 0) grid_sizer_2.Add(self.UseTabs, 0, 0, 0) grid_sizer_2.Add(self.ConvertTabsToSpaces, 3, 0, 0) grid_sizer_2.Add(self.StripTrailingSpaces, 0, 0, 0) width.Add(self.label_tabWidth, 0, wx.ALIGN_CENTER_VERTICAL, 0) width.Add((4, 4), 0, 0, 0) width.Add(self.TabWidth, 0, 0, 0) width.Add((64, 4), 0, 0, 0) grid_sizer_2.Add(width, 1, wx.EXPAND, 0) tabsWhiteSpaces.Add(grid_sizer_2, 1, wx.EXPAND, 0) grid_sizer_1.Add(tabsWhiteSpaces, 0, wx.EXPAND, 0) Guides.Add((4, 4), 0, 0, 0) Guides.Add(self.IndentationGuides, 0, 0, 0) Guides.Add((4, 4), 0, 0, 0) Guides.Add(self.ViewEdge, 0, 0, 0) Guides.Add((4, 4), 0, 0, 0) eol.Add(self.label_edgeColumn, 0, wx.ALIGN_CENTER_VERTICAL, 0) eol.Add((4, 4), 0, 0, 0) eol.Add(self.EdgeColumn, 0, 0, 0) eol.Add((64, 4), 0, 0, 0) Guides.Add(eol, 0, wx.EXPAND, 0) grid_sizer_1.Add(Guides, 1, wx.EXPAND, 0) AutoCompletion.Add(self.AutoComplete, 0, 0, 0) AutoCompletion.Add(self.AutoCompleteIgnore, 1, wx.EXPAND, 0) grid_sizer_1.Add(AutoCompletion, 1, wx.EXPAND, 0) self.Editor.SetSizer(grid_sizer_1) grid_sizer_1.AddGrowableCol(1) general_Label_Sizer.Add(self.signatureLabel, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) general_Label_Sizer.Add(self.Signature, 1, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, 5) general_Label_Sizer.Add(self.browseSignature, 0, wx.RIGHT|wx.TOP, 5) general_Label_Sizer.AddGrowableCol(1) general_Label.Add(general_Label_Sizer, 1, wx.EXPAND, 0) paths_Sizer.Add(general_Label, 0, wx.EXPAND, 0) terminal_Sizer.Add(self.label_terminal, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.Add(self.Terminal, 0, wx.RIGHT|wx.TOP|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.Add(self.label_terminalRun, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.Add(self.TerminalRun, 0, wx.RIGHT|wx.TOP|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.Add(self.label_terminalRunExit, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.Add(self.TerminalRunExit, 0, wx.RIGHT|wx.TOP|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) terminal_Sizer.AddGrowableCol(1) terminal_Label.Add(terminal_Sizer, 1, wx.EXPAND, 0) paths_Sizer.Add(terminal_Label, 1, wx.EXPAND|wx.ALIGN_RIGHT, 0) html_Sizer.Add(self.label_webBrowser, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.Add(self.WebBrowser, 0, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.Add(self.label_pythonDocs, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.Add(self.PythonDocs, 0, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.Add(self.label_wxPythonDocs, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.Add(self.WxPythonDocs, 0, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) html_Sizer.AddGrowableCol(1) html_Label.Add(html_Sizer, 1, wx.EXPAND, 0) paths_Sizer.Add(html_Label, 1, wx.EXPAND|wx.ALIGN_RIGHT, 0) self.Paths.SetSizer(paths_Sizer) self.notebook_1.AddPage(self.General, _("General")) self.notebook_1.AddPage(self.Editor, _("Editor")) self.notebook_1.AddPage(self.Paths, _("Paths")) sizer_2.Add(self.notebook_1, 1, wx.EXPAND, 0) sizer_2.Add((4, 4), 0, 0, 0) bottom.Add(self.label_warning, 1, 0, 0) bottom.Add(self.defaults, 0, wx.RIGHT, 4) bottom.Add(self.save, 0, wx.RIGHT, 4) bottom.Add(self.Cancel, 0, 0, 0) sizer_2.Add(bottom, 0, wx.EXPAND, 0) sizer_2.Add((4, 4), 0, 0, 0) sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) sizer_1.Add((4, 4), 0, 0, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) self.Layout() # end wxGlade def __fill(self): #mdi keys = smdi.DI.keys() keys.remove('') keys.sort() for key in keys: self.Mdi.Append(key) def update(self): for name in VALUES: self._update(name) self.AutoCompleteIgnore.SetStrings(self.parent.getValue('AutoCompleteIgnore')) def _update(self,name): """Update one automatically""" item=self.__dict__[name] if type(item.GetValue()) in [types.StringType,types.UnicodeType]: try: item.SetValue(self.parent.get(name)) except: print 'SPE.dialogs.preferencesDialog.py error: can not set value',self.parent.get(name) else: item.SetValue(self.parent.getValue(name)) def OnChooseFontButton(self, event): try: font, size = self.parent.get('Font').split(',') font = font.strip() size = eval(size.strip()) except: font = 'Courier' size = 10 data = wx.FontData() data.EnableEffects(False) data.SetInitialFont(wx.Font( pointSize = size, family = wx.FONTFAMILY_MODERN, style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL, face = font, )) dlg = wx.FontDialog(self, data) if dlg.ShowModal() == wx.ID_OK: data = dlg.GetFontData() font = data.GetChosenFont() self.parent.set('Font','%s, %s'%(font.GetFaceName(),font.GetPointSize())) dlg.Destroy() ## import stcStyleEditor ## dlg = stcStyleEditor.STCStyleEditDlg(self, 'Python', ## self.parent.config, None) ## try: ## if dlg.ShowModal() == wx.ID_OK: ## self.customStyle = True ## finally: ## dlg.Destroy() def OnDefaultsButton(self, event): self.Close() def OnSaveButton(self, event): #Editor for name in VALUES: self.set(name) self.set('AutoCompleteIgnore') if self.customStyle: self.parent.set("stcstyle", "Custom", 0) self.parent.preferencesSave() self.Close() def set(self,name,value=None): """Sets""" if value==None: if name=='AutoCompleteIgnore': value=str(self.__dict__[name].GetStrings()) else: value=str(self.__dict__[name].GetValue()) self.parent.set(name,value,save=0) def OnCancelButton(self, event): self.Close() def OnBrowseSignature(self, event): # wxGlade: Create. path=self.Signature.GetValue() defaultDir, defaultFile = os.path.split(path) dlg = wx.FileDialog(self,defaultDir = defaultDir, defaultFile = defaultFile, style = wx.OPEN|wx.DD_NEW_DIR_BUTTON) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.Signature.SetValue(path) dlg.Destroy() # end of class Create if __name__=='__main__': prefs=Create(None,-1,'haha') prefs.Show() spe-0.8.4.h/_spe/dialogs/styleEditor.wxg0000644000175000017500000001406110515765540017176 0ustar stanistani dialog_1 wxVERTICAL wxEXPAND 0 4 2 1 2 4 wxLEFT|wxTOP|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 1 wxTOP|wxADJUST_MINSIZE 4 1 8 default bold 0 wxLEFT|wxBOTTOM|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 1 wxRIGHT|wxBOTTOM|wxEXPAND|wxADJUST_MINSIZE 4 -1 wxEXPAND 0 wxHORIZONTAL wxEXPAND 0 wxVERTICAL wxEXPAND|wxADJUST_MINSIZE 0 0 wxEXPAND 0 wxVERTICAL wxEXPAND 0 wxHORIZONTAL wxEXPAND 0 wxHORIZONTAL spe-0.8.4.h/_spe/dialogs/winpdb.wxg0000644000175000017500000002145310576621430016151 0ustar stanistani wxVERTICAL wxALL 4 1 wxLEFT 4 1 wxALL 4 wxALL 4 SPE - Stani's Python Editor wxVERTICAL wxEXPAND 3 wxHORIZONTAL wxEXPAND 0 #ffffff wxHORIZONTAL wxBOTTOM|wxEXPAND|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL 4 1 blenpy.png #ffffff wxBOTTOM|wxEXPAND|wxALIGN_CENTER_VERTICAL 4 1 #ffffff wxEXPAND 0 4 1 1 2 4 wxALL|wxALIGN_CENTER_VERTICAL 4 1 wxALL|wxEXPAND 4 -1 wxEXPAND 0 $parent $id wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL 4 1 1 wxALL 4 1 wx.ID_OK onDebug wxALL 4 wx.ID_CANCEL onCancel wxALL 4 onHelp spe-0.8.4.h/_spe/dialogs/runWinPdbDialog_exit.wxg0000644000175000017500000001156310347351233020745 0ustar stanistani Stani's Python Editor - Run with WinPdb wxVERTICAL wxALL|wxADJUST_MINSIZE 4 1 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 1 wxALL|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 -1 wxALL|wxADJUST_MINSIZE 4 wxALL|wxADJUST_MINSIZE 4 wxEXPAND 0 wxHORIZONTAL wxALL|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 1 1 wxALL|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 wx.ID_CANCEL wxALL|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE 4 wx.ID_OK spe-0.8.4.h/_spe/dialogs/shortcuts.txt0000644000175000017500000001221710272471120016724 0ustar stanistaniHOME VCHOME Move caret to before first visible character on line. If already there move to first character on line CTRL+SPACE JUMP Jump from shell to file and line number UP+ARROW LINEUP Move caret up one line CTRL+DOWN ARROW LINESCROLLDOWN Scroll the document down, keeping the caret visible DOWN+ARROW LINEDOWN Move caret down one line SHIFT+UP ARROW LINEUPEXTEND Move caret up one line extending selection to new caret position CTRL+UP ARROW LINESCROLLUP Scroll the document up, keeping the caret visible CTRL+LEFT ARROW WORDLEFT Move caret left one word LEFT+ARROW CHARLEFT Move caret left one character ALT+LEFT ARROW WORDPARTLEFT Move to the previous change in capitalisation ALT+RIGHT ARROW WORDPARTRIGHT Move to the next change in capitalisation RIGHT+ARROW CHARRIGHT Move caret right one character SHIFT+HOME VCHOMEEXTEND Like VCHome but extending selection to new caret position CTRL+HOME DOCUMENTSTART Move caret to first position in document ALT+HOME HOMEDISPLAY Move caret to first position on display line CTRL+SHIFT+HOME DOCUMENTSTARTEXTEND Move caret to first position in document extending selection to new caret position SHIFT+DOWN ARROW LINEDOWNEXTEND Move caret down one line extending selection to new caret position SHIFT+LEFT ARROW CHARLEFTEXTEND Move caret left one character extending selection to new caret position CTRL+SHIFT LEFT ARROW WORDLEFTEXTEND Move caret left one word extending selection to new caret position SHIFT+RIGHT ARROW CHARRIGHTEXTEND Move caret right one character extending selection to new caret position CTRL+RIGHT ARROW WORDRIGHT Move caret right one word CTRL+SHIFT RIGHT ARROW WORDRIGHTEXTEND Move caret right one word extending selection to new caret position ALT+SHIFT LEFT ARROW WORDPARTLEFTEXTEND Move to the previous change in capitalisation extending selection to new caret position ALT+SHIFT RIGHT ARROW WORDPARTRIGHTEXTEND Move to the next change in capitalisation extending selection to new caret position. ALT+SHIFT+HOME HOMEDISPLAYEXTEND Move caret to first position on display line extending selection to new caret position. END LINEEND Move caret to last position on line SHIFT+END LINEENDEXTEND Move caret to last position on line extending selection to new caret position CTRL+END DOCUMENTEND Move caret to last position in document CTRL+SHIFT END DOCUMENTENDEXTEND Move caret to last position in document extending selection to new caret position ALT+END LINEENDDISPLAY Move caret to last position on display line ALT+SHIFT END LINEENDDISPLAYEXTEND Move caret to last position on display line extending selection to new caret position PRIOR PAGEUP Move caret one page up SHIFT+PRIOR PAGEUPEXTEND Move caret one page up extending selection to new caret position NEXT PAGEDOWN Move caret one page down SHIFT+NEXT SCI_PAGEDOWNEXTEND Move caret one page down extending selection to new caret position DELETE CLEAR Delete all text in the document SHIFT+DELETE CUT Cut the selection to the clipboard CTRL+DELETE DELWORDRIGHT Delete the word to the right of the caret CTRL+SHIFT+DELETE DELLINERIGHT Delete forwards from the current position to the end of the line INSERT EDITTOGGLEOVERTYPE Switch from insert to overtype mode or the reverse SHIFT+INSERT PASTE Paste the contents of the clipboard into the document replacing the selection CTRL+INSERT COPY Copy the selection to the clipboard ESCAPE CANCEL Cancel any modes such as call tip or auto-completion list display BACKSPACE DELETEBACK Delete the selection or if no selection, the character before the caret SHIFT+BACKSPACE BACKTAB Dedent the selected lines CTRL+BACKSPACE DELWORDLEFT Delete the word to the left of the caret ALT+BACKSPACE UNDO Undo one action in the undo history CTRL+SHIFT BACK DELLINELEFT Delete back from the current position to the start of the line CTRL+'Z' UNDO Undo one action in the undo history CTRL+'Y' REDO Redoes the next action on the undo history CTRL+'X' CUT Cut the selection to the clipboard CTRL+'C' COPY Copy the selection to the clipboard CTRL+'V' PASTE Paste the contents of the clipboard into the document replacing the selection CTRL+'A' SELECTALL Select all the text in the document TAB TAB Indents multi-line selection, replaces with Tab otherwise RETURN NEWLINE Insert a new line, may use a CRLF, CR or LF depending on EOL mode SHIFT+RETURN NEWLINE Insert a new line, may use a CRLF, CR or LF depending on EOL mode CTRL+ADD ZOOMIN Magnify the displayed text by increasing the sizes by 1 point CTRL+SUBTRACT ZOOMOUT Make the displayed text smaller by decreasing the sizes by 1 point CTRL+DIVIDE SETZOOM Set the zoom level to 0. This returns the zoom to 'normal,' i.e., no zoom. CTRL+'L' LINECUT Cut the line containing the caret CTRL+SHIFT 'L' LINEDELETE Delete the line containing the caret CTRL+'T' LINETRANSPOSE Switch the current line with the previous CTRL+'U' LOWERCASE Transform the selection to lower case CTRL+SHIFT 'U' UPPERCASE Transform the selection to upper case spe-0.8.4.h/_spe/dialogs/winpdbDialog.py0000644000175000017500000001643210764106050017110 0ustar stanistani# -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Thu Oct 27 00:45:00 2005 """VERY IMPORTANT: PAY ATTENTION TO TODO'S AFTER UPDATING WITH WXGLADE.""" import wx import os,webbrowser import _spe.info as info def _(x): return x class Options(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: Options.__init__ kwds["style"] = wx.TAB_TRAVERSAL wx.Panel.__init__(self, *args, **kwds) self.gui = wx.CheckBox(self, -1, _("Graphical User Interface")) self.chdir = wx.CheckBox(self, -1, _("Change working directory to that of script")) self.encryption = wx.CheckBox(self, -1, _("Use encryption (requires Python Cryptography Toolkit)")) self.verbose = wx.CheckBox(self, -1, _("Verbose")) self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: Options.__set_properties self.gui.SetValue(1) self.chdir.SetValue(1) # end wxGlade def __do_layout(self): # begin wxGlade: Options.__do_layout sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.gui, 0, wx.ALL, 4) sizer.Add(self.chdir, 0, wx.LEFT, 4) sizer.Add(self.encryption, 0, wx.ALL, 4) sizer.Add(self.verbose, 0, wx.ALL, 4) self.SetSizer(sizer) sizer.Fit(self) # end wxGlade # end of class Options class Create(wx.Dialog): def __init__(self, name = '', *args, **kwds): # todo: VERY IMPORTANT: AFTER UPDATE WITH GLADE MAKE "choices=info['history']"!! self.name = name app = self.app = kwds["parent"].app if not hasattr(app,'debugInfo'): info = self.info = app.debugInfo = {} info['arguments'] = '' info['history'] = [] info['gui'] = True info['chdir'] = True info['encryption'] = app.fCrypto info['verbose'] = app.DEBUG else: info = self.info = app.debugInfo # begin wxGlade: Create.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.panel_1 = wx.Panel(self, -1) self.logo = wx.StaticBitmap(self.panel_1, -1, wx.Bitmap("blenpy.png", wx.BITMAP_TYPE_ANY)) self.title = wx.StaticText(self.panel_1, -1, _("label_1")) self.argumentsLabel = wx.StaticText(self, -1, _("Arguments")) self.arguments = wx.ComboBox(self, -1, choices=info['history'], style=wx.CB_DROPDOWN) self.options = Options(self, -1) self.status = wx.StaticText(self, -1, _("WinPdb Debugger")) self.debug = wx.Button(self, wx.ID_OK, _("&Debug")) self.cancel = wx.Button(self, wx.ID_CANCEL, _("&Cancel")) self.help = wx.Button(self, -1, _("&Help")) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_BUTTON, self.onDebug, id=wx.ID_OK) self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL) self.Bind(wx.EVT_BUTTON, self.onHelp, self.help) # end wxGlade def __set_properties(self): # todo: VERY IMPORTANT: AFTER UPDATE WITH GLADE COMMENT OUT self.arguments.SetSelection(-1) # begin wxGlade: Create.__set_properties self.SetTitle(_("SPE - Stani's Python Editor")) self.logo.SetBackgroundColour(wx.Colour(255, 255, 255)) self.title.SetBackgroundColour(wx.Colour(255, 255, 255)) self.panel_1.SetBackgroundColour(wx.Colour(255, 255, 255)) self.status.Enable(False) self.debug.SetDefault() # end wxGlade self.debug.SetDefault() self.title.SetLabel(" Debug %s"%self.name) info = self.info options = self.options options.gui.SetValue(info['gui']) if os.path.exists(self.name): self.arguments.SetValue(info['arguments']) options.chdir.SetValue(info['chdir']) else: self.arguments.SetValue('') self.arguments.Disable() options.chdir.SetValue(False) options.chdir.Disable() options.encryption.SetValue(info['encryption']) options.verbose.SetValue(bool(info['verbose'])) options.encryption.Enable(self.app.fCrypto) def __do_layout(self): # begin wxGlade: Create.__do_layout sizer = wx.BoxSizer(wx.VERTICAL) buttons = wx.BoxSizer(wx.HORIZONTAL) grid_sizer = wx.FlexGridSizer(1, 2, 4, 4) sizer_1 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.HORIZONTAL) sizer_2.Add(self.logo, 0, wx.BOTTOM|wx.EXPAND|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 4) sizer_2.Add(self.title, 1, wx.BOTTOM|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 4) self.panel_1.SetSizer(sizer_2) sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0) sizer.Add(sizer_1, 1, wx.EXPAND, 3) grid_sizer.Add(self.argumentsLabel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) grid_sizer.Add(self.arguments, 0, wx.ALL|wx.EXPAND, 4) grid_sizer.AddGrowableCol(1) sizer.Add(grid_sizer, 0, wx.EXPAND, 0) sizer.Add(self.options, 1, wx.EXPAND, 0) buttons.Add(self.status, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4) buttons.Add(self.debug, 0, wx.ALL, 4) buttons.Add(self.cancel, 0, wx.ALL, 4) buttons.Add(self.help, 0, wx.ALL, 4) sizer.Add(buttons, 0, wx.EXPAND, 0) self.SetSizer(sizer) sizer.Fit(self) self.Layout() # end wxGlade def onDebug(self, event): # wxGlade: Create. try: from winpdb import __file__ as fileName except ImportError: from plugins.winpdb import __file__ as fileName path = os.path.dirname(fileName) _info = self.info arguments = _info['arguments'] = self.arguments.GetValue() if arguments: _info['history'].insert(0,arguments) parameters = _info['parameters'] = [] options = self.options gui = _info['gui'] = options.gui.GetValue() if gui: debugger= os.path.join(path,'winpdb.py') else: debugger= os.path.join(path,'rpdb2.py') if info.WIN and ' ' in debugger: debugger= '"%s"'%debugger parameters.append(debugger) chdir = _info['chdir'] = options.chdir.GetValue() if chdir: parameters.append('-c') encryption = _info['encryption'] = options.encryption.GetValue() if not encryption: parameters.append('-t') verbose = _info['verbose'] = options.verbose.GetValue() if verbose: parameters.append('--debug') self.EndModal(wx.ID_OK) def onCancel(self, event): # wxGlade: Create. self.EndModal(wx.ID_CANCEL) def onHelp(self, event): # wxGlade: Create. webbrowser.open('http://www.digitalpeers.com/pythondebugger/') event.Skip() # end of class Create def dialog(parent, name=''): return Create(parent=parent,id=-1,name=name) if __name__ == "__main__": app = wx.PySimpleApp(0) wx.InitAllImageHandlers() create = Create(None, -1, "") app.SetTopWindow(create) create.Show() app.MainLoop() spe-0.8.4.h/_spe/images/keyboard.png0000644000175000017500000000100510272471120016247 0ustar stanistaniPNG  IHDRasBIT|dIDATxR9kBA  B4Mm#6)ael6TNA}Q-LN13߇*sZ,+ \ ]4vχ{BvOj@DPT0L6`X,;ϱP(`"d2F&Z-lۘffsP/2 NN^#IxĎ Ws\;%n, 1j:Z>I!, :wjh4Yg.@>P(n)+Z~V,]^|T*A$naEd, _jBZ}᤿G &Q7)[ ŦjIENDB`spe-0.8.4.h/_spe/images/x-click-but20.gif0000644000175000017500000000154510272471120016725 0ustar stanistaniGIF89a>2WApNn!XDeʝpVv|h$Hs4f"6M!,> pdih,YXDtmx6PxpH,=P= g,f ,I"B&@k\ 3< w3 3z_C LC u1 uD L y{L5  Yc@ @XfC h?B 4$cxp '`48\Pp $\@4, T<(0cac7PA$a\&C`鄞?1á~( Qt ar@HA`A0PS]E196Ä- ܁h8M-Jό^8C<83Bs (j sRFK5l5Vpg0e`FÂ6j@p Pz2hrܦ~1W\)8 @[L;C@=MH EA$ dU T¥Q0v4֨C1c6}}"DDv@Y$G$OBydH.U4t`3h^n%cre7eA(SfsJa8Ibif%BR٦V6imƙh2 (1Tf馜v駠fꪬꫧrA{j뭸뮼k;spe-0.8.4.h/_spe/images/x-click-butcc-donate.gif0000644000175000017500000000202010272471120020326 0ustar stanistaniGIF89aI,M*a`bPh;㺷5ׇؘPҕ>@E郀N!,I,'dihUep,tm߸Xe%Pp:E8ШtJZB\s(ޱz >,sM;7\T  Q Rzqh}   P|OĀOw{sP׼ښ (lv2kzN8 †hx"=z J!7OL9 @]NF:)x]; (׶>It@ : ZP`Y"$eAJ"Fs~d b* pa4` *`Д˽Z6 ^j" L0PefH}ka6TAX*D (@08  (o*Nj^iniVt Oځzj(j뭧:jUꫯ֊*Ȃ,6kjW,;Z_` ^Aznbfѽ˯>``,]Y`' 7p¡I Ygw wEpă(,/!@ L`8p#W&4& D~# P EFSvA6UKu#%byqA^H}L?r}``S) L ,\ ߾c,7Y9dx4 ~p>qo%{Owci P IF&&Ff..?0&W(+21r 1K1< ~b`Hnqɹ/6.?~3+׷2x  `mԣ 3pcW ?gx{y947O>`ؽ  foF՛D}'nGsr$<7÷2ʸVqprdeajjjrҪX~1G B J >a )3k_í~W笊Bj VnawSCFH0p)q^qhfFVn߂囄Nf6?yxl.{VXd`Xھa zbN &"~ L_~|@9vQFnݸp~̟3|b,5C-܍Ϝ@jJ<3+"!!8HY!9_98rrqSVV^)%q f b' Wc\("?_!) N wf73ݝ\y͠!cΞ(.&ʁFBq08XRBz`)Z2l\x×B<ӷ \<n]s;XS \\45?˓ @qv?X^2p>Wb<ÑuW^%$$$ HDPBq<?~wo0]Ba͗C0ʼdQTJ限h7a&fVpŨ97o1H2 8~ʍ ^f?\Jo>lɂ_y>&Yr[x ʦ2Z0)p1h20t6,a(j`3g"}ao ;D־~ϐdA5'W/mw굫2'l-\z?;x@1N1`- k7}/_`ܸo%v*D_p{p3H 20<FX-e6f{K`1Ւw@L v>ưVnpa `IƗan?6ebWܜ nں x#kKc6`e|j 50s l7 ~O` +r1q0|fUbxϮMw v0L{T: W|{_ 33K>8,.ĂL3S|Q )E9I. !r,30, ]clă0TAiL:?~`Xr2h3yʐ~Cc W1hh0h)1p+ط/0D3pܿΠ.Cw`eAAoY̟T+)h V ͻOX{w`[3T?0 02||qȭA*cA`lg<|)#7 z*xP;9>v`1aXoDY1,]!z!@7o߃1ϽҒfef;X}ex:T#@{?n?La+ [7, 1A؁c~Ý 61 5N]}`j=[#R#II"»~zw֖dcc`P} IP,!89ypR2a.k`u8%N`&ASd W1B7~DE1uSc3tc^q3d5ϰw7Ynf>Ay`Yܘ1É, U2>Ih0|9" 8310ʩ1L?:0 ?` ߯o <} \a p~|-c .9J_kdK]Kd`ڥ(`Ϡ Q~VAx ?^ ?!A eЌ:{xMo qo+7 :^i2IX<pQ;* meb e>6X ,kjT12x&ً;|fs`P2`}^$@Rœ.6,FƚK8 ;;h! ^?g8d $}vy 1|z8Q`H~}O In2y$@p?yc\6x܌__TFKH C,@0X3|᷂ ++q35~|B.fex%yw^31H 0d x! K}z1BE F@46" 0A;$cW@O,U/ ձ u> G @faxῃg_ y>{61BBGA@\<_y+pw Tּ&G0|}:,1=KET?3 ˏ/ :,/3q1~W էexa@|a+/L1Rg&SpS`h ٸ2} þ &'k`Z@B# ~b`xx4tj^P_ELf(7ZS 1$ 3j! \yao t4B}c+Xw`(}%; 9 +ߩ />zf:;'M27k?‹c+ܼ& y,'#33#8D@OP^}` 2?cl~o.|%~c5o߾0 c!D1"5?\03~{UTnȸjM˻oX5>}0MY0 +0>.Mc0)0F@$g6']>oa pS Jf 6(킺Z '0+0fwV3x :S@߿}V?~&[_xgo?kp1r|/1toŰ|wh b1PjU}a \K*C K_Ai?3 9<ЉEP_XXX?#+++۟?X|Sbs`hrJ5 20mwcwؐ fޠ 80#'^~1 T΂44TwA08][G@1B- k: P ,$A1!;3y?t* uȡ[(~Ġsnn/i4tl j64X`zc%3HP3 TZI9`d-?¯ ǂ@ u-4tA!- H Vl(ML~G49RVOM :JRPGrB MgPتPȯP Pp`}t}.@1hmٲ必߾}o߾>>> _Ç`CVüy󦵴󿧧߿~ 555y`LOL!11 KKwp}p84L8)S8pzz^^XP38 @Cŋoݺg̘x 9e 0OҥK@.9x@,366Ԅc yyy== Realtime TreeCtrl Demo - SPE widget 1 400, 300 Right click on any item to display its line number in the statusbar. wxHORIZONTAL wxEXPAND 0 $parent $id wxEXPAND|wxADJUST_MINSIZE 0 class Dummy:\n def hello_world()\n def goodbye()\nclass Colors:\n def red()\n def blue() #ff877f spe-0.8.4.h/_spe/test/test_realtime_ListCtrl.wxg0000644000175000017500000000364110340415755020703 0ustar stanistani Realtime ListCtrl Demo - SPE widget 1 400, 300 Right click on any item to display its line number in the statusbar. wxHORIZONTAL wxEXPAND 0 $parent $id style=wx.LC_REPORT wxEXPAND|wxADJUST_MINSIZE 0 #todo:red\nblue #ff877f spe-0.8.4.h/_spe/test/test_realtime_ListCtrl.py0000755000175000017500000000625111002645341020521 0ustar stanistani#!/usr/bin/env python # -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Sun Nov 20 19:04:45 2005 import wx import sys from _spe.sm.wxp.realtime import ListCtrl #from wx import ListCtrl #to compare TAG = '#todo:' TAGLEN = len(TAG) class Frame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: Frame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.statusbar = self.CreateStatusBar(1, 0) self.listCtrl = ListCtrl(self, -1, style=wx.LC_REPORT) self.source = wx.TextCtrl(self, -1, "#todo:red\nblue", style=wx.TE_MULTILINE) self.__set_properties() self.__do_layout() # end wxGlade self.finish() def __set_properties(self): # begin wxGlade: Frame.__set_properties self.SetTitle("Realtime ListCtrl Demo - SPE widget") self.SetSize((400, 300)) self.statusbar.SetStatusWidths([-1]) # statusbar fields statusbar_fields = ["Right click on any item to display its line number in the statusbar."] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) self.source.SetBackgroundColour(wx.Colour(255, 135, 127)) # end wxGlade def __do_layout(self): # begin wxGlade: Frame.__do_layout sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.listCtrl, 1, wx.EXPAND, 0) sizer.Add(self.source, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) self.SetAutoLayout(True) self.SetSizer(sizer) self.Layout() # end wxGlade def finish(self): self.listCtrl.InsertColumn(0,'Line',wx.LIST_FORMAT_LEFT,40) self.listCtrl.InsertColumn(1,'!',wx.LIST_FORMAT_LEFT,20) self.listCtrl.InsertColumn(2,'Task',wx.LIST_FORMAT_LEFT,500) self.Bind(wx.EVT_IDLE,self.onIdle) def onIdle(self,event): source = [(line,index) for index, line in enumerate(self.source.GetValue().split('\n'))] source.sort() self.listCtrl.DeleteAllItems() for line, index in source: if line[:TAGLEN] == TAG: item = self.listCtrl.InsertStringItem(sys.maxint, str(index+1)) self.listCtrl.SetStringItem(item, 1, str(line.count('!'))) self.listCtrl.SetStringItem(item, 2, line[TAGLEN:]) if 'blue' in line: self.listCtrl.SetItemBackgroundColour(item,wx.BLUE) elif 'green' in line: self.listCtrl.SetItemBackgroundColour(item,wx.GREEN) elif 'red' in line: self.listCtrl.SetItemBackgroundColour(item,wx.RED) else: self.listCtrl.SetItemBackgroundColour(item,wx.WHITE) self.listCtrl.Update() # end of class Frame class App(wx.App): def OnInit(self): wx.InitAllImageHandlers() frame = Frame(None, -1, "") self.SetTopWindow(frame) frame.Show() return 1 # end of class App if __name__ == "__main__": app = App(0) app.MainLoop() spe-0.8.4.h/_spe/test/test_realtime_TreeCtrl.py0000755000175000017500000001122511002645341020502 0ustar stanistani#!/usr/bin/env python # -*- coding: ISO-8859-1 -*- # generated by wxGlade 0.4 on Sun Nov 20 15:23:13 2005 __author__ = 'www.stani.be' __license__ = 'GPL' __doc__ = """ Demo & test script for sm.wxp.realtime.TreeCtrl (SPE widget) This module was orignally developed for SPE - Stani's Python Editor Homepage: http://pythonide.stani.be Email: spe.stani.be@gmail.com Copyright: (c) 2005 www.stani.be License: GPL (contact me for other licenses) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import wx from _spe.sm.wxp.realtime import TreeCtrl #from wx import TreeCtrl #to compare class Frame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: Frame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.statusbar = self.CreateStatusBar(1, 0) self.treeCtrl = TreeCtrl(self, -1) self.source = wx.TextCtrl(self, -1, "class Dummy:\n def hello_world()\n def goodbye()\nclass Colors:\n def red()\n def blue()", style=wx.TE_MULTILINE) self.__set_properties() self.__do_layout() # end wxGlade self.finish() def __set_properties(self): # begin wxGlade: Frame.__set_properties self.SetTitle("Realtime TreeCtrl Demo - SPE widget") self.SetSize((400, 300)) self.statusbar.SetStatusWidths([-1]) # statusbar fields statusbar_fields = ["Right click on any item to display its line number in the statusbar."] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) self.source.SetBackgroundColour(wx.Colour(255, 135, 127)) # end wxGlade def __do_layout(self): # begin wxGlade: Frame.__do_layout sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.treeCtrl, 1, wx.EXPAND, 0) sizer.Add(self.source, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) self.SetAutoLayout(True) self.SetSizer(sizer) self.Layout() # end wxGlade def finish(self): self.root = self.treeCtrl.AddRoot('Root') #difference between wx.TreeCtrl and realtime.TreeCtrl if hasattr(self.root,'wx'): self.rootId = self.root.wx else: self.rootId = self.root self.Bind(wx.EVT_IDLE,self.onIdle) self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,self.onRightClick) def onIdle(self,event): source = self.source.GetValue().split('\n') #mark begin self.treeCtrl.CollapseAndReset(self.root) hierarchy = [(-1,self.root)] for index,line in enumerate(source): label = line.lstrip() #hierarchy based on left whitespace level = len(line)-len(label) for nodeIndex, node in enumerate(hierarchy): treeItemLevel, treeItem = node if treeItemLevelO1da`1H_OOm+}YG!V\_:yg)&r#U֑B5ҫ3Qvn ++t!pAꯤ "Օa&$nt m7B޷VX۬U"OtOJڭ\m]No'7U߾X0 -$]++e!Ԏ ][u)6Hh1RD%]hՕ؂ p"}|:?׷?U}lwq[N>T37Tr+&msh͟,l՛G7u(5$A#4(1:B̒x a'<5a'}}|:}(a'Wn[>ٻF"1pu~CQbܿd,nac^mP `eWF V3 B[.Lrx W-ڢyR DH"(DQeUꔥ}Ɵ/f]s ip.,؁\'Q?J_? -+Ra<%+RY2ĞHD]3hXcgԈM1'ʗ%tM u]ql%r|Y[K|53#;f J}7V*,C&պyw`\x/ _!OS\~%)G*:qRַ԰YmTi$z8/x &HUJħ# Feunaj<-wxbw&m+YeX$<qSǥyZrcH<)bB!wyٹT\m bJ)7ge[Ϲ%Y%XO0598\er0nƪ{Jo>GBl G!Zt:>x1¸Nd.#FbxvDu+P7ܙ6lܬv<0̢ف˾:gon_\N>:}_ߑuҀ>:VJQy[n S!O?zfUS-O"'dkVʂH:7AEr"ǒ%#{Ybq(eUYX,?o4x2A} EOq\xiʢfny{{TL*eEMoV8iU\eehջmUvu8P8'|_&ljAfdPg7W߿ebWUu(̵nsJ2F gf<Ŕ{ddł!8'TypB5( V8z~K_C{cT \j)J`'o]?x?~fJMnN Fч"u ^+Fg"T~}tJP}Qg"T~}tJP}QJe/+ƚHO\lP *,7,X|3yǪVpe( _VL?)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP R)@)JP RI @|_G1=qӷ$ڙcaqaڤ`l]|Ir32.HS J &RM"49OP_-bGv$^,Jd7u;ą#C\ycZkn,Ft\$f)]`sgg"ʨ*57W)>L^\cUEƖId7>Sj[vir1 .H?/`@:<*ٰ'}敉[D/!^aŃoǙA' cbӟ_n'I$k796\'Xy"[(ip7k.֞_Dv#m"y"Gn7O[YߧA.0aB[oa{k6գkcTJ_Yԇ#SQ585ȗ>]"m'P&@r{`AkuU{V ='s͒BϺ*FF$dR͘Š"̳-$NㅙXU 3.6V=E4j0 L`̅sIX1XklFDžybQ*_Y1|o)Yx2a{.z@M[o^^Orp'?b~K[kڪjJRU߉oh$4[r T2OXUΆݰɴIzXĦq*x}r8&.țt(Jx{-I]x+x۶O cpq4YT:QnoR64GTRdUzT()JɌS{ _ؿt&CC$z]Zb M& 79Z}.fG7g&4x#k$.M{rnStS$R/0ǰL=xׂ-zĜhg_Z#ῤh}qT1F$,LկjSFS*P_H&Gx|" vNjŏܘ ~ƽH:ˋG2h2B#N_-{g!Yu纷MY&KA~2O 9^>RD@g[Uiե #~3M$RDnhYdɂ4#tK{ArŁfjyl8tŽeb÷H%'3NH?}3(GiswrYYAEJĥ䑂"llh[\,ll*c>QUenXQ݋vb QP R)@)JP R)@)JP 1~}!CcPɘxjhѨ?+Yz* W @Q4ɑ3jfi$ncXJJRR)@)JP Rspe-0.8.4.h/_spe/skins/__init__.py0000644000175000017500000000000010272471120015726 0ustar stanistanispe-0.8.4.h/_spe/skins/default/0000755000175000017500000000000011004131464015251 5ustar stanistanispe-0.8.4.h/_spe/skins/default/throbber.gif0000644000175000017500000000147110346714615017567 0ustar stanistaniGIF89a333LLLfff! NETSCAPE2.0! ,HɉZgՆ}HIl ta ޭpe0 &|.Q^ڭ"'N! ,HBZ}HIl0tq<ޭp@ &|.BQ^ڭ"'N! ,HZ}HIlAt<ޭpP&|.Q^ڭ"'N! ,HƠZ'!}HIlTQtS<ޭp`&|.Q^ڭ"'N! ,HZg) }HIlat <ޭpp&|.Q^ڭ"'N! ,HJZ1}HIlqt0<ޭp&|.@Q^ڭ"'N! ,HZ9}HIltA<ޭp% &|.Q^ڭ"'N! ,HΡZ'}HIlTtSQ<ޭpE &|.Q^ڭ"'N;spe-0.8.4.h/_spe/skins/default/filesave.png0000644000175000017500000000207510347124612017567 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEJ LB--_E?^uK[f㎡HK{''R̫$$$PබׇLJМ̞Φ혩ʉLY5:dTk8dmgirtÜTW쯽؛>Kyհɋ[[n|k}먨ǁ4O{m^aL((Toybp7 .QǨ[n<⏡,-^;Ҷ[h㼼9dd9:mČOXmm!!Ds}ޖ'VGwtRNS)IDATxb؄0dZ$N $o֘*9iF3d r` F,7Yn 3(J"EiCPzb6MƍV5q@]p%]Z~@߄ "M h̦zg-[Y u7IbQFzI @<:sC,a|b1104-۴ s~vIENDB`spe-0.8.4.h/_spe/skins/default/help.png0000644000175000017500000000035510272471120016714 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEٟtRNS0J_IDATxb`DĀ.@!@0 3Ƈ`FF P-Āg ° 0T@ah 0|t3IENDB`spe-0.8.4.h/_spe/skins/default/warning.gif0000644000175000017500000000125410346714615017424 0ustar stanistaniGIF89a~ԡSĴS׍￴fI2{pǷuZЖ⴯fEnsnH@mf\Et-ՂĿ˂ZR3f`m1s-G3ta¿Q ٌ}NU TF͎y?uLe3+m&\1r`j3Fddn{nC fl@0Ip%v N&{(U촖jaraᗢ60N頻@N@Iu{r"qؗd?>9`0U.t3>=M飙쭖骙d j(9_%q>le ^! NETSCAPE2.0! ,~#+"Mo$_7Z/a IXH|0&& Q$O~F --{(*}Czc i\RPhUN*1T(A ەk5WuSpq"e.! , c)Y!v_Et %`,!mrɃ%xJVswn=)dΒϘ;spe-0.8.4.h/_spe/skins/default/run_debug.png0000644000175000017500000000207510346714615017752 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE{rqr)QlFhh|5 ;\W󁊡Rf$o?iZfY  L`_;DfSbeXJJWzS )p h`1|J76kjm zf #h] R$Ml>؇ 5 ipnN\Z#?qVo藄8hQt~6o`tx~) <!yY}CKPH j9@[nnãr'8tRNSEIDATx4coAsY۶m۶m۶m;?ooo'3WhR0)ps6q=')Ii"Xw٦ !s.FjIWc8M:Y%"FYE3irgt/MVR\l9z~_Z#BjuAx`䄢lЭRMZ>7ήrA7%7kW S` #N;y8Q賭dx0mЀIENDB`spe-0.8.4.h/_spe/skins/default/editcut.png0000644000175000017500000000213010272471120017416 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?ê gW&&=@JJl|>~ׯ_ " 6 VaӋC < <<\` ))2KVVӧo >|gqFy 6 O00neWHAp~ G)Z0 ̜ `ß ax͛ }f_~/*oAz @330 |׃  WV35Zx{ X# ۿo /3Vc`{kk@{-[|۳D2rB1_? >~{2)0Xp,X㑣$%6؀AQYZY3'w[? ĩ<})FX O_&Ar|zQFe'f-c<2ÿ/[k n/#[F\b%Mlϵd%ϰ!R?y  8cߍߘ?wŏ/g1f@݇c8Q 3\ > #''+0 >ð  a);6 ;pPً?/vgq_cxs,˾ϡ𯊍o\ l_OxŌ ,5<t7 ,߱13cg{/ߙd`6Zf&!6 Ą1|̡ 2v:1{aed^tIENDB`spe-0.8.4.h/_spe/skins/default/note.png0000644000175000017500000000173710272471120016736 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEzo\~yLmFjΦBeƋkl_|dɪd뗷^ugt^meﺻ凩\}r稩5P_}BW}Rt^fk^qNomPp̃{y䎰u{XywlUwpgwNWqeܓHiiWxYzM^\ex nnn{{|4׊ŽpQ]ׇ m{0 | 17p 888yU΅U[pfiߚtRNSfs)IDATxbkVBX SrTy6Xc$ОM6MݣBCz?@')Lh5 <%v}uPnYdN'pedF}ڐL~ް}nİl^D`ڪ)k- މ,>*CeGe!w|~b/3aw4uںd?@1HaI޷o,~M~}+\[ Z!,fv]`łtgIENDB`spe-0.8.4.h/_spe/skins/default/throbber_Layer 1.gif0000644000175000017500000000012110346714615021033 0ustar stanistaniGIF89a!,(Ȩ| *Pf]bi!Hu贐DZ~G};spe-0.8.4.h/_spe/skins/default/goto.png0000644000175000017500000000045210272471120016732 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe< PLTE@tRNS@*IDATxb`&& @ .H `@.#@ >X3@1)` # @ P!|fbghbbgX  r&=pB,6 ` @ Pi&fC*:EfbIENDB`spe-0.8.4.h/_spe/skins/default/comment.png0000644000175000017500000000072410346714615017441 0ustar stanistaniPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FJIDATxb?% X@zGMmP']@`0800ʀ Ze'2!8d3A!20lބ @ T"1]4In@ - iͫ[AacؼYn@ <ͦh$v #CT<#P abGCl,Yn@! j[,RhpbP hY>B`FFA8˗n RQqQQ60||pn@1R%I )L@! 0!~ܼIENDB`spe-0.8.4.h/_spe/skins/default/documentinfo.png0000644000175000017500000000123710332317741020463 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbdgϦO 4Ʌ,,Lv2b܌ `?3NL@>@1EĀ|!%Y_bdvxp(39 f&;!&fQ_bpnqqn77 _bu.^^. @  ~4 MaIENDB`spe-0.8.4.h/_spe/skins/default/browser.png0000644000175000017500000000166710272471120017456 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEأaaaTTTqpu}}}SRT}}|GGI`_h}||srtuttvvvjinkkk(((rp! "MLZJIIኊ@@@rrrDDJNMV~||HEQ`^eݱTTdVUi뢡͙~}][e`_m~~~`_krpputZYqՔpnr綴އ|{}\\gի{{{NNNcck`__igulkyXXXgfihѼxwۨǚyyyQtRNS^UkIDATxbAᥞ=Āgdf d>K7/@!+庙k{$'\ @ =ڂ)>Lq@YbI,6K6e ND:N@1630&d)iB#| C[$onO@1ًFֳCIs@dyak cO@1t(;Y9&Ts  u㌦. ՙф'Tp.ڕuF@f@Ћ-{,ߋ4qC3e1䥮xDR63M01Tۚ"wsڈe|T*ב'ꪑ룐PyG뫢Άo)oC9ʎW5҆sWvn9)囬cN^SnԖ[oI1\G_6"Q&d瞈gu1Ns@ې!l$لM؁9үSO$!|?&xkN0sp>n}MV( H}#맛ԇ*Qﵙ駍\)1}|V,N1weXHm˃rM童y+ɇN)k!:HtRNS> IDATxb;wdm0?= S1ŒA)Ğ @`Cvv/@`Ӵ 9s$`f3[O[AFt.@T5Z:{xanuvj~ULO nb0tkU&@ l!%q]mV5SX̝ @ L,էO @ sӧ&j$ L; vKg ;#& @`mw fD @kT+F3IENDB`spe-0.8.4.h/_spe/skins/default/editcopy.png0000644000175000017500000000141110272471120017576 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb}/>>nKK=;QQYp*߿^c ~e`x 00)me +ŕ? @5?a4 P ۷X!!Nׯ?0|6?~ xo&$  `VIIQ9..B0@ .. --4 X@l 0@1"_Nl`W߁~ ??`0?`z0b@y|XﺺNJʰ7,`q!#@9Y3f at2H߿62 A^ @(061+0m$sF7@ ٢,ˠNkdeeſ@X&8@ 'a` c8z<4]y v˗ blIENDB`spe-0.8.4.h/_spe/skins/default/view_top_bottom.png0000644000175000017500000000060410346714615021214 0ustar stanistaniPNG  IHDRagAMAܲ;IDATx=JCQ;/1EJB쭴B•+,t E0(1,hyx`.qfdiqs<]^OIPgӳ-*.qYUhbOSJ\][t:ED>^wx8+KeHmt'<;!55etd"AoFbCFa*QC5@'*ZOZk zwpehqzLR|>!LSghVai|9A$ꔛۻs @͌zib IENDB`spe-0.8.4.h/_spe/skins/default/encoding.png0000644000175000017500000000152410272471120017551 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% pm 6n_``!&e#!!q{иA,ù u4ߴi;v c@ DX>ʰGjfe 9s @1W5 HJ221 6ǏG@4@1@3Ӄ>|``x ߾}c8z/o޼w2:}zoڵk'_|A1 oݴi `׀ x!Э[l9b/6)PJԀwoJ}}  0*b`(rrcbZsqqy_HH?|||] @` 8'54~edLd SSSt0x@# Ë&tIENDB`spe-0.8.4.h/_spe/skins/default/forward.png0000644000175000017500000000074210272471120017430 0ustar stanistaniPNG  IHDRڭgAMA7tEXtSoftwareAdobe ImageReadyqe<~PLTEْٜ߹舭Zʧjڂzӳ򉧾2JhuᑲQ*tRNS2\IDATxbЄ Mu0 @ 0T P (0CD,!"# 8"3H Jjb@0)KjhH@@P ,l &@8Abyh0wt@D!P҄x W 1OTIENDB`spe-0.8.4.h/_spe/skins/default/pychecker.png0000644000175000017500000000122510346714615017751 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<'IDATxb?% (8Qc@7 @2@ĬHl(A!A X2lj okȧdP}گ? ?YB/oV qj $dIH6]'P"@10" H3]"rTW__WہÀꞀOS ; B׀&03$0Z11|88> F1  F " @aC/Gpr000r10 0`^1a8ph:P"A %^`` S @@14%$@ xjPM3 g 0f6Or n5]ex4ؿU |i X?=L ^5S(\ `N~` /, {b,HIflb47Ź QU!6IENDB`spe-0.8.4.h/_spe/skins/default/separator.png0000644000175000017500000000034210272471120017760 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE֍tRNS0JTIDATxb`DĀ.@!@!@!@ h 0T@a@a@aI<IENDB`spe-0.8.4.h/_spe/skins/default/undo.png0000644000175000017500000000126410272471120016731 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<FIDATxb?% (Ȑ $Uxy7䯏 _b߀D1 s1@!\🁃74G _my0 ĸ `RQwev4Č`$0t2g5;ߛo/ @A10ef f#'E1\/9^2<|w6Ob@ ?>b ?dw/ @M߀20 XOgtu~ 3  ~`h_1?2O fCG@cMwfePepy ;_a 'FF m 4h5'2@;3y1@ CP22b E#0430|džа >с&C@| L*.= +PAp@S4>@/aZ$@ ))2(k-Щ@O 70ZtL=Z`r FJs#@Q |ʽGBIENDB`spe-0.8.4.h/_spe/skins/default/uml.png0000644000175000017500000000117710346714615016577 0ustar stanistaniPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FIDATxb?% LJqڵ ... |WZ͛73L8l3@1$'% VV`ZYY LgggAi &= Î9 ܹ ?~0Ud/O\@, ƪUU%WI3MZ@ SBC!^,'-ʮ({  Ν;9y).x)C[O t#@BH ܽ ŋ߽{f߿j`@, ɆW탳\EcI)#7/̎fHH 02@1W ޺ӷP`xp \~ư0`TB Y0T66Vw0E 1@   !lIJФ R `fJf 6AWC62t/Tˏb4;&/sA3IENDB`spe-0.8.4.h/_spe/skins/default/fileopen.png0000644000175000017500000000207010272471120017561 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% XT1X0|/Ьc'^2Xd'_X8X}>v#uo}uh8?b߼_ q_9YQׯ v V_Yt?FEĢʛ/?  ??I d˗@'108:7@  &6V/L  ~`)_GRW[o?@C/ëtD,$0# 0@t oy0X(Á @/T~p)qn}fQUF  @~s2:O f/_ @sGt`e4{sßOXA?++fv1| r< : 21 A{! h4y؅N\g`xà wcxó><|{!#.c3d*Ѐ1ǯ ~gJ8l$.ƿs/by'*?P 3w0 70&_0>y;܀\4$8} 7`}H߿~,3#@U4733 D (yp{S3nv&`S_7d C0gdeamIENDB`spe-0.8.4.h/_spe/skins/default/notes.png0000644000175000017500000000151010272471120017106 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<_PLTEzzz{{{沲sss´]]]ibZ܇tIK+㱱hhh߇20ȮǙVUn~~~|tuutyU~b{c6o;x~Ǿ͂WWWbbbסljrrrƾڪ[ۮck̐0K:ϮҾoooץR@أK{QrNppp`\Saaayyyst^DutRNSIDATxb(A%Āg u( d5%B,bU, WIQiI @R]y t2ĠǪ"`ok  qpOL^bP O4 CIB,%sD|pnI @ -fre/ &iLVq"\vG1y5;3@AVYR@P8 @ȞCSZxKQIENDB`spe-0.8.4.h/_spe/skins/default/favicon.ico0000644000175000017500000000706610272471120017405 0ustar stanistanih& ( @LJt$?8hUi5J"u,-^D9_Sm:Or9? J(|V           ( @ @C1V0/tb=tPjZFaF'06{2:HC S#RBt0djTe:l Y2_DH$")2t?kd\%Tz/O+]O)g @Ket [KQ-_P1KV:;!9@[T3B=^9En_PD$5JpQGv.;4/Tqsg67qN~ 9W3h{ E"xb/l,2ZP#UƄh)2_E(%cY-Z1 Jmj7V4Ht,Zx )@l== V D@z3 9,@e&}It&QhRO# ~-+?l_>ru J;ZMuGoQe*.'/4">U#v[mmWUmy -Ck5Y]3'~j 6`7kAa3N? *Vt;Fu*[APH >=PJBio\8Dn e6N<`K'\)f Jw4 2L U(;]8Co\rA=%Bi#+`'r-l75EJ5H~ z&?7y5$M^B`'= Q)7fkY 18, Q+Z;t*a'UsI:n;#8te$N3tIx$v1u1FrWX25 6]\`9+WgK|<<yDw$. S$q-2- AS/6"w#c.V> WyXj=#a5`l P^L+r܋mqq{X}X[qqqqqq(AqqqqKLը(ӐqK\ՔF[[{ڔ[[[[)79ürrڔ[[???orr[B????e{;X[qP.G???I uffX[qM???FևsqqqM&?@MÛ Fqqq:$dA=qqqqq*/kR-<;Oqt2`>nщ 3X՟JzZ# Vva]g'T%Dli8|Y ,HCYԮ! _̍E"1ϬcNwTb y~0WNwjUh]x6pwQQV5Sl]j䒞ʍS_4,]S ??8?~?|p ?spe-0.8.4.h/_spe/skins/default/output.png0000644000175000017500000000212510352640155017326 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb^ gAcǯ߿Ϝ.c3%r̥?}.l]:gkc` X@##?FYp~2`2YW(6B@0>01V^an&_<&3ÿ ߜs+##s P7Y ??fbq-ą ̌?nf/YK*?;߁raA'䩳 3LH - E %Ԗly\g?]8|:o0]|/:/bA#fa`ѓed`PcFʲS`ggšGT XX|e]=f_3ucwFqVflXn A2Hޮ 1B!"  b ޺Q,{̢i[N3f ]Nƿ <.3b}kƠǯ؁10?* @,&i r$ @㆛[fk8o _A0|="??_0j30p0CSF@\a|eݯfq,@1X {L)?01 [10^00^i@wbG733WIL/=  \]+lAqݟ;Ӏ Xag`Vx VyiN8TcB]'i0mĂAder_?ߟ}ﻧh,`|B`$pOIENDB`spe-0.8.4.h/_spe/skins/default/icon_py_edit.png0000644000175000017500000000140210515765540020437 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<2PLTERRREEE555{{{MMM---@@@WWW###KKKXXX///eeeiiizzz**,ooo[[[ǓĞ|+cYk!C$Z?+}}}_J\ WDOʼn\wMvd`;aCGuwww}tJnnnߝ[ccd6z\j}ZZZџKԅDDEhhhYaGɖ__a5D|aZsss9dde$~ί{i;lEڷ'ftRNS5IDATxr@ d> 2$efҦP5} csb4ReN⸩i|Z+ +D_3Wkwi"q7@vNu' _Y9Xr-z2ֻzr& 8M9z/ٍKqݳ"L15*b/}JY_ǁE]pxk}'vuIENDB`spe-0.8.4.h/_spe/skins/default/filesaveas.png0000644000175000017500000000212010272471120020076 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb??Ç>~ ?} d2]`l}AIj'x{7.pz/7 @@L3ׯ?7Cwwz gq_.'BHN8?@\PT? _~ ×/߀ e`< w3dY h?bXO?iˎɞG`>=517L4?|7Éw0°Û/_ w0<|+Р?~2|3h@E@ge8~'7 ? @C!;++#?" qil e8^ /×ϯ0(>gPc0Ֆ8', pL~>4ޫ kϞ(   ߿d/ë@W * \ ?0y/^~e ` ?/0 /pS(mp?t> ~ ɯtw7o1q3|F)cp毟.-H`| wb%YP&*tO`f7މh1fd?~A3p9 X| ?U~hO?0q10@1cb/1Y ~P|fW ׏ ʱc``2>vIENDB`spe-0.8.4.h/_spe/skins/default/session.png0000644000175000017500000000105510272471120017445 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEї*)#0.'chiꜨiqrskuw\dfz=BAXWSꣾ䒒eus!'(*;6ONIOTSKRT353q{}\]ZYt"!^* 7tRNSYIDATxb0C`i1 7qKJH@X]P(@ %>>ueYi@DuyD%Trĵ٘3P4b222b H@C&@ ...V&3P @Z@l  0##`[b@>@<'ѳ䆏IENDB`spe-0.8.4.h/_spe/skins/default/folder_delete.png0000644000175000017500000000060710272471120020561 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE^VNTu6C RntRNSރYIDATxb`gdcceegefeb`gc``cdea;D,@@VF.F3@ && #P@1,, 66.Eؘ"惔 @ ff~&+;@؀:X@"4g d@2XXn  @~,!߬_IENDB`spe-0.8.4.h/_spe/skins/default/import.png0000644000175000017500000000204710272471120017276 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEݢ-?L[ 4W )}*8/=)>̹'R-N.~5{O:Mbt9"=&^Ι3caY߁)7~$9޸;]bϦEpH|Gvmk a`Rn}5cʇq},fQ5 [\ڱ5no&ČՉώ,V[:Bep0&W NΔvLfQ_I_[)D@k1F:hpϜKZ~Mz^8jIE IONv )3\V3[f|[iVc(N#x"7ATW\t|L tRNSELhIDATxbXp|ƅ0@ t8daZ0ST T%V9HU օ %JShoB5ʛ dw!.p!@1gDETcY- y ds BNٚN +GF%5aif3|.\0)Gw.@1.\\c@ v,k,дKՏ  p24L 6[vBAl IENDB`spe-0.8.4.h/_spe/skins/default/lookup.png0000644000175000017500000000633310352640155017304 0ustar stanistaniPNG  IHDRa pHYs   MiCCPPhotoshop ICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3gAMA|Q cHRMz%u0`:o_FIDATxڜkZQƟ{FPEJ P!KA(H!HAETŏ P$XRLk%-Ī{y;d+F0?xãajBMƘg4MFUd2湨jO9I)I)ERJ:9MfW^47|4 A)i:508qΉh2R ,^ 7t@P t:|j z]) %AJ "^f~mVcx]4 %s" =liُHA,Kӹ#>y/Ei<$ !q.H޼?ww>lqvnMW_ htz{՗up8o fpsډDbX,T**M,B4fe2RBJ$V<dpX~rʈD"^/ r9 sXZIENDB`spe-0.8.4.h/_spe/skins/default/editpaste.png0000644000175000017500000000174510272471120017752 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_F[IDATxbA 22|_=-!***#-1ÌY5>߻3j/bɳ\~a3 }.NG^maggg3>Z 3.}#&"-f!hA~ Ý _f! ▒ __{MMk?302g ?Mrp?25Ћ *6 n0|d`72~Lbfbb O g`m //_0((2*C?/v]'jbXϯ@"&߾}eFv6`xMb>ӧ§_\|d&_ ~8?P/0ӧ "" ll M !Qg n4 ffaf&AA~6g^1P;;+0 `r0`` ]F|`0GY|5q߿pI>~ XrğIENDB`spe-0.8.4.h/_spe/skins/default/spe_about.png0000644000175000017500000005550010272471120017747 0ustar stanistaniPNG  IHDRdi\gAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEjf&&#zwsigcsHLļQ-0hfutl21ˇR|y||˔ba\ec}Ľ/.B@;rktrlԕWTc\XXc^҆ ̯{WWqlXYzdftqjE|zb9AEE1bXljyu*^ 녂ґ)\kvv300tr`\`FFvA;tZYURQMZb;:8WV:?JIEtz$olysP'Ҳ*dc}yC9pmh.+*DHDTJ%o{y984]]Ykr΁ sTbQMI&10,GijLPjrMMIsvUUQAEEARMGEogWV\]KP3"t)ggMt*mon(MRoL>koSPmoixpi͙>b`~Ri ़+LQf,k0ROͷX I$=#1~D6644[࡬ڠ4?xroYUQ\yDǎo荐uyDƮe_ጚWƽMDߕaqʢҟ ]EPuzűRpfuKDA`mrzfvҾ55tKszu`1Z`㡙g}cCCӴx&0[kiqbk!&Ҿ-%0H;JMDJMRNC=۰'?.;E<-6l~|WIDATxb=i!!k .dpq  ݻDWفݲ AA t\\B 0A$H$$$(mU&"@(̉`ʬ ` `   X1Wg77` ])P؜ؐq( ~ `.Jv;p@DAebnKNgןaÙ_ZZzKjOT7C _&b0F8FFM@΀@ "$ =e\Bw y,ge\D14~W"Gd!E0Z E08~E ^fư$8s$Ep< ^P g n% &j"G/jGPAW#Z\OPprpsדϧ/^lcc哤3Ap_tb|||į(s+s..)# 0z;ξm۶i_wɞ:Z.`t$;"8 %ِ ̈=Eqs0P VůA:%1C ` `d$xjJEuw`" ,@ĠUqfbW lAppee Qxƈ`BD^޲6Ϝi>k\ IJ^;ò0E9NF`pXs0f l`H Gp0~sAk4tEˋ-OHIOjf_݆;!XX惕Ү|Eb)&m`GR]LV -F/lg4@u0J\u09XR L͕2/[ci- ===_[S1  Ù+ Ӡ0_ 0e\ VNI铹D0@!`=`;| ؼ˗dn`:ZDSZC"GlIaRWFp`EEk+?wKŖ6^,(5!Jpp?CP @,hPAX!4\NeX# m,ii]Ql> ò\eC %n)%xru$TBhhtNK6`n1ԔaPQ` `eǎ< , bPqF)p.̕龮~sssQq|Ӡ[Ѵ%)@/$59:WHƯ0~+ Z9}b@,Ks0+0pG&V~\Fa H3 hcsWvQ`xӊ>NHPEz\`WF9[9- NpZ7NF1VŰ 8ug)C08ed\\AC9XSJJjr kc~jgR^?1s[5g2:p+u09EHP|ך~H ""WJ 4amSYxxa+N~`_`  A;)A6(``bX [YFw Ġmcmoɦ_,Fzs`cs=L`bZ1ka<9<0~;g^. [)jEkhַ# $0͛P)`mщ̢ 3zX/gbk b`.n @zϜz\қ7wc~ \+bPSkK.`:-1=LzTy l,D45=54'gz:'??T 0 @30(~큤Dk`ImŔ-a`Po1ōiF`^. <(;8) c0^LPX6p"xHIda9X{XǑە@`,Q /mt^O :bF!0NA Z3>Pf`LPư`@<nfIExVN^?: ,ԵkB.kB51 ,Q<ᖃb5$qs08c8?95pI%hHSqvz%oU)5GY  T 58~ Uvs ORk=ȗ&](lյ ϧNm||{gBF;ߚTCA\A(EiJS_rYYr@,,Y@̋``M`JHu0 C92ENXGn \ibR)e$lM ~cU0DEDE[*FߎLHĀ(h ,哀XT[ўɆ`dP \P>oYx`ϙ3OxC F1^ λAr, ξ8ebeaApQ4 :8 hp#lu@pǃIR Тɿ6PD4T ]`'Ԇu pKLYLYbb/HZ 71qQ @F[=!iiYs`PG;=ω[>sss~X@$   g` 2@9/X ;y_PJ$ : LT w)|8Xsr"87RFP3iEu|UaX`P ;:z]IOOOJOמaRƒoYxeÅ}}դXxc9yWr}lhC<_P6E12S9PVCSHbp KhX L r2a _ߑZ80$$XhhjHheV,!0B&{@G idAr0bocc6!/~i<5&.&/fZ9q->&hF XBAI] ,Wm2F+5ww' 8f2!5 -,!U وz}>0򰥥- ao[i3phj * 40[[ @}+~ mP\<#< .AAc F00؜qA>㹗㩃:--t1}}jk[sn7gۅ}}}ŤB !mhy.Ĕ6ޠ,`fdV `UEMP X4I.;rB`YIUR h0y43yNԞ;qD##))ߎʠU:8Z,Î2Q^[WOb2 00 C8s0@#X:ܵ@d=9rWz|#}cN'ɛ2M: lD&B1B&9^UDV\5`E_[^^R`5LI&N`Nn zX @B߬:;G#Ǻf%pIbtQ'0X&R+AY.ff2_&4)-uXd-1l6(~&ϖ,Sx'HZDFLeh`,mw6[Zt%3~v\V$z`}i?u0@AgdcMbkHE;sΟ>ܹ/feA)@߅s,J&`f `P!KΔׯ_L@?0@Y,,A` T** cX,U~rb.7|8 뵁 h\+s]#r=@[AT#(@XNhGp-iaom!'Yٴ&&'hڄc8)%NEG0@˜;ź ^pߩpqqhp nGjgd Zi20_,,rY ÙxA8(4ĬvWʯmɒwX0DV6S45,+$ ʶE0o; |22 ln [w((4{&&6ӁEgzz%wrQI`ωq##8}_g.;<бr)XZ-)t鯕F82Ab_ n@l,z)֡WZAɏO.RS.ZL.. FDm#n> T&&VXOZUhJ{ER\e#!aI{R(ObmlHILJ % d(l:7oYf99Z=޾ͲeAdW^O]ʕEeS=Ԋw`)[X4Ua'n\vǏurmk[by1D{plb}B--'BsBޑ  Y OԢ&TЊz)g̨OOLfd˶4NCmaEߧx4XZ:s`rqsV!?? ٠1HZ`69?^^RQ2?va1Дsg 7֌x3y@`%X# #YBҧq;G:Ww``oO8r Th&)"rL,@r)Cl>uѐq`7D^%'ۖkc\lZst钲0k-sW6ЭX2wd*[)#؎v7dVќz>"ʫ63AZ9>b.x@ }+}m s\ds30,B`gŅy:_Y} _L#Ht.X `l%S`(T-0טq᠟&c]4ˠ}~#xýO.zpl{זQl]aSKx`$'6Fq32gdv#ݞVGYpޤ"I{h` @ v 4ju9t+˂@ѲX, 3!#Yt ],;` pC˱|#Ooɒ/,c\gvfcPTi4^ Y oiyӲ(+ս X]A"XLΐOʫjV~ML3h'gq vIoZ:osdw^_\W ]K˖1%039@FA ̿Y,L "EBBbxZrN ;-.^^d%K>0{rFeɠ$+kd2K6Ԁ4$Ȣ,`sMwq `= ̓xmmm/Y\ `hPk5A; 0~//Y"qmYo aP-Z`(#Ǫ9xFM0 Xr|`b+:3Nuׅp"K{Q__8e_ZKs/UPG3ȷ`kfAY$&8e&o]4$+S:V\`bK^#)hP)uť] TL/^,w?K~V`w/SXDdAraUS}[Ψ6ӭ|[2bN5s0@1t],[qoֺP`s _?w}7fྃA/~(F_a*a4IM{YYZ yᛓDhpO*EÇ9˓wK;HG%SFr?8s[\nɋ'9ŕp'{K;2AYb xxJJ .6r~X/YCkN.Vl}TAI._߸de_ѲRԌ(2VAUfT܂'4Er{3Cq},eKn5Fxk.0s[r><*3߫)ͱnn`e:G:7a`Lꉹl9Z\ 2>bxz`o h(K EKYfuuϵF: gP)4k۳Q؈FT[!'Aِ%ߺhP c,Դf Ho@%qn## C3{`p_~V`> O )l[lf+a6RpwwaͤRnu`sL>>ۖ#{uRڿbϟHڐ̐Ya`VA\,lC[;IL~m`H  2 J Ln]4x=e&.V\]=¤o%jZ-s[tTw`Tldy l}#涜00/ҖFpeao/ 4zJcO.]i xz+KE"mUdC˃:Z`:ϊ3X1E1+fG9dW& ^r)303r0 "fajn]4d0 6[Zps/jC#CptxZYx1}YPɽ$0tNK hGh3  *>11ՁWO710жM(!, ~n}qgaH_P>ǰ)|P)H"ʬ,`fmcGѠYL , M,CLxU%`,>[\@d܌;e涴#ݐSTYl zҒ50РSn0h |/l? Q2z1~uib)ML LZ-^f}@ o;\&?AqLX ,_"V0Z6W-ZijR_p7VFzЅ9`7IiDvv[kתO(&yOk(3w <AxUUnn|ChxNe>c!( 'Y* ,U,}Ηs^l2^, עaϛc"A=nDsp6EɭYrY,-A +Wʯm-m]10v!5`[{WGhH]߮)e l&yxV\hn <F)#ڽڽxx@"":ЌAAQs(QPx_aSߚrԦL9.@1`Ka9ǝYUe9.GaxF 9X9``kJGJFF:Fܫ(:!C3`[ ||*@ƍӰbWPO21^3еIoɂX /JВr!9.ИJy 0E13őӼ,SvC $*%$Jq (fc E@Uq UUeaIV`FdFp]nUѹ=)܇ū='|I>s02/#uj3T :!S Tr]70tСFCFC*(;;;'h,R)-Cli`ՠͼY@HdRX#iHE$L^˂d^rLf g+d ReʻW7(/K2+*hI%xͬ+xeK@"HBB0&(lMQbN ~E00rA9u!E*( KJkV`Kj`If` >E{Voߔ qU~|钘c&ePM<ܥ㠭h;mMa]>GB4H֩.P2!)?H3:1?$,EmdveDY9Tgj`;JǗ%?Y;}X|de%&&.:I4).w:~n]rP =A>&^&v%]&Sf!$ 3(`% bpyhCxB,=$P>#,|fRQ/M1`=|w%1qg9# @G뚖&:_BZKT?`}~|VY9dWsp0NL 0DMY% ?02%?`hxNNu(kS9%8$2PTMPD5X6-LfetbM .!GqsR>TTQ&y]rx!]g ?Ѯn00CVzJyN2ʳt&h x a P>5,  h`'It609'͛^  77ةh\^8`5 "i=FS4F6=BB),,/X3n ,Oy`7 r` :#S)gt ߙX;]o?c- %)?($EW52`UVrr2aA29dl)VƺՌdeXU^Huz9i[`k {z[YqZUVVʕ2UPHqV;V:r 3(z /@:8A%ZߚT1揉aLhbK7D6 ɖs |X#XTH^>%'h] `Y8LA')2WU=`٩`؊mku5EED72+%_Z*Y Nffub[]:%5`N&-şpc-0<뢑Oս~,V[[[[ L*=s]Ors9Ut#Y CK tL|!04* @`PVq#8snP;';"4Ea@:XBEBsK  9R/Th,Q`7q#075@ ,Yr9 C/d2$bJ `5I?ZAID"qD™EXYXɌǁd$'Kg `L$gY^^?[[[5`60oM9 x''իҽ"3ZEtxu~8#j`~ 8ځ#8:Z2ZPG޸Ѡ5'$[-;t4QlnD`sI3|C?ĸt8C8jnKXES_(z\j5Uĵ.)~ >T:&mZ!D{!oW 2ddE0( @Y4,v!9X،cD%1F l_ oh:Պ; w(j `#K^Q 'Yz4)\\"d+`S\n{+L LU!E倹xo^Y$jhp & ىJM%%>,IL VJTǁ%v:X#|Ɯ:VlѺ6l)s>+NE3ҨƳ.ވ:Ԁ9XDGhTWWGD:7QqðUbt C92y! g{{he*vh`hhX7u*Ojh{ z i`,CK!- M<Ȃ 2BYJHJY&S^^SS,i%&^`WrThhRI"4 "+\91Q54 oM9:#Y9 ,ɑ,̩ɩD ).Ex[ip74֟/Z' je:@u](f`Pd`P$Ʋ14 ``XX\>m1:8.;  uV!gLƱ<03\\@ +6q&[AYpN`Am++\Љ @ MK.UM( &2H"8z-,Pͪ bMa' %kjk&b^Qs0O}&SYxjD6xoP(`/I xu0s2(""Ҋfg` +4tZmLlcZgo:`_7 YrӧAKԽAQ^'l -ꀗ記W RZ[CT!Ct!- WQg>>6S^t&)h @1p2f@ nJ!V9ifP&oY\VZi*"g%#Ŕ7K Z|hp+3+0o]*!Ҵ{&~F-aЌh68YFU< [ґ#n]4#m֐tQC}@ zB٢U3:_Dt2s Wh:!,@r9_T(vI)tӇ)TDM/2oece?/($>XDERf[5Vg)uZ%* N ?9@XwPS#zgY|iP%,@  M]`dlWs/s4J  V4`{aH40~7lѣ g&Iyև,A_` `NJ%*$ lOs12s fj AK)(A$#dM?0*2 Z? 9dzE5Nټ?~ * N%[D꜔/u;^'_2u3&*91NVtuR MT8 uk  ZvwZGf۞~^m`eUUmG*荂q@#tf _3{ $`g``gM)>!!dAr0@1HH3`.iQЊ\ǹܲ\)?pϦX%3 }A5ȔJp׈fe[nZ(эQU4&# L$D$D/U/ĘAX0KLLdtRVjTK8** rQ6F6P3ЭhO@9X \U\j5qb/x0y@9S5aQfQ,`7lQйg *:F6S }A|.r;"Br0@#M' [_:?0obW ϕ,*+%[ӬNn+Uk/crVGЦrn߹%,nEXV7fϑ v*H?@IBQ)-@TDxKU?%/qrb?j 0J'Wd QuLƺh#4 !V{jY%u"xQl(s0(q dq;4fHkh6i0aأ-j<2N AEJ&?*>܌}@ B٠f03 %/.,T,+LHQT4?+/Pgl(r +-O5eʴQt%,E%RRrDE$JRJ(,$\!qk6pl ?92&?XMgE,ł"XM\KU`@+(h~hhoܹs[h, Z|4$p X|M4h944V 308GJ򉉙8`I._ ^- /KV ֽ 9V~ȑ]ɵCؖ)IV6+(kGֲM@6HrL C YN0 M"A5ItcSD"MM" ٢DH4 ^Y)) Z\)ʪZ# ;W@;FށVjy+ B[B+Etooj*hwƄ OQ/:3ET 4 JW`3@vfe09-š\A,͊nB,|WȲAA ,E8@ayS-zJS`oIndfeq5u Q$̈C'(%*G:3&66Ta[WA+=0|f|'h _j +"55u\F-D1Nh p zA8 -2T1f3W@EYTWO(bݶ Љ$!p@x<0jA L+(Hh2+eDsv'-m; p7'p2mKO5zmRSBRRR0& f )Z Y`fUdYwP#z ApD(=mvH@[tt{(AE+(@t[800)hCҾ8c̀ I*9 3\9#lab$ţY 6!GB" ٗ |[!\zI\\A1K` JZXlYh 0#457M@{XGal?TnE &\(D*%BJhЦ3PH2f #Щu^4~~*X=" 7Lȋ0hծ]A9W 4+ 2f1l *4UxtT&gyR\s;?chcA" @&g=iPԾ-^i`%4h$;ihG2zX4V :# XB#M7AYK@g$ ;H(MMJDDf`%$Bc3)2$ a8΋]OMMK o,^\grD1C&R@8 fѰ:\CЄ006-[ EVh0mnPemNM΂F<ϋjZZr++ nXAhh``bx+䔨tKWDo=\hFʔ8+YQlxy?8-d@`ڞ їSppo{@kh+(>@{{SBS+/Mf ,@3v30(AÓ'sz)66S}b,-/i4ڄpsǔTqggtf*w0fsɛ':q|`mgTe6u 0P ? l`g JD^z^4Y{ZR@MmqOFKNw)PGgr0j{`CK&1DO=7ՠ&cJ}Kf߃m`bn:%_4X^| KlV\ln\\Y ~PddegU 4fUp`l>sdeܙ, ]R"w C>x1q-p;tH?w. sxb$1Ɇ << bѐ@   QRI{lϓy~F! !`!J%ÐsE4տ yxZR{ݟT9E|yqS̘a~[bokM'Ya,. Y. Ѐ4a 4f)' :-H.t&9SD$:iEr/0bxQ6u--PC4Ѯծ-]`Ypn,D/)'Hv#j'*\r_3~J`;4; ]Gh6IzuฅF,x$ .6nvN~V^FbpCS@Ubb`U QP 6"TE<.dU f|B!@JIENDB`spe-0.8.4.h/_spe/skins/default/__init__.py0000644000175000017500000000040110272471120017357 0ustar stanistani#(c)www.stani.be import _spe.info INFO=_spe.info.copy() INFO['description']=\ """Images, made as a package to easily get file information.""" __doc__=INFO['doc']%INFO #_______________________________________________________________________________spe-0.8.4.h/_spe/skins/default/tab_left.png0000644000175000017500000000045310272471120017543 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% (DDDgPBHsCcF<׀4Q@8 k&d@1K&AFgdd8s4V#$/B?.9b4) (6 (6 (6 NrrIENDB`spe-0.8.4.h/_spe/skins/default/thumbnail.png0000644000175000017500000000152710346714615017764 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxlYHTqܹ3wfMǥ*+ (0 -"0hl, ""!h!*ڠޢVȱ"v2r$v\=Lsp~-W}*T:YպyM .#@)tu][K.O?'#wDSo/*+_knkpr{0+GgO'g\rT@=ԮZqcϮuNv@1~sN,Іd1b#6z C9{(} P|bf+(> o@3t7<] P $ ^æz.!N\>xWStEz+bA*V8>5uV(03nB"P7v {ߊ nUdvl\j0(r'y%{HQɸ'va~-n 1+iI~f%f8`@vJDqrI-F'g!jAhX4[D0 @ǫ8ChR? AGa*# Gt NYnd<~q? RYZ\ti'??Ue%0hTf B4ʊJj/c֜yde!@2A-^2W4xi=jfI2iT&IWb-%Om~ ?WHEsIENDB`spe-0.8.4.h/_spe/skins/default/view_left_right.png0000644000175000017500000000062710346714615021162 0ustar stanistaniPNG  IHDRagAMAܲNIDATxN[AEϝq鑨ez(H$->@OM4BK(yػ/HPŎ\ }x]naژp0Di\D ‚RY=["߯AJV>OϔKy/]˺&'tsc{#k0P4@{xtr-'7bl`Vb)#fLp.$ 2@ AB#T.o61IUc`\RR9QWc-`0]/[a(3GuIENDB`spe-0.8.4.h/_spe/skins/default/redo.png0000644000175000017500000000132710272471120016715 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<iIDATxb?% (P $y SeHRfbΟޯ_3o ꘁe` QA@ :+(p+PP<x.Y&i&2|m;c /3!C"j<#$pΔ?m~iC"Pck@b@U f40!t/CЃ.z ļ@ Գ h S`/(ZX$pׁlc`tX߀pr@,Ty d3QcD@k  DV@[Y :rAJ ?O?0<7s6weY @s;* /3սb` FJs#@Q D<${IENDB`spe-0.8.4.h/_spe/skins/default/throbber_still.gif0000644000175000017500000000024710346714615020776 0ustar stanistaniGIF89a! NETSCAPE2.0! ,(Ȩ| *Pf]bi!Hu贐DZ~G}! ,(Ȩ| *Pf]bi!Hu贐DZ~G};spe-0.8.4.h/_spe/skins/default/blenpy.png0000644000175000017500000000621310272471120017254 0ustar stanistaniPNG  IHDR,9zA9gAMA7tEXtSoftwareAdobe ImageReadyqe<PLTÉ у   } '(%y1{v12562 xؖ.:) Ӓ-rO5 >>;ՇJIH {{{5D/h,a? , PQO#U%ۊ tFƉ+ghg oݙ/ˌ*ڄWa!ʅGr*mmmftj,_`_)ci11qAh XXW)OJ6;t49zU@5#0/+X +;S68JRƋ1@M3߄]a)3zsss_@ eEW8A r X$ub)hU0y;aJrHftS6XwlYfJj;|QY(QZF|g}'`4QzqdRhSu`P>Qyz{sO;/Dw dGϐ-{֞NI=gr=֐$k H7yXuEאvQʓ;6qj:d\O՚dl@`7PNF3vs082@ `'.b`VfY='g|'_/ 冔P1X5pqt)Ya `pIo`&& delf;Y@ g@ELՓChS-&m`?jIf !%*)*-tæ}5?gN0@fSzzz"Z@Wtl(Pe,> GA T 夀nUkRmC .Yb54FOS"\ݲL@PѹE H8 @gy8hn,H1Nq::j>XtPskkCW+]ãc@0kfQ Tt#PuWpNzm-d:kE@1>+h:`IF/F?-vm4@1ŘI:63 r0Y-@q*ʡh/b@ rb&k՟J2 !Q 5Q!`!#hǟ!@ --i4;#(4D-`ӧ~ [fdXy?O!@6Ã/D4 o)M1X21t2`k)[N n"h 7 qXnf @1*xeo ׇ @Fbb謬dWIENDB`spe-0.8.4.h/_spe/skins/default/recent.png0000644000175000017500000000134010272471120017237 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEnSd'{{Bri4o,s=+J0#wOW]s/x8mF숽zm|C醻{GuxzxrR 94WtRNSc5IDATxb651F0 - 䘁 @y@OU0b]8Ue}8!-T[38ğWE< |^;!'sAb` e gbvg Py> `bҐ0 u7f^!<@1)JB~\ala`#ª#@@Ii)[j *z &\@~@1}$(-*fD @4wIENDB`spe-0.8.4.h/_spe/skins/default/uncomment.png0000644000175000017500000000115310346714615020001 0ustar stanistaniPNG  IHDRa pHYs  ~gAMA|Q cHRMz%u0`:o_FIDATxb?% (";  9zRXvN 1  X`NZva #}mPC e`ؼ 6FEb"*h"[j&͛W]_ ⃜ưybO% ?ԚgT @l 201@!`! ?buwexAh"PP&9K1/6O@  6JI_i_,vP4!2 Y  =3h10|cu R@Ta )vbT 8~?Hb9PRVyABYh#0_R R3#xk ޿b~a4 "kF6W6=o#\IENDB`spe-0.8.4.h/_spe/skins/default/filenew.png0000644000175000017500000000132510272471120017413 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<gIDATxb3? Ǐ fx#ӟŃ [73j[SM ?uO egg? FFFE L$$EuEUwC8 Xgb663zl>~X߿"t?H-@auL@WMb?}ˇ6:L@oAOW VV6S'v/ 2| h?1 `a`ff /`XXYlFZ073)gX؀t+ԓ@,0Bc h;?&f X44F  b 60Y003"rȃ(-&3Pbb{j;3  fLrBJai?$@,09nVDnbp 0M0Y 9O_:'abbZ@'361#0Z|f@Iۀ6ƩIENDB`spe-0.8.4.h/_spe/skins/default/filefind.png0000644000175000017500000000201610272471120017540 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE9hC dT5 4d1c6#@ p7 luq A"~_׿1 kŀp+e_:ua5  7d{eH_ tb03< @`iI` 7&=C(.ZSL߄14. `| ?(1\0šv01V^an&_<&3ÿ ߜs+##s P7Y ??fbq-ą ̌?nf/YK*?;߁raA'䩳 3LH - E %Ԗly\g?]8|:o0]|/:/bA#fa`ѓed`PcFʲS`ggšGT XX|e]=f_3ucwFqVflXn A2Hޮ 1B!"  b ޺Q,{̢i[N3f ]Nƿ <.3b}kƠǯ؁10?* @,&i r$ @㆛[fk8o _A0|="??_0j30p0CSF@\a|eݯfq,@1X {L)?01 [10^00^i@wbG733WIL/=  \]+lAqݟ;Ӏ Xag`Vx VyiN8TcB]'i0mĂAder_?ߟ}ﻧh,`|B`$pOIENDB`spe-0.8.4.h/_spe/skins/default/down.png0000644000175000017500000000102410346714615016740 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% XpI0v2?#6ur:fQgP0D S-@t) {Ani럿hb?~1< H #r,-2x vLSBL;]@ PbDF!b3"bW@[w~H,AM9֨ F\ d='؄;Lĸ!.7y@C׼)?,O6Ċgc\vÁm~N>bGs@@ @ W"tIENDB`spe-0.8.4.h/_spe/skins/default/folder.png0000644000175000017500000000120610272471120017233 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% (ĨmnO^ݍbl^$C =bY+ 6@?} nϗ7030# 2u dawJg1022-&FF~{ 37 /_ e8q ?؀:nw ,` @t? h8$@( ?~12 2r !zŀ@ \ @(hJ02Z3meZ 7 @GNW/!f$x2Ĩ߳ P tO@06B D1@bJR.w0 FJ3@֩椑IENDB`spe-0.8.4.h/_spe/skins/default/tab_right.png0000644000175000017500000000047110272471120017726 0ustar stanistaniPNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb?% (DDӀٳg8ӀgO24464 p3!iiix  .x9Аϟ34 XpI|pF\_k~!#>/(%b||q!cb4) (6 (6 (6 ׈Z'(3IENDB`spe-0.8.4.h/_spe/skins/default/blenderRef.png0000644000175000017500000000154610272471120020037 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<tPLTE ̓ ΀bJ%7j ׇ pT)~iXk} Gmcl0 Փ+/R6 ň'ߒ 4t#Q]^Zsx|΅{bP3SlQD/ cv[p}Y 2vLj!b͈UH21nS)׊ZAzP-.zTcGl&o p /ֆ [l΁"o ,rV(6t&;J;|loW1x ^N lՃ4OE2|n pf\#! ]mfjv3{h@.{ݓ ˏ$ڈP2Ԓ,YՅ&bI#ߜ1'\\H;(u *׏| Ԓ-ڋқݻ|tRNSj1IDATxbFmD‹ dK虀tc7S @p]zProX5@8=}\be$"mZ(a@`3,#+Yu8$]n(Qo@@-LvoJ  jws\}e>6? J$J*%'Jȶ,(@@* `t * pWVo\>}IENDB`spe-0.8.4.h/_spe/skins/default/def.png0000644000175000017500000000161410272471120016521 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEω%䒒Ӑ{*ݭϳЋ  tDìϋ(ټ["׽~ڳɈrºȻ|,֒ Ʈ޿gҘ;b Á ɝ ˲ֲνχ߾˪ػڒoE說n tRNS"IDATxbhjw. plbhjbg`eca0bTe`af qDK"X 6qFbAK%]tjv|kD6nx6I$m0طKojkomYt㦢Xe}訄mv>Fet+Z 5i $RU"]Wܕ8Ynk^Aڡeq)!4*e[ߦv9 싀ߘ-vGw'cxּ N|O6}0iuNCauU"X(vrR v_\7lk;_j"贚ܲjI.+0lTR)찍WG6ַUYkof6ۥ`lsLQSDғwOane?ŹmXY+IEDUD{J/ĸM1W^ JؼJiQ5OݤA zۆmll9>;PU_ ĵs:/Y~tV.6)'^Updl_?-c ׊LJ)~VP.T,@ 9@BT.PrP.uBҀ@:J%TT*y<p}o/zf^;1bU=zZc˔aC´Kt'+y?8~x|kMӧi'+L^%،1> |ʺkK,4\ D;f؆S3|4[hYx  #e?ճwu7'ZgIEd :{_vnm⽒䰢)me',a%~:hQ@6DI VȋrD޴&a,cF!PD['T w?"̇2RE橧jBه4^mnyHX~8eTTEVNG79g8ZY!LUh*PTr~_'oq?}xTh WXӥz+Bdw"R4;/iWlgҟYx?3}_ N1&3a&I0[Y:q4e4CEnKZz}_^{UGӳtM&S3ގآ>*#u]S5;Ov^1vJ2<5 Sb4LaqkR<>=w- tԧ%"@me1) 4r܄ Jf[TPmQ = ]vַIVmNzуnr? 2vեH{ݷBSޡg8k N7Wh܇u],R2J ,K#ۼy*noVzoM2D*YFM+ѝx*h?0!iz9vep \n8WZ$*fآiySQK@ 9@.P. @: Pt@'@ U*ʀv/>ݟlF[FdzKrr~K%pU"tQE7/_ۥqEڟ* wB[[DB_ĕu᪾-#;):vd_P1Tҵ[㕗14^끇/ƹ/Wg-\2 P oZZpĶr|q]O-VVrw>&.;E4O},Ni` "~he]Z!AobB|-aU,z+ՙ#H26h֩psc& $t>$;6}U-kxs{:?Ldy m6HQV뮟el^|F[L`$62eUi4OnE3aVqX.I /BO}m/6?s! r]h"r3Vb$ ~BWy_%o i5J6 -.K[=\W]f֜D67uRaa$/OdUO l:j{!gzvzޯیC )f3|F8ss#ӡ hb?6?-yOe%1SvFx7JA>Vţ^i^f9}]Vo[ Wq\dܱ'#t_|fElHfJ;D=z{|LC6A8`tTC@yQUBKشR:5=pf\C9?H+@_;q1e`cb DMU|Uz,CI{ E3 6anRe!=2䚓X-OնI(f˴E\+*r9rsrs]]!crg(t 9@(:s@N%@T*0:5OmSշLfuXq 8vnE$ .TxlSJֈzUטy|L)DxO?*.Sxpʜy]tI̔pU#]K{+>&lt5{Uǭk~Z \;k].3b5^W>M^=k\a{sž9d 2&AExWe"0/i"fXξPٌBQoe+kk+Ř.D5Fj]L;t{ӗ`e< WQ+.׷BD}kT;`GD~+RMT=8 NSѕD$"ЯïG34Fn ̗0PuSDrܵcby ?}*Ñ{4*~Z+ʽYC_?,=ҙ'qE!1f{n!};x=b>]yF'kHmR@J(>dv_>/gz=טH⾲տfBΑ25׼:_&JGZqo{q_R- *|Qu ?9߯!` -]{銿wDK[t|wZs"cƟ!m+q"(")J7̖Y}x]4BK(/TT˃Lr"=3&XIDV^I q^=%+῾ɆL9Y~POL-4m*&ȵ^*d}(#3lTd0bcDˤڢ EI /R7/#uMe8rq& PE]jd}*)w(:g(:ܠYܢ:w(r@rs>:T*E@"Pj)_ѭ/dNxcz!,VcHӪ?Heg\ ɝj(~EmW".oҰNZmlS>0U{:Z-_)ZysyP hJ-_DuHZ hh;8sUﺏ8Z C eᴩpUp.R+[hhrxR8+ Բ*|jvk)A6WPE=)Z=Q{E "K"W=uR"0qjhZ}SEԈe3Ö&,h!%Nk\-lȬzyufkl<}vB$$J9s19˔r2bɥjtkÎ|A $M[>v_kȑ_)w'OUq,U_eaUUu"8KU:Ybb?A$Dꖷ^?Ӯ4pt O㘱Db0B$8"("*(g@ҀPܠ\P.T,@ 9@BT.PrP.uBҀ@:J%TT* Qu>OaWd_J!F-7帗ㄊ%rl^d'36:tK%)kFԌ\.-"E|UM45͘2)6˛b:sS-UWyֶeR2"-ۀՕgkk-  XТ)".}a)jV9gHBO|jLi"Z y1$c7ZQKR'{j̫5uV/]t+VgL4ȷ7&&.BVZy>ǯhWh;]=.m0$ +:ER?DGeȡ'SsdzR @=壭Q]퓈*!Ewңf_qKRKS.Lxh Qkn8E_N;Ү XQI~4d}w!#eT[Gw(0+Q&bGa,4_ETc|;=DwY)*[.oEn-避Y"/dHaƌDWBO.Hj4 +Jp}}"hbIsT[[89cLBeG]tnw"Ap˕4Gyeo}R$Z]*`qC(_ =T_69Z}yJ j)n5P[Č%(uZ1N&[5DG95 Zƒxu!DU@(g(T.}(t: U@E@2Rԉ^oN4Uae -,+|o\zJoƙd< xv@@OP+v'bQ-qADDKzӷW_Igb1rV-*ISo^Uv< %_i0'$g8.<⥓]+<#WDQTh'{*ij3pI/FX<"Q0Qzi׭p8ft7B]Ht_YG+4aȥe` [;tJ Z[N E0wCtzH2|(LXXUH_u-}q~żm.A+CwxrR:Ŗx4\baDEQt.$TUQDS%Q._֤蜉AC7]]SE[*{p9# K-[6QSqJ艭쬭lѣꙟ/{$Y'hQtSE$;{1:Dq̬PPK}ʥjV5^6_E[Ie}?(sQx4BLcmIe܋{@lqPWJׅV>|cӃ52bZdR&6.ƴ_H/r %̔Vcƕ)ŲLe wZ6AG.[uZM'e\mq̵/, Ѥ`$3uXWUlvD)9< Ͱ>>~J&0m7ěl(ө*-Sy@;1܀Ǘ3L6<{M"}u.UyRy&^n&,XMFmHc F P!-7*l0e#No({Cy4 A>hw*o X&79&4D*NmWXNjv#(okYOU(C%L '4; nGKхȹ^sa$bV , ѐ~] bD "(6*ҘP=Tˆ!RڋCyYdJpIXzD\{ Ь6G%18ѱB +Im_cR;hxu4!?+|ܚKL31 Ib0z:{ޘ drD&FD~8O%7{-SJ`n*c6WI{L4n0*'̖])`dvdd1"^mŵ&=RcK}Iqۄ  Ω,f."-;N*Gv~b(WMuL >JLY\V>k-I I4. P,g(T.}(t: U@E@2v=џZyVb` )ۯݳa7$e=Et/:LQBLŷ$ 6x̹hϑ%V:k:Spb!^:ZM$D`O-_ֵG)YZ6DFxñ_DjD lu3mSH)WHaӠ~e@МzbGO06Jes1`#hW@hۯ潍vAPF&dtK_wƶҜjZIyS9mK_?=8IrK8/J_edrn3k]GթOr(p%.Ui#VL M2R0N龎Dq: JpIiBBAj"|j*)O٨W8PHq J;".EƛPB袽*;;fSqd, xȌBȔuU_mA wr.NQ22BSNi[iZehmm:){Ij Kg!V3 ) ;%(z[J)6xi mgF㲄 \7ؠ(WKS(N/ޔ桤|;G y縒뻪!iN&2p wuQ*IZ"$ѻ4F$9216ѓ Dx%q8#F|kr1ھ߹Pi+}Ze%܊M(#g6БvÎ l61Q#?p!w -G|.9 FoUM(u>&(ƅ&h qmDHTZ8eEyF;n-o6\AmÜR'bT>G7C۷u$ΙplNܪ@)8Sػ #hM$5D7MUZc"'$!S4yp7 ȋU3$FQYmhPaDJ w(r@rs>:T*E@"Phe.)u9UaFaخ }8oWϼ4Y.)饼ojl^7+2rg"HA=>%'dDc0(^|PT|4]+ oLCYV4ڠK+.oH,t&Ef<,&INvTe%QtX:!zQc_4֣FAyi Ú'Kia\ SkQlWVQ\ O&s05]Vw˱}xڶ[eW1'&ꢛ-G.wJ՝zؙ˓O Bv+3}l &"gcּˏr. i;PxԃbEO2m -xj-kKnP÷!9GFYR?e)}/ B7~G5t8\Z\;yoX$o U!d9'PqK8=aŗu@/xk"66%Q@K<%qC@:7!ޛF\]Z`cS(MfIPGv+*I>yw&%É1XTqR"pERDAK Fd&򢏘ce.&l+lLv&zy$ Ts-\*@z*ja5Cj]Ge^NX}t.8  %@Nleʖ1X ` o^b:{" VoNS/s_-7} w}N+{?](#C/d_MWsocm/vw7nOߑ}?n_l-bvnת~ 7/v;5mo9o+;}Ͷۻ/;7[kvױgeJטy;Og+#||--wZg3>X|y{[>N-@o%Z=);6PaϥP.uBP.t @ D,uBP,g(T.}(t: U@E@2e~7JGX{_=ྦྷ=Zf_Z3ʯ˻߻gU֝xVKjgM2~+kMroAhiYX7[tRNSVIDATxb5k:̘5k@1ݦ2MHK6>}zYӅR9gHeR, @ TLʬ}KDYgHaf]t[Kk b3NR+.Mh@ }2Q63AR*bCJTPYQ5KC5N[Gq@1(;yK;*zƸG ;2f20Gt9 '3d4)Z`ch17mb@@( \\a9nIENDB`spe-0.8.4.h/_spe/skins/default/donate.png0000644000175000017500000000224110272471120017232 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<1PLTE$їǬGíG⳪ϯ6ŧż_ީïwPKȯ^ĝտ,тsR&Ѝūc?l'ή<Ϡ3sj3ôA8a$8 @ X橤Z @@;UHXV-`@ 7Tad. 74 ])@,qYĹIENDB`spe-0.8.4.h/_spe/skins/default/icon.png0000644000175000017500000000075510272471120016720 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<`PLTEJ5O8?$?9itu"D^-_9(J :mՒJLV,Uh|Sr tRNS\\IDATxbG&ť ' (X @,ܜ⢢@ s˳0s$//&*/@ 6&IIY.F11y sHHIɲ2Y>. a) 10 d( &) #*- #"@ @8$ee0Ȉ<#P?@bG н`9*dIENDB`spe-0.8.4.h/_spe/skins/default/spe.png0000644000175000017500000007440710272471120016564 0ustar stanistaniPNG  IHDRGgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE$! qe)" c\ qkmie^hC9kIA\SuoiamizTL|YRX3)uia[Y92unEysuirOD bZibaTL.'."(8"#]XyLEtRJumrF:H"mdmeum: QDR*"i]C,,]?:9(-uqmfi]\VAuuu}I>yp*b?/qiUPP1.@UUUsO;f92ZRd\f_zTCO:=|YErkϡiaEEEmeI34{_ZSJ\U! /ie{ZLLCdSsWR[CD\KlOIUPut5|~!gdqieee{uUG߬ymmaiTWaL]JL`XYLp[^lkqengieysbUwcgPF*sx~z=1:ф eaqnkn,iU{dMO,qOMɠTJSOl^]kZTrΏ,z71vwh+$zip]ZQCJh`M ra2mYѵlCc\x(`KF?;zlZG g+QAea:z ty1& me ~'.  /2,gBCn$m`6Mӳ$Ze2 cgkW]_|DW*jqkOmic.{K~#8;nu@Aqm divt^Q|}ҟTxh7NfPhX3<qOow!LD0z 㭆3XBK}@ VIIUUIP>F*5G0RR Z@QYrU< I\hƓڌ &>%E E>>@c"*$ @R$4&R(f@`D0oYgϲkQkUML%E0#0$&'$LLHHW4OLNN6UTvwVVR<< j kz V4@1 C־wn+(>S2,"z%JU+%䰰DPtJJU\RYZm+ xK}LT)`Fyx n{f``reטfІ30rTYV@Ĕ Ȃ, RpG\!#t8Lւ;kc۳oܸQqnkSP@D ܎62q4TIF]hLn1#j x Ək7=ɶvb`H=|v4VP̧X\(I4fc)UP+.Λ@%꤀-V # `-֞x|f`oܿZv$9ZH(cV ,3k> a>n ]dE@n2*##++h܃" 9y`Fikݵ1T_w"҄YH jY-^XR& RM1<=zetP Fh%LJ#gabEٸ@"?thPiٞ{ZkGaf0K@ ̻ff@jRRj` *MMg  $-5kbh H$E1`>@4rjC(w-quD6JhI?"4X%SP*i %;(CF+,$`kI`E3gE0N-xW6nܽqx8ş! 5@$)RU5I,*OQ5vMMŕy!m*^!+i`$D9K@`KƝ݌ {`-eE6w!pYkmS ο̫(//U5Q I,  :+W}5E0H4``M6>t#?߽q.0ߟҎS6Ӄm\sN#m ;S U2WXg/KH84UПh V&A(DY [@Lp}=5#Nr}ƍ?8~Oߞ?u*2~s66tP>4@ETE lQ2#e_m {n`&%Lf_` '0N. U2P U53J+ÒC2Y3`+{D0rG cl6n\16xKで?RnhS6[dN m]]h n0`#8X!&%$(pjԄ(~h1%l`aa=," @wƍw_Tu|NϜ97ٽsguDp|JbUY ӌą 2„'NL=ֹ^PSPSeCbB24j^JHhdg$ԄfE`b8󇀑۳bŊx}oȝ=c*mu TɂX` B "Yj㗑A*4&89%  hPgSSS PcWpR*B@"->ypB0~y٧=[J- /!q LT;Ul8A/"20ԯܰ/ 23xyxLyyMC $CCqc2a8,< cԽ|h,/à-(=aFY6m=Hۑ ׯ9xٳObÈ@hC?Zǃs`Xǯ<#ܺ$&4x q}|yy n,e/{H]x*j+b8/A<*bdgZV#@ v6H~.t|ms_};2_Ρ6j/ci+]o `11-|`ٔT9j8O~/]ULJJ̢@,}MLyA( ed^`f@¼M@[Q0j0@!+E0(z!Q|(~g|v|ElP_ }(+{.ϰeY]_^_^TxbP 2=j-߰E)qSeg` A/Pc9brZAO!, %؛){u/ߜ̄=쩰 G`8F8X}ˋ@1۷WD; ZJY*V,C:?&gf4a/1`iPI " L3,[ jaA:Ia̜l2U((ISY^Y!P7v؈<CϸfX[+T%HlDoF0@1@w;4gG2xޠ9d'~:rvW77/qX}wwwU0blXXyQ284""6 `k ^v @FVih`H.|[r8AaAad`F`<IjnRPӢ0/` OP1UrBT#\[c8 PGV+ 3oMAZ4ʁ!r >~͡PTzZ_澕}}}^^X5WXrbg^^6PgS^-'''Xc RcWSS|IhpfZQ"<}?o u>X^ @&R}(SJ| PA20biAtVM׃#T< `k;FE9hjP`~fEp$xb`8/} Z#.4#BӦF00{Cg`A'W mT)q^-u PWARdp=%P  `Gqd?0~s/;vz_4HC񛩐h5IJg ٔA1 Ծb/=A٧/_E*Ew`6/Uח20MHG⼦|Nc`a 2a얠 gЈ2;! =Ҋzt|(@O/T>:Fi6k¾Ӧ1o!4~O h7RhOO"80 &'J:Z30$r q<&-QʈYYU=&K8|owf_6u|6JVsiK#z?,v 6عs`\\_R84T4I[I(褸jA$0G:4D`ndje"-# P? _p ~چv^ܹcՠ:X`X:Q=h 0N1Pb28/rFDG 冴,Հhq#2or0B;` V_cKPʜ1 4XL(VJ0@A"k |'((Ep>XTGw`=D+_&4J+`i慠rP ؾR#k*b*$q @7Pb+^4dL0N$pHBgE5%(33 E0,F082#A9=(R xHQ6S$Jb?ܬH 3(z+>e`hFă"8&bH 4mA@l\ml@`A_D ^G ̾w66@`04qd,)l`k_1nh`c.Y ˚:H:%U͘e) Y`Ó51 LCJ6oQbj6+OAt:e|&Hd7P_>M`́15#8RA*]&C 4)?錑u׬ ՠF0'&&&OTQ&j_ dd͠)"aSIe^a/aqS*K J ʗw2$Q Te*3yUD0D@E `nYno lV``D&=?@Q&x",>:@ P-f 'Ox`SAJw?2/+4!‹w``Skô} a Bj؛5074rAr C[_~~ FFJJJ 3,ؽ5@' I5mHFD3f@`` @z6M:e'8c@`r<MF!Ps 8Y #5`@xu3[h6aJlPJSh˱yJ贝/E;/N[4Z - z`k@R\]MMĊB^p cDU)8hfF;(u0@<`-bb2LH`P @E4(Ԙ"F?#Ph`Ίg br N`C Pk® O^GDp|>( xj YT>_; ^`Oidž+@&NggP'ADT2ɿ\((KMMVw/٠0C ?o_Pm!iq +)+D0 V)m = &` o)\Gtp{ #"X\]AҺެbּs͵k/\ZoayQ3J(  D_Z/ZMKm%ZРL˧Qa%nS^B``#[zۀ lrEp< . "M w<)XC"8UPYvtP&L6٠F? 0S""ؕ)a **me46iAss}}b+AJqCPwmg.tX`@,d@_`6u0(U1`i ܲ| [_BH)AޙjivaVdlnse AsY1'!!^^h 1Kj!Y >D{DF_F@ET8v<φמl55p8%%A* 9WT@sq!)q /'4zkkAyRIGRPR` xA jr#|MPWb=@F4hlX;6"'4 `l`f`*dga`4i͚{w20x% DٙIMzŌ`??nvKԊԊdS*/,! ֐+jY€p֮L#<00{O)h2tK$B@ qi`3 %9LDE1PYv>SS$PU`?T/`="xgDȱg& "YC. E0$~ͥ +ZFq&Wf&h Ya!!H CVʚ*K#yt!@aD0u]`[cO@r HPvAa,!fC (*kY?@ç`5MTj&*.>0jd-Ι4ivP .fHqv6坨#*%.&V "{ {Hxǥַפ&or-,aPru3u6C`X))J1AfA.,0tH9hV|;͆Ҡ  F(K,:F4 *4 j[ A0 Zk;1|0$i,,z`ϹPҘoY^#< t Ko:Y` AK͍F_B@- E*juۧK" }kL`'+kez%hi +p G0$z``[Xp),iOV̬a ZZ'jLczgED0b H&jLDCOC@;YMRϟ߾&% 2xLyyܒt"eTȣ>g~20*P #+rwrw}ڐZ(s 4:TI ,9YR[kjr[QVR;Q9$L<)ƥqa^.p <!-hxlZQN8-y1DZY\jFeCԘƱ0ݴ4/h) F#0U00AEtiD0/̪LgISw'+ps"[h "-~A'+W$ZYY|Z%4!` y{k9;hZZ<ΪH\Bh_pN/k+.c&06g\"h|N[S]EL51<ʯJR/F(D)'cʊ5h4g PSp{y%h vyW E_cHŬ`9zghie5"'ZTY\V 3fXP/x{-YqqJ  Uň\ ߈6-U``ZY %&妠`qeɉVjT`H-2?Kђ]–3f 8䁋i` 'y$y@0 3ba`Q%Kr@PO85Lb:(Jl:7 M#@/* ,Yt!㚰\ V<NNcV7&XL< Rh,,`l{HO 5I45Q53Q4)biB-zJZ S-(#8JX$'W w @`"Ԑ;g;7vʺut)(554bax8|vsKR1UŌ``e48Y}Vwd؎-N65M,# `n,E `F0"0 RL^ - y,Aq KHIuS5iĈ``""<_ %^ ى aE `:t9/6yQ@@c@޽UGCy ```ЙBBNB|J^UaJE`115o*E`F4j""0L! ^vhFCb; )@n$S@[A:d՚#G/?>0998tA\/ǭ+bWcgMKK:bD0'(YD+CBZ gZTZPigfoĔuFp2oefe@``R#B"F<Baa¼#؁^Ư"Z 0z՝@]A'#@FE0' 4 F0g!gLe0z[+cggpV씥Gp#ÒM ``#xG"{&/FBXDY`|VES 0jA;E!c8"XúGLn'PZ\hV(}5qgUpVAD0+@F0i lDYXZ*[ k%''(N ̽BNȅ42"Jk1#Xâ.4!KEe'mW-65Ӻ J a|<:0pp# F#7< "J3eAmg`a,- a\@`(`0rs:T#XB_:a`W8dV,c `LYeeIU)p.؁@L0k@د’%-A@Ov{@-*0Pa ى 7`ȼ"S/ `G`뻥F4* X:e"]`[zꈈs0%hh9a,H[X)9++( YV" W7LC> ; -9qD0d@XDkfm]_093D3K)@,n-b**kh# h4`P:&&g}-P_.)i7)Fj_Epuu+Ev@w[40DVV"Ʋava@؈ưg>Pb- B45n7SH41Ԟ`*h` ĕK@\,i,\!֩h-ͮl;;q/;V3u_ifhhdJ؜EpnP'\` M,MN8EADH4X#``ΐKO/I_p qgeӰL` X(Y9{E-0SԀ=a=Y~pm;ʉ/+YXB@l³@.b ED a@+D0JQswff*h_E%P~Vb೟@ke,~q&&%[؁8#XƠ.00s[,F)Ku=DE  _hhav@uph[0hJE vvv)RZIC%oJ4hT>]\I RJCb?1tnii GAl`q`"|?#@F0N0<#;,,,At/;[`Gbj|1:XI'\ Z t[8h+>hT˂ii yq0'tփŰ 5p๱#x`8;#X9~ F#`g3X„5&B A$&`l:sZ4h":([/4~Awh 0G-j# 4 Zށ!@j`+E:kрvae#gi @L\љaaVN1.m-`#O\6;pk蔒nsB@OѰsP tE1 tj-s4(iڅZTPhk89/,)kB" F#fEjys𩂠 EZ:>@ ja9 +`upp'`B ``/(( ,A`E!v.UWX_l*lb fG0@F0e4谻ЅWj]!'h1gl\k`iV]Qgcc9|!\;PeӬ lceujYSTCY 4#)m؝ n T MHϊϊ]CL 2]a=En5+u^P 꼼"Z] \3; ,"خE%wnm2kYB$ Tlcli# vD!%pVTUuѰRax) X#XscKC4$@+ߗΚh l %a(H-edG a:iҝ0t( `vjA}i`$ pHF&4yĕӢ$Mx'ebj$E0h-:sl'Y2)RF3zc XѮ1"g-~xYs_IGYR4UX@ "@ țț\cb"u5Mtd 5)QAn)`n'hͬY7k..I-*ޘ<[ @;12Y+&T-Y-i`hP褥EEIH/쐒e#dV11jEp~d%h)8ty½e1" Fh"V*XB)0HI yWs#K@;E]\2mB QQY\yK`{w``%` ue ,ֳuM,5^qq^%nK><^I4D0ڤ!fHlE0g.,)%esCS@Oj1RRRdeӉ|k`ѫapB (6D#6dҥG@kc,-x󒝡K`[h4aj>}NM(J_Ӝ@YXF xZ%@e8hTZ<6A30`, -!!G,c,-b# F#oGkHk347+H:x"TcTThΤT11jPjn5q^!'Ѐ@'n RqY@ 22d.UU-l ]M ``V-(>fߨF{)IbbՂ]]b)jjNAs <Ѭpo'MlDl)F>{FXFf" %`rMND``<^>+ePPӸQJ$gM$1,X ʥbjBB1BN)jNn1pB"/`MhgqE/l/,a'l1 ?3 R ח,5S`MLrxTQu'h,v5'''> u}ف.0ncmmcc 'EԕzzzBN䀜@ =0XÆ -v%$4E4~#!ǫkiǛ>q0@F0,k- ZeV^_Tc(_`ZU2t (=!,(ޟ$f)= -m/m?4E0 ``F10%Ŝbx@9 4s?jΧ~ab3UP9JJj! hPa)b _СWu 5|')(bobU? F#p?̖x2Uŧ' $%']FC# bNqD/,&C h, e 5++!YqILK$Uyyɡ2h4I`%w>E&(%%}\5ӁzQ!8 {CE/4~ 'O\=( j}Β U^1qIy1n+IYXgVhlZWԐ `% KHG>``+ uR`{@ ]B Y0hMp+>`kYY+N/&7O>V h4qjh+Sx@kb%ut$%MD0, hFaPCZ< nǯ10~ue!Q,H8a #nWe$#92) @;cE;[sRyD^G0?ea!l?dzdH\ ]Y+߉`M([;Y9K y111%*iaV`|]h2|MeIs*xŕx5/=\ SȪ7T]p@HAt,AY@ a)ij)* 9 *Uy)( '(G F#2Epj7(TF</Lz ‚)` wpxhV@6",,!x8:SsrQy''#lj```HG) Ӳ*4xMMy'*TLFX)ebDsF7Y}gH ^OOh`N$P""pwvE0}}LU @cR#u|Qa™k.0(C)44~Y " D1,9YYYDYj y#]AyJ1 2 F#\C#tlffEjzΒ%/ދ0F1+ -$Cp ^]p::\zz,'ml HW.䄢PUx! @/ =J) [/\R`C0x!`5hàApF uF/(DtA3bw,!' /h4ïfUoEpT`􂏐^B=1Pi iJ#XO!}`^GGss,(a iZ0܏RG/(c¼BdhH*緃4LO_^`97JA<2en.  "<!_]pJH@"9EE-,܆[ey؅yyxDtA98I1 ^&>ׯodɒv&]0V 4^~--:S.+ΠF/q%͓GZ EY Siiy;X*[Y ¼[H F#, tOHГr72V :EI  ` /,* sZ"<1^ 3lUQ&%#t]{+nk*{t!#ѐ}/o%F(`aHG(Kq8o!-YK!P$x:@j+ihÐ$J5 / `)bϝೠC@<@SgAQ beyۛG\BH\\Y*-y:XJYa>fL @Ll C3ov`\ `zztNxC84 j^C bx"XиL/ɛrA/5}ᘰ"Йh@@Ld YCS/v`=SzOЭsߗzưtQ#G[n!>CYYRRt_(vc|TU@h݅I6K@T椧z֗B@ _!0 {FDx `"K #XFw{+mUҒcumc4pu-i%p*1QE0@F0  N+Yq۝][NA`Hfe"1"X3 lllzKYvgСU MFpXPp% @LT `Вz >XR]r ZcX#0<<"/ (VTYqOenCZh0ۼu66*}34~qE^!70 jA+JZK:*[HV6Ԁ{4dap6NO=zBQJ憘"wn,b])٩ExcиG`n=N~P6F;;(#mqaYe#`R``R#8AtA?En55Z) !Nj`p_P a  ܰ.1E`=1rWRSRh lF;8#WDYYZU|.)@F0=aF{`BoUƞ h7?l$5`q)eRPCW` Ð+ aԃF9E+-b_o>d)DzV6f_Hmf@LzmoR E`zpGs pss rursVWsvI; 7ZX v <#8ktncpw#-v v-t9""XHl lsGs `UF,cdmm-"nm,") h,Lv+5++'u'5 ЭYB}t\\L =ˎ 6 % (! dPw<# ytx1''.%Ӭu 8XDhPF3#XNC۾33Հ1*)&KQ t`hJ8^$T|8 i'(8Aq`.,!,lbՁ8,E-+`- $++`4gqk` @Lx44 s0dؗ[Y VdRsjjjAh0ߚ ;|d"t4͡0h9ra9l\fn#c).+f@YRDWHD\ڙXFhh4oN]<n%bl8z,ո9ĸŸ>(55-"z4abG0a `#8`rPL^$h%F*@F0ie4`CP UE0փ\^!)œF^6F R@"Bܠ:]DLjt-(yutt@)HJ*;8YhΘ_`[-u% v Q+:;D\"X` ͪE`h- #\GLE:4ēL%tEDD 4k))U`ja؜6}s/=`&tbS;Lth?d?TQ'h)RP/#>I:u= Q@RQAOH6m?A~ɺ HX(hM0r1U60& fE^|<©95 <<"'QrsPٗ)E"xR@ T2xLG`(Kꤥ)+"XGTRJR F#, MRÄ5xyk@+A g"zP!4?V4~~ 55NBQ}} MxڡpCSB`308@WF;8$%,gSSI`20f`FpM:oh`2,.):zz00YY uE $ V44-&X-wp+ww5ōt], Xh4vcchPf(~NjOOMK O2Ut t˿gg-!7>'85")' ,VV69Am,` A"4 >IR -* R4dfaмaFcSE}J5~7nGxLF)f-Znݺuf5]]KUhAD |gsmP _w#h/wqmƯ5*) WJ@ F#Fa9xjSE:5붘GlC0nA _85k&ΓA#XP5PYesL :Z "XDāAu $UH5@F0YҒ/0 d gw#lՁ ])S6mڲe-Sf-`QAP bS~L0f;Vak Z(v1wqqq6V @LVa 5e6mm0 ߲:`ΚᡖYae-66Dc ؑ5 D"i9@K9"C1 "\l52`E*@F0yY6( +y)kism0dۥoGpGwN==E`Dq#XQJM/ <@牃OUůJwPwIR0))FЕ R4ddaVƑL?55-wН ":]ѯ?t\P6L)ut@ň`P }/$~)pbg`*[WQi'`Bډ#G$ bX5+Il""@64ܮKݺ>]1|\P+)!,5ƅz+EH>0` }!"wX*+;9y@T`G9vb@F0YZl,pw]CɊ ls,5SP4e__H A Vi@Sd_p#\F++KJ5N&:&JOKK8 uk^+%e0[ϝ;eE2 'pFX- ^Ng _!j~! nf;' $%MA''(\&aƌ0a!!`[L5dcby՜Ae`~YZ×ς'CqаhZGYWT F#,}RWW857@9wA;e<`3t*+! ,GHvݡTBW bb̿'OJ*77-1qMBhS1l&++$ :2གྷ5-@;e ]]"Ő]ܭW(&n4ₔA<ȑ#%H興c4b@F0Y%Z$D#w]1puru 8 @9VDY\J܉;8hS%M*n߻SbAhЅh^TAWڒ٠9ŕu^tpq͢ke&h`GѢR;"E2o%jRR x YYAD%-M4@LYf`RPf)4 4s^Hk3-o#e5+3CEiP [ePHN Ch4)`H_1ޤ_ tʦ)xހuQ#JrWW7 3 -؀Ժ4)%%[! +I;ʐ62hD` hx 3Lk[lqP ߥ{ ڀhE/"A +`zFA\@4f`,nj &QGMA ΐ^8qvx&N`De^IѬ~ɒt+2Ou ]y4QP jY^X Ў/߫,bk*..5aUPAUw.N0@Lq 3}Gn|Va]I1 =GbZZ"3xy3#,ƭAZ#(~'DF"ʒ.0hZY@_ɉ4dG?,!տ&ݏC,(F $ ct` ,sn17hlgZXcWU@l?^Є>hD@F.XrK " Z3+.^P7x܀ @Lu`d_SQaa1hU\X:PoTt[46]#ͻ| @QQQZ@5à+arp7c01 bdd^:HCbYҗG00zAF"`@ AkA+, "n ʻ@5TT#<@)eiZ77` @L&$)r0Z#h"K-KT0r!SuqI7<^ QQReQ&#4JZZZvvSSeeu *)6q{B$g~N"q#k`8-:8u̽\Q PHX6_&7H,p"N/8Rhvs.֒olT::Z흧 F#eaf,aR$B] [W;4\`FqY_Y^X Ո𸁲/ԄFUee```lrFm@wej;`30x6}Qzj";<oG0:.WӮVR֒B}$P j#`тZȎS>(, [P$GM n@JRQa`JfFpwz%;ZTꃻ+ SA;|A(+l*+ ,!!^^7-P3M T溁 H8Ӵ#TAG{O2If^ W* @L (hO(E4:,F!7xBPF(z5%E@^PkJVC\mIHGlR/.^cn\Q09. |,b| ׏hS>a9hg *n"zjPj/5 #=ޒ8mr\oqq()):E0@F0" 0`Wbx-[ : g^()e-kIe`% :9VDG-w &5V]b`PqQG0@F0U#ZR-TPKRSN+AF;M5ƴd!x^*P'AZUv0oZFnqT]$geRh$eRd*oh<1kc` 7+9,ɰ5Zee5h2//M/4P6P6[G}5.a̲<y-_|9,ҁ2T"PJ1PTGD0@F0`13d>4*< ѫweXVfX>+_d 0+󯤪dh1.u5|A4m$`޶]ܒE <` YI1yyf, _`J#|7Ojy3/NKIsFx6eaU`$Jn""Za `qcI3lGrw- p6xLN0@F0$l]&fj(I-C^"Z`gWPjG6$]m%e` l1HFE#4 b` ǁ"XnUf)'{U-ssں5NVV(GU՞ @L !f&&&&&5 舀dUIP9 >YdLpIBq l_1<˷_~Va^3@%b102hHWҒQR99,xAFE/:#gk`|9F TBJhD)YʫVYZ.`z:;$zBΪ_FF`je`fM>-\BFF:E&fygPMLe_Р2څ^K3_9 >2 ;[<-#n`VXf xƏFjL4t8}AEk 0~xk Aāt(AgTZ qK`C: fG00vgn֭yJBGzA souuu^SgDB" Ȕ4(brE|^%H+=222[م444x!@eBn-ae4ɘܒn/8r{{AM[Ve扃T.QRR&aJVS6!a& lצA,<LhoBl@ŸH&PtE23egbb b >(l@zP`Dl_, D\IK*FQHRAX k"ÖFZY\D@Y/0Xm, R,yϰsJ v cmmAG 'L!E5(zQ?x*߿)M>ƨ 866&D 6yC;XR"/ӒOHCV7YRYT[œeo;E@/Y._*-g˕@gAΠ@ZTQV t!B*`ET`2-e!< ټ~hQ hO00{:u1rfā1|JVVj sG0b ݤ&`$C<,!,? n'2KLL6 jq31dgg7 H> L0~ID`Nv ,p,%Vc&rƷVbR61A(3 ~-,0An&dlJZXlU1rPI W&ׁL. m-A3."bG- 4R @#3Q"cÈqhtCjXrPU0ʿ" mXRm۶MHvJKY~ 7`34Zdb pE0dx-PxЈ`6bc#F çR 00//aa,d,v'IIHSغ~}zx8.b2$V HmgdHc]Rkȋ`X$2)H(>%̑!wg!0j)((/>""||sssTT((cc77hhh^^www))dcc22((QQnnn&&qqtt%WYtRNSOIDATxr@ w`0{^ɽDf4oW?va4n.HXFowwwB{RB/S_ +z@̓múkѓ0IdQ[΢Lg>/f&eD0/a8}~_B6wKV0 r8T `ƌT! a&}jE_ǁE]qx}!HepIENDB`spe-0.8.4.h/_spe/skins/default/empty.png0000644000175000017500000000031410272471120017115 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEU~LIDATxb`@ @ 0@a @ @ 0@a vsIENDB`spe-0.8.4.h/_spe/skins/default/exit.png0000644000175000017500000000216010346714615016744 0ustar stanistaniPNG  IHDRa pHYs  /iCCPPhotoshop ICC profilexڭJPGmE!7 .1iKjI5ɥ6\?:>oPq|7A"dp3uncF5Aϗa˙Gi -oE3i]l>L)u ;ڂH[Wk6;V>1axap] =6+7Z"Qrw\Z5*VFf`UTݞJ=%bY դ'[x `npͺ-//P=gAMA cHRMz%%m_l<XxIDATxڤkSa{ߛ&Uc ?jA]DqqAtp]" Q"1:A$ޚ&i{CLs?R"7TFQ)5Z"j6Ar3 GƶDq5`AqH>Jk1(IR}XJ@e}>Oo.̵k`iL&C}qիɌoZhYo |& E4D&|znlpnggesqwuBU#zx)~|vu kiqofd2i?tRNS&|IDATxbkk @ PV,@ P4%H \NA^)1@1XrsqKE]]IWC $@ @ @12EfhZXHWCFVX !"6j,m2rmXl,X̕Q KA"` 7@q96kg`9)>7,IENDB`spe-0.8.4.h/_spe/skins/default/remember.png0000644000175000017500000000046110346714615017573 0ustar stanistaniPNG  IHDRagAMAܲIDATxS= 0}ܼ7{/A:6K(cq <[6$bL,|/`# ce@A9UI>*$Tmۺhع\QZ{tY=HOL^AByZihUrIzJJKYN]PQRTVeUbWqhgl]^kq`ab~mnhqfvirjtwl{xqn|xqzrs{t|}x|r21tRNS@fbKGDH pHYs  tIME 4dPIDATc`IEq$ g"-)[DEzJ9I!<@ζ0GN5ʉf͙1*VCAͣv549210G47oq<#AbjfACu\ E5]})[&)00O>sn? =-[Rd=;!*k7l}Bn[ESDp73lֻ6Kq VFF: IENDB`spe-0.8.4.h/_spe/skins/default/debug.png0000644000175000017500000000045210346714615017063 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<$PLTE#݅#2<rv tRNStIDATx\Q C[I"Sgpe[pEI\@ X rM`gv)薪 Q r9ip"0M375ݬg4 MIENDB`spe-0.8.4.h/_spe/skins/default/_.png0000644000175000017500000000074310272471120016203 0ustar stanistaniPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<uIDATxb?\ΜΐɈ.@ @…ϟ˗~?H~Μmaa pL`  snGq)@1s6##N f#@,4m`ˊǯ >}e|\@1ᷝH3/_3|FD e`aafNj(f??a`gg  Xia?YYr{  6lD[A.bbB5 0?``Da߿ 2 0 6Bv[@a_h@B:(` 󑝋C90 LoA]IENDB`spe-0.8.4.h/_spe/skins/default/index_char_win.png0000644000175000017500000000025010341055650020742 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTElK(IDATxdȱ {HHHHHHHHHHHHHH 0^LIENDB`spe-0.8.4.h/_spe/skins/default/class.png0000644000175000017500000000206010272471120017064 0ustar stanistaniPNG  IHDR(-SgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEb })3m}2a];DHAI#dG7>|/'1Gp_ !x-.MΗxBu)YaBv`:E}?wn+)4 [_vQIMOVkIc yYI&hդrđfELk8:/8n&+6zjwyglJ~isy u@~o  6ig~)7 DUUvwwolF٤Z8xӲ,:mcY֩8} .^4d2_T: IRVQ{{{K